在安卓源码的设计中,将将屏幕分为了37层,不同的窗口将在不同的层级中显示。
对这一块的概念以及相关源码做了详细分析,整理出以下几篇。
【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树
【Android 13源码分析】WindowContainer窗口层级-2-构建流程
【Android 13源码分析】WindowContainer窗口层级-3-实例分析
当前为第三篇,以应用窗口和系统窗口2大类型窗口的挂载为例介绍窗口是如何挂载到层级树中的。
这篇看完对AOSP中整个窗口树就有了比较完整的了解。
应用启动流程中会触发ActivityRecord,Task,WindowState的创建与挂载,其中WindowState的处理上在addWindow流程。
1.1 ActivityRecord的创建
启动流程开始的时候会执行到ActivityStarter::executeRequest,在这个方法里会创建一个ActivityRecord
1 | scss复制代码# ActivityStarter |
tips: ActivityRecord的构造方法会创建一个Token,这个token就是阅读源码经常看到看到代表activity的那个token。
1.2 Task的创建与挂载
流程开始会执行到ActivityStarter::startActivityInner方法,在这里会执行ActivityStarter::getOrCreateRootTask方法来创建(获取)一个Task
调用链如下:
主流程代码
1 | less复制代码# ActivityStarter |
小结:
最后描述一下最后创建的2个重点部分:
- 看到通过buildInner 创建了一个task,而buildInner 也很简单粗暴,通过各个变量直接new Task 对象。
- mParent 不为null, 是 因为在创建的时候 setParent(this),当前的这个this,就是 getDefaultTaskDisplayArea返回的也就是应用Activity存在的”DefaultTaskDisplayArea”。
在 RootWindowContainer::getOrCreateRootTask 体现。
注意log里的 #17 的这个Task,与前面的层级结构树新增的Task,是对应的上的。而且this= DefaultTaskDisplayArea 说明也确实是往DefaultTaskDisplayArea里添加了。
1.3 ActivityRecord的挂载
调用链
ActivityStarer::setNewTask
ActivityStarer::addOrReparentStartingActivity
主流程代码
1 | java复制代码# ActivityStarer |
这里的task 和mTargetRootTask是同一个对象, 进源码跟到流程也是一样。
然后进入 addOrReparentStartingActivity
1 | less复制代码# ActivityStarer |
这里的逻辑设计到的Task就是上一步创建的Task,mStartActivity则是“电话”在之前逻辑创建的ActivityRecord.
setNewTask的堆栈信息如下
另外这段逻辑里有个ProtoLog打印,日志如下:
1.4 WindowState的创建与挂载
WindowManagerService::addWindow
WindowState::init – WindowState的创建
WindowToken::addWindow – WindowState的挂载
1 | java复制代码# WindowManagerService |
“win.mToken”窗口的token是ActyivityRecord
1 | typescript复制代码# ActivityRecord |
直接调用其父类方法,ActivityRecord是WindowToken
1 | scss复制代码# WindowToken |
2.1 WindowToken,WindowState的创建与挂载
1 | java复制代码 public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility, |
WindowState的创建和应用窗口一样,区别在与WindowToken,系统窗口执行addWindow方法是没有token的,所以会执行创建逻辑。
在创建的时候会根据窗口类型选择挂载的层级。
2.2 WindowToken的挂载
WindowToken的构造方法如下:
1 | java复制代码# WindowToken |
创建WindowToken的时候会由DisplayContent执行挂载逻辑,
1 | scss复制代码# DisplayContent |
状态栏不属于应用窗口,走后面的逻辑,DisplayAreaPolicy是个接口,真正的实现是DisplayAreaPolicyBuilder的内部类Result
1 | scala复制代码# DisplayAreaPolicyBuilder |
mSelectRootForWindowFunc是一个存放RootDisplayArea的map,所以后续逻辑在RootDisplayArea中
1 | java复制代码// 根据type 找到在容器树的位置, 如果是应用或者输入法都走不到这 |
getWindowLayerFromTypeLw会根据type找到对应的层级,返回一个int。
然后根据这个值去mAreaForLayer拿到对应的DisplayArea.Tokens,将系统窗口的WindowToken挂载进去
mAreaForLayer其实就是开始构建层级树的那个集合。
2.2.1 mAreaForLayer的赋值
在开机构建窗口层级树的逻辑,最后会执行到RootDisplayArea::onHierarchyBuilt将层级树的集合传递出去。
1 | less复制代码# DisplayAreaPolicyBuilder.HierarchyBuilder |
RootDisplayArea下的mAreaForLayer变量赋值
1 | ini复制代码# RootDisplayArea |
所以mAreaForLayer保存了层级树各个层级的对象因此根据index可以获取到对应的DisplayArea.Tokens,并执行系统窗口WindowToken的挂载。
本文转载自: 掘金