Android14 WMS-窗口绘制之relayoutWindow流程(一)-Client端

news2024/11/18 15:49:30

Android14 WMS-窗口添加流程(一)-Client端-CSDN博客

Android14 WMS-窗口添加流程(二)-Server端-CSDN博客

经过上述两个流程后,窗口的信息都已经传入了WMS端。

f57b6efae369489bbf40634cccb43bf0.jpg

 

1. ViewRootImpl#setView

在窗口添加流程(一)中,有这个方法:

http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/ViewRootImpl.java#1314

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
...
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
...
    }

2. ViewRootImpl#requestLayout

requestLayout中的scheduleTraversals是一个异步方法

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
//异步方法
            scheduleTraversals();
        }
    }

3. ViewRootImpl#scheduleTraversals

scheduleTraversals中有一个Runnable方法

关于Choreographer编舞者,这里也不重点介绍。

    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
//执行view遍历操作,进行measure,layout,draw操作
            doTraversal();
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//Choreographer Posts a callback to run on the next frame.
// The callback runs once then is automatically removed.
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

4. ViewRootImpl#doTraversal

来看看Runnable中的方法


    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
...
//要执行到了真正的遍历操作,这就要对view执行measure,layout, draw流程了
            performTraversals();
...
        }
    }

5. ViewRootImpl#performTraversals

    private void performTraversals() {
...
        // cache mView since it is used so much below...
//这个mView是通过setView方法传进来的,也就是Activity的根布局DecorView,使用final修饰,以防在遍历过程中被修改
        final View host = mView;
...
//mAdded指DecorView是否被成功加入到window中,在setView()中被赋值为true
        if (host == null || !mAdded) {
            mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
            return;
        }
...
        mIsInTraversal = true;//是否正在遍历
        mWillDrawSoon = true;//是否需要马上绘制
        boolean cancelDraw = false;
        String cancelReason = null;
        boolean isSyncRequest = false;

        boolean windowSizeMayChange = false;
        WindowManager.LayoutParams lp = mWindowAttributes;
//顶层视图DecorView窗口的期望宽高
        int desiredWindowWidth;
        int desiredWindowHeight;
//DecorView是否可见
        final int viewVisibility = getHostVisibility();
//视图可见性改变
        final boolean viewVisibilityChanged = !mFirst
                && (mViewVisibility != viewVisibility || mNewSurfaceNeeded
                // Also check for possible double visibility update, which will make current
                // viewVisibility value equal to mViewVisibility and we may miss it.
                || mAppVisibilityChanged);
...
        WindowManager.LayoutParams params = null;
...
        boolean windowShouldResize = layoutRequested && windowSizeMayChange
            && ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
                || (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
                        frame.width() < desiredWindowWidth && frame.width() != mWidth)
                || (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
                        frame.height() < desiredWindowHeight && frame.height() != mHeight));
        windowShouldResize |= mDragResizing && mPendingDragResizing;
