当前位置: 首页 > news >正文

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

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是一个异步方法

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

3. ViewRootImpl#scheduleTraversals

scheduleTraversals中有一个Runnable方法

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

    final class TraversalRunnable implements Runnable {@Overridepublic 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()中被赋值为trueif (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;
...
//判断是否有surfaceboolean 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//绘制三部曲之measureperformMeasure(childWidthMeasureSpec, childHeightMeasureSpec);...//绘制三部曲之layoutperformLayout(lp, mWidth, mHeight);...//绘制三部曲之drawperformDraw();
...

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 {
...@Overridepublic 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端流程太多了,另起一篇文章分析。

 

 

相关文章:

  • Java学习-JDBC(一)
  • 【数据结构】图论入门
  • 开发常用软件
  • PDF编辑与转换的终极工具智能PDF处理Acrobat Pro DC
  • Day14:响应式网页
  • java 原生http服务器 测试JS前端ajax访问实现跨域传post数据
  • 【Python爬虫单点登录实战】PyExecJS破解慧职教:过河源技术学院单点登录统一身份认证
  • 电脑开机出现英文字母,如何解决这个常见问题?
  • MAVEN:自定义模板Archetype的创建
  • 【java】速度搭建一个springboot项目
  • 计算机网络--应用层
  • BF16相比FP16的优点
  • alist配合onlyoffice 实现在线预览
  • 达梦数据库
  • Ajax入门
  • Android单元测试 - 几个重要问题
  • Apache的基本使用
  • const let
  • CSS 专业技巧
  • Intervention/image 图片处理扩展包的安装和使用
  • js数组之filter
  • node 版本过低
  • Python - 闭包Closure
  • Python学习之路13-记分
  • springMvc学习笔记(2)
  • Vue 2.3、2.4 知识点小结
  • 对超线程几个不同角度的解释
  • 分布式事物理论与实践
  • 给第三方使用接口的 URL 签名实现
  • 使用 @font-face
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 怎么将电脑中的声音录制成WAV格式
  • $(selector).each()和$.each()的区别
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (10)STL算法之搜索(二) 二分查找
  • (9)STL算法之逆转旋转
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (已解决)什么是vue导航守卫
  • (转)程序员疫苗:代码注入
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET C# 使用 iText 生成PDF
  • .net CHARTING图表控件下载地址
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .Net mvc总结
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .net经典笔试题
  • .net开发时的诡异问题,button的onclick事件无效