...
//第一次执行测量布局绘制操作||Activity窗口大小需要改变||View的可见性发生了变化||窗口属性发生了变化||ViewRootHandler接收到消息MSG_RESIZED_REPORT,即size改变了
        if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
                || mForceNextWindowRelayout) {
...
//如果此窗口为窗口管理器提供内部insets,那么我们首先要在布局期间使提供的insets保持不变。
//这样可以避免它短暂地导致其他窗口根据窗口的原始框架调整大小/移动,
//等到我们完成此窗口的布局并返回窗口管理器,并最终计算出插图。
            insetsPending = computesInternalInsets;
...
//判断是否有surface
            boolean hadSurface = mSurface.isValid();

            try {
...
                if (mFirst || viewVisibilityChanged) {
                    mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
                }
//params,窗口属性变化内容
//请求WMS计算Activity窗口大小及边衬区域大小
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
...
   	        // Ask host how big it wants to be
            //绘制三部曲之measure
           performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
           ...
            //绘制三部曲之layout
           performLayout(lp, mWidth, mHeight);
           ...
           //绘制三部曲之draw
           performDraw();
...

6. ViewRootImpl#relayoutWindow

我们主要是来看看ViewRootImpl如何向WMS申请布局的

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
...
//window申请的宽
        final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
//window申请的高
        final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
        int relayoutResult = 0;
        mRelayoutSeq++;
        if (relayoutAsync) {
            mWindowSession.relayoutAsync(mWindow, params,
                    requestedWidth, requestedHeight, viewVisibility,
                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
                    mLastSyncSeqId);
        } else {
//请求重新布局
            relayoutResult = mWindowSession.relayout(mWindow, params,
                    requestedWidth, requestedHeight, viewVisibility,
                    insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
                    mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
                    mTempInsets, mTempControls, mRelayoutBundle);
...

这里就又用到了AIDL,WindowSession,WindowSession是APP和WMS沟通的桥梁

   final IWindowSession mWindowSession;

可以看下这篇文章加强理解

Android14 WMS-IWindowSession介绍-CSDN博客

7. Session #relayout

 

//Session继承了IWindowSession.Stub
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
...
    @Override
    public int relayout(IWindow window, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags, int flags, int seq,
            int lastSyncSeqId, ClientWindowFrames outFrames,
            MergedConfiguration mergedConfiguration, SurfaceControl outSurfaceControl,
            InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
            Bundle outSyncSeqIdBundle) {
        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                + Binder.getCallingPid());
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
//调用到了Server端
        int res = mService.relayoutWindow(this, window, attrs,
                requestedWidth, requestedHeight, viewFlags, flags, seq,
                lastSyncSeqId, outFrames, mergedConfiguration, outSurfaceControl, outInsetsState,
                outActiveControls, outSyncSeqIdBundle);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                + Binder.getCallingPid());
        return res;
    }

8. WindowManagerService #relayoutWindow

Server端流程太多了,另起一篇文章分析。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1799482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ubuntu22.04 下 pybind11 搭建,示例

Pybind11 是一个轻量级的库&#xff0c;用于在 C 中创建 Python 绑定。Ubuntu22下安装pybind11步骤如下&#xff1a; 1. 安装 pybind11 1.1 pip 命令安装 pip3 install pybind11 1.2 源代码安装 安装依赖库&#xff1a; sudo pip install -i https://pypi.tuna.tsinghua.e…

要想数据形成好的数据集,必须数据治理(目的之一是防止大模型产生灰色数据等),用于炼丹(训练数据私有化模型)的数据才是好数据

数据治理&#xff1a;必要性、实施方法及挑战 引言 在当今数字化时代&#xff0c;数据已经成为企业最重要的资产之一。随着数据量的爆炸性增长&#xff0c;如何有效地管理和利用数据成为企业面临的重大挑战。数据治理&#xff08;Data Governance&#xff09;作为一种系统化的…

排序数组 ---- 分治-归并

题目链接 题目: 分析: 用这道题来回顾一下归并排序的思想找到中间结点, 将数组分成两半, 运用递归的思想, 继续对一半进行分半, 分到最后剩一个元素, 再将左右数组合并, 合并两个有序数组, 是先分解, 再合并的过程在合并两个有序数组时, 需要一个额外的数组来记录, 为了避免每…

【RabbitMQ基础】-RabbitMQ:初识MQ[1]

简介 RabbitMQ &#xff08;高性能的异步通讯组件&#xff09; RabbitMQ是一个开源的消息队列中间件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;标准。它是一种可靠、可扩展、灵活和可插拔的解决方案&#xff0c;用于处理异步消息传递和事件驱动系统。…

HDFS的块汇报和块放置策略--从一次HDFS写文件故障开始(WIP)

文章目录 前言事故分析&#xff1a;代码解析BlockReport的调度和时机哪些Block会进行FBR或者IBRIBR所选定的BlockFBR所选定的Block 块放置策略详解之在上层寻找机器为文件添加块的基本流程块放置策略&#xff1a;选择机器为每个副本逐个寻找机器在指定范围内随机寻找简单看一下…

毕业论文word常见问题

0、前言&#xff1a; 这里的问题都是以office办公软件当中的word为例&#xff0c;和WPS没有关系。 1、页眉横线删不掉&#xff1a; 解决方案&#xff1a;进入页眉编辑状态&#xff0c;在开始选项栏中选择页眉字体样式&#xff0c;清除格式。 修改方式如下&#xff1a; 2、…

FL Studio21.8中文版深受欢迎的数字音频工作站(DAW)

在数字音乐制作领域&#xff0c;FL Studio21中文版作为一款深受欢迎的数字音频工作站&#xff08;DAW&#xff09;&#xff0c;因其强大的功能、用户友好的界面和对中文用户的优化支持而备受推崇。它广泛应用于音乐创作、编曲、录音、混音以及母带处理等领域&#xff0c;尤其适…

Serverless 使用OOS将http文件转存到对象存储

目录 背景介绍 系统运维管理OOS 文件转存场景 前提条件 实践步骤 附录 示例模板 背景介绍 系统运维管理OOS 系统运维管理OOS&#xff08;CloudOps Orchestration Service&#xff09;提供了一个高度灵活和强大的解决方案&#xff0c;通过精巧地编排阿里云提供的OpenAPI…

nodejs---fs模块,文件读写操作详解,自定义一个文件写入方法

fs模块导入 Node.js 同时支持 CommonJS 和 ES 模块系统&#xff08;自 Node.js v12 以来&#xff09; // 两种模块导入方式 import * as fs from fs;// Es6:这种方式需要在package.json中配置"type": "module" const fs require(fs);// commonJs:如果你…

【操作系统】进程与线程的区别及总结(非常非常重要,面试必考题,其它文章可以不看,但这篇文章最后的总结你必须要看,满满的全是干货......)

目录 一、 进程1.1 PID(进程标识符)1.2 内存指针1.3 文件描述符表1.4 状态1.5 优先级1.6 记账信息1.7 上下文 二、线程三、总结&#xff1a;进程和线程之间的区别&#xff08;非常非常非常重要&#xff0c;面试必考题&#xff09; 一、 进程 简单来介绍一下什么是进程&#xf…

【人工智能】流行且重要的智能算法整理

✍&#x1f3fb;记录学习过程中的输出&#xff0c;坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;指点&#x1f64f; 小记&#xff1a; 今天在看之前写的文档时&#xff0c;发现有人工智能十大算法的内容&#xf…

stdlib.h: No such file or directory

Qt报错: error: stdlib.h: No such file or directory #include_next &#xff1c;stdl 报错&#xff0c; 其他博主的解决方法&#xff1a; Qt报错: error: stdlib.h: No such file or directory #include_next &#xff1c;stdl_qt5.15 无法打开包括文件“stdlib.h” no suc…

数据结构之ArrayList与顺序表(上)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 顺序表的学习&#xff0c;点我 上面这篇博文是关于顺序表的基础知识&#xff0c;以及顺序表的实现。…

第八篇——矢量化:象形文字和拼音文字是如何演化的?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 通过这篇看似在讲文字的演化过程&#xff0c;实际是在说人生应该如何走&a…

中文文案写作有哪些合适的AIGC工具?

这是计育韬老师第 8 次开展面向全国高校的新媒体技术公益巡讲活动了。而在每场讲座尾声&#xff0c;互动答疑环节往往反映了高校师生当前最普遍的运营困境&#xff0c;特此计老师在现场即兴答疑之外&#xff0c;会尽量选择有较高价值的提问进行文字答疑梳理。 *本轮巡讲主题除了…

Solon2分布式事件总线的应用价值探讨

随着现代软件系统的复杂性日益增加&#xff0c;微服务架构逐渐成为开发大型应用的主流选择。在这种架构下&#xff0c;服务之间的通信和协同变得至关重要。Solon2作为一个高性能的Java微服务框架&#xff0c;其分布式事件总线&#xff08;Distributed Event Bus&#xff09;为微…

重回1990短视频全集:成都鼎茂宏升文化传媒公司

重回1990短视频全集&#xff1a;时光之旅的温情回顾 在数字技术的浪潮中&#xff0c;短视频以其独特的魅力迅速崛起&#xff0c;成为我们记录生活、分享故事的新方式。而当我们回望过去&#xff0c;那些充满怀旧情怀的年份总是让人心生感慨。今天&#xff0c;就让我们一起踏上…

Day45 代码随想录打卡|二叉树篇---路径总和

题目&#xff08;leecode T112&#xff09;&#xff1a; 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;…

VMware虚拟机与MobaXterm建立远程连接失败

VMware虚拟机与MobaXterm建立远程连接失败 首先可以检查一下是不是虚拟机的ssh服务并不存在 解决方法&#xff1a; 1.更新镜像源 yum -y update 这个过程会有点久&#xff0c;请耐心等待 2.安装ssh yum install openssh-server 3.启动ssh systemctl restart sshd 4.查…

【Spring Cloud Alibaba】13.自建存储对象服务与集成(minio版)

文章目录 简介什么是云存储服务&#xff08;OSS&#xff09;为什么选择MiniIOMiniIO相关地址 搭建(docker)安装Docker部署MinIO创建存储桶配置存储桶设置存储桶可以直接在浏览器访问 集成到Spring Cloud Alibaba项目创建子模块引入依赖包项目结构配置文件工具类接口类测试 简介…