Android窗口是根据显示屏幕来管理,每个显示屏幕的窗口层级分为37层,0-36层。每层可以放置多个窗口,上层窗口覆盖下面的。
要理解窗口的结构,需要学习下WindowContainer、RootWindowContainer、DisplayContent、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState
WindowContainer等类。
WindowContainer类
为直接包含窗口或者通过孩子层级形式包含窗口的类,定义了普遍功能。它作为基类被继承,像RootWindowContainer、DisplayContent、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState都是直接或间接的继承该类。
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
……
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final WindowList<E> mChildren = new WindowList<E>();
……
}
窗口结构层级相关类
先上一张没添加特色模式窗口结构图:
该图是未添加特色模式时的结构图,添加特色模式之后的结构,更复杂。
RootWindowContainer:根窗口容器,树的根是它。通过它遍历寻找,可以找到窗口树上的窗口。它的孩子是DisplayContent。
DisplayContent:该类是对应着显示屏幕的,Android是支持多屏幕的,所以可能存在多个DisplayContent对象。上图只画了一个对象的结构,其他对象的结构也是和画的对象的结构是相似的。
TaskDisplayArea:它为DisplayContent的孩子,对应着窗口层次的第2层。第2层作为应用层,看它的定义:int APPLICATION_LAYER = 2,应用层的窗口是处于第2层。TaskDisplayArea的孩子是Task类,其实它的孩子类型也可以是TaskDisplayArea。而Task的孩子则可以是ActivityRecord,也可以是Task。
Tokens:它为DisplayContent的孩子,它的孩子是WindowToken。而WindowToken的孩子则为WindowState对象。WindowState是对应着一个窗口的。结构图中,DisplayContent不止包含一个Tokens,还有两个。其实ImeContainer也是继承自Tokens。
ImeContainer:它也为DisplayContent的孩子,它是输入法窗口的容器,它的孩子是WindowToken类型。WindowToken的孩子为WindowState类型,而WindowState类型则对应着输入法窗口。
Task:任务,它的孩子可以是Task,也可以是ActivityRecord类型。
ActivityRecord:是对应着应用进程中的Activity的。ActivityRecord是继承WindowToken的,它的孩子类型为WindowState。
WindowState:WindowState是对应着一个窗口的。
结构图中,DisplayContent有5个孩子。图中从上到下,第一个是Tokens,对应着窗口图层0、1。第二个是TaskDisplayArea,对应着窗口图层2。第三个是Tokens,对应着窗口图层3到14。第四个是ImeContainer,对应着窗口图层15到16。第五个是Tokens,对应着窗口图层17到36。
Activity添加窗口过程
@frameworks/base/core/java/android/app/ActivityOptions.java
ActivityOptions(Bundle opts) {
private static final String KEY_AVOID_MOVE_TO_FRONT = "android.activity.avoidMoveToFront";
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
@frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
startActivityInner
Slog.w(TAG, "xww startActivityInner, targetTask=" + targetTask + " r=" + r + " sourceRecord=" + sourceRecord); //xww startActivityInner, targetTask=null r=ActivityRecord{44c341e u0 com.xxx.launcher/.MainActivity t2} sourceRecord=null
if (!mAvoidMoveToFront && mDoResume) { mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask); }
@frameworks/base/services/core/java/com/android/server/wm/Task.java
moveToFront
Slog.w(TAG, "xww moveToFront 3, task=" + task + " reason=" + reason); //xww moveToFront 3, task=null reason=reuseOrNewTask
moveToFrontInner(reason, task);
@frameworks/base/services/core/java/com/android/server/wm/TaskDisplayArea.java
task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);
Slog.w(TAG, "xww positionChildAt 3aa, child.asTask()=" + child.asTask());
//xww positionChildAt 3aa, child.asTask()=Task{7862cf6 #6 type=standard A=1000:com.xxx.launcher U=0 visible=true visibleRequested=false mode=fullscreen translucent=true sz=1}
positionChildTaskAt(position, child.asTask(), includingParents);
if (includingParents && getParent() != null && (moveToTop || moveToBottom)) {
Slog.w(TAG, "xww positionChildAt 6, this=" + this + " getParent()=" + getParent().toString());
getParent().positionChildAt(moveToTop ? POSITION_TOP : POSITION_BOTTOM, this /* child */, true /* includingParents */);
@frameworks/base/services/core/java/com/android/server/wm/DisplayArea.java
if (includingParents && parent != null && (position == POSITION_TOP || position == POSITION_BOTTOM)) {
Slog.w(TAG, "xww positionChildAt 18, this=" + this);
parent.positionChildAt(position, this /* child */, true /* includingParents */);
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
case POSITION_TOP:
Slog.w(TAG, "xww addChild 4 child=" + child.toString() + " position=" + position + " this=" + this.toString());
mChildren.add(child); //ww addChild 4 child=Display{#2 state=ON size=1920x1080 ROTATION_0 name=avd_launcher} position=2147483647 this=com.android.server.wm.RootWindowContainer@973f7ec
@frameworks/base/services/core/java/com/android/server/wm/Task.java
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask, isTaskSwitch, mOptions, sourceRecord);
if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) { positionChildAtTop(rTask);
@frameworks/base/services/core/java/com/android/server/wm/Task.java
moveToFront("positionChildAtTop");
@frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
populateInputWindowHandle
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
final boolean focusable = w.canReceiveKeys() && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
Slog.w(TAG, "xww isOnTop 3, this=" + toString() + " parent=" + (parent == null ? "null" : parent.toString()) + " parent.getTopChild()=" + (parent.getTopChild() == null ? "null" : parent.getTopChild().toString()));
if(parent != null){
for (int i = parent.mChildren.size() - 1; i >= 0; --i) {
Object child = parent.mChildren.get(i);
Slog.w(TAG, "xww isOnTop, i=" + i + ", child=" + child.toString());
}
}
return parent != null && parent.getTopChild() == this && parent.isOnTop();
//isOnTop 3, this=Display{#3 state=ON size=1920x1080 ROTATION_0 name=avd_launcher} parent=com.android.server.wm.RootWindowContainer@bf43992 parent.getTopChild()=Display{#3 state=ON size=1920x1080 ROTATION_0 name=avd_launcher}
@frameworks/base/services/core/java/com/android/server/wm/WindowList.java
return mChildren.peekLast();
return size() > 0 ? get(size() - 1) : null;
@frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
parent.isOnTop() //parent=com.android.server.wm.RootWindowContainer@bf43992
return true;
addWindowToken流程
@frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
addWindowToken
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
da.addChild(token);
Slog.w(TAG, "xww addChild 2 child=" + child.toString() + " this=" + this.toString()); //xww addChild 2 child=WindowToken{a0b2c76 android.os.Binder@9f68311} this=Leaf:3:14@132637315
mChildren.add(positionToAdd, child);
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
addChild
Slog.w(TAG, "xww addChild 3 child=" + child.toString() + " index=" + index + " this=" + this.toString());
mChildren.add(index, child);
打印窗口信息
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void FindChildInfo(E node, String indent){
Slog.w(TAG, "FindMeshInfo: node=" + indent + "|--" + node + ", size=" + node.mChildren.size());
if(node.mChildren.size() == 0){
return;
}
}
void FindChild(E node, String indent){
indent += "| ";
FindChildInfo(node, indent);
for(int i = 0; i < node.mChildren.size(); i++){
FindChild((E)node.mChildren.get(i), indent);
}
}
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
positionChildAt
switch (position) {
case POSITION_TOP:
if(child.toString().contains("avd_launcher")){
String str = new String();
Slog.w(TAG, "xww addChild xxxxx begin");
this.FindChild((E)this, str);
Slog.w(TAG, "xww addChild xxxxx end");
}
FindMeshInfo: node=| |--com.android.server.wm.RootWindowContainer@58ef5a3, size=xxx
FindMeshInfo: node=| | |--Display{#4 state=ON size=1920x1080 ROTATION_0 name=avd_launcher}, size=4
FindMeshInfo: node=| | | |--WindowedMagnification:0:31@251785581, size=7
FindMeshInfo: node=| | | | |--FullscreenMagnification:0:14@45167010, size=3
FindMeshInfo: node=| | | | | |--Leaf:0:1@131968563, size=0
FindMeshInfo: node=| | | | | |--DefaultTaskDisplayArea@48817648, size=1
FindMeshInfo: node=| | | | | | |--Task{e9e1c50 #8 type=standard A=1000:com.xxx.launcher U=0 visible=true visibleRequested=false mode=fullscreen translucent=true sz=1}, size=1
FindMeshInfo: node=| | | | | | | |--ActivityRecord{bd29e49 u0 com.xxx.launcher/.MainActivity t8}, size=0
FindMeshInfo: node=| | | | | |--Leaf:3:14@182007657, size=0
FindMeshInfo: node=| | | | |--ImePlaceholder:15:16@26527214, size=1
FindMeshInfo: node=| | | | | |--ImeContainer@79362703, size=0
FindMeshInfo: node=| | | | |--FullscreenMagnification:17:23@93221148, size=1
FindMeshInfo: node=| | | | | |--Leaf:17:23@197452069, size=0
FindMeshInfo: node=| | | | |--Leaf:24:25@118182650, size=0
FindMeshInfo: node=| | | | |--FullscreenMagnification:26:27@175550635, size=1
FindMeshInfo: node=| | | | | |--Leaf:26:27@228557576, size=0
FindMeshInfo: node=| | | | |--Leaf:28:28@117926561, size=0
FindMeshInfo: node=| | | | |--FullscreenMagnification:29:31@170632390, size=1
FindMeshInfo: node=| | | | | |--Leaf:29:31@133016711, size=0
FindMeshInfo: node=| | | |--Leaf:32:32@36554676, size=0
FindMeshInfo: node=| | | |--FullscreenMagnification:33:35@160370653, size=1
FindMeshInfo: node=| | | | |--Leaf:33:35@179128146, size=0
FindMeshInfo: node=| | | |--Leaf:36:36@49187363, size=0
@frameworks/base/core/java/android/app/ActivityOptions.java
ActivityOptions(Bundle opts) {
private static final String KEY_AVOID_MOVE_TO_FRONT = "android.activity.avoidMoveToFront";
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
@frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
startActivityInner
Slog.w(TAG, "xww startActivityInner, targetTask=" + targetTask + " r=" + r + " sourceRecord=" + sourceRecord); //xww startActivityInner, targetTask=null r=ActivityRecord{44c341e u0 com.xxx.launcher/.MainActivity t2} sourceRecord=null
if (!mAvoidMoveToFront && mDoResume) { mTargetRootTask.getRootTask().moveToFront("reuseOrNewTask", targetTask); }
@frameworks/base/services/core/java/com/android/server/wm/Task.java
moveToFront
Slog.w(TAG, "xww moveToFront 3, task=" + task + " reason=" + reason); //xww moveToFront 3, task=null reason=reuseOrNewTask
moveToFrontInner(reason, task);
@frameworks/base/services/core/java/com/android/server/wm/TaskDisplayArea.java
task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);
Slog.w(TAG, "xww positionChildAt 3aa, child.asTask()=" + child.asTask());
//xww positionChildAt 3aa, child.asTask()=Task{7862cf6 #6 type=standard A=1000:com.xxx.launcher U=0 visible=true visibleRequested=false mode=fullscreen translucent=true sz=1}
positionChildTaskAt(position, child.asTask(), includingParents);
if (includingParents && getParent() != null && (moveToTop || moveToBottom)) {
Slog.w(TAG, "xww positionChildAt 6, this=" + this + " getParent()=" + getParent().toString());
getParent().positionChildAt(moveToTop ? POSITION_TOP : POSITION_BOTTOM, this /* child */, true /* includingParents */);
@frameworks/base/services/core/java/com/android/server/wm/DisplayArea.java
if (includingParents && parent != null && (position == POSITION_TOP || position == POSITION_BOTTOM)) {
Slog.w(TAG, "xww positionChildAt 18, this=" + this);
parent.positionChildAt(position, this /* child */, true /* includingParents */);
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
case POSITION_TOP:
Slog.w(TAG, "xww addChild 4 child=" + child.toString() + " position=" + position + " this=" + this.toString());
mChildren.add(child); //ww addChild 4 child=Display{#2 state=ON size=1920x1080 ROTATION_0 name=avd_launcher} position=2147483647 this=com.android.server.wm.RootWindowContainer@973f7ec
@frameworks/base/services/core/java/com/android/server/wm/Task.java
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask, isTaskSwitch, mOptions, sourceRecord);
if (!r.mLaunchTaskBehind && allowMoveToFront && (!isOrhasTask || newTask)) { positionChildAtTop(rTask);
@frameworks/base/services/core/java/com/android/server/wm/Task.java
moveToFront("positionChildAtTop");
@frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
populateInputWindowHandle
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
final boolean focusable = w.canReceiveKeys() && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
Slog.w(TAG, "xww isOnTop 3, this=" + toString() + " parent=" + (parent == null ? "null" : parent.toString()) + " parent.getTopChild()=" + (parent.getTopChild() == null ? "null" : parent.getTopChild().toString()));
if(parent != null){
for (int i = parent.mChildren.size() - 1; i >= 0; --i) {
Object child = parent.mChildren.get(i);
Slog.w(TAG, "xww isOnTop, i=" + i + ", child=" + child.toString());
}
}
return parent != null && parent.getTopChild() == this && parent.isOnTop();
//isOnTop 3, this=Display{#3 state=ON size=1920x1080 ROTATION_0 name=avd_launcher} parent=com.android.server.wm.RootWindowContainer@bf43992 parent.getTopChild()=Display{#3 state=ON size=1920x1080 ROTATION_0 name=avd_launcher}
@frameworks/base/services/core/java/com/android/server/wm/WindowList.java
return mChildren.peekLast();
return size() > 0 ? get(size() - 1) : null;
@frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
parent.isOnTop() //parent=com.android.server.wm.RootWindowContainer@bf43992
return true;
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void FindChildInfo(E node, String indent){
Slog.w(TAG, "FindMeshInfo: node=" + indent + "|--" + node + ", size=" + node.mChildren.size());
if(node.mChildren.size() == 0){
return;
}
}
void FindChild(E node, String indent){
indent += "| ";
FindChildInfo(node, indent);
for(int i = 0; i < node.mChildren.size(); i++){
FindChild((E)node.mChildren.get(i), indent);
}
}
@frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
positionChildAt
switch (position) {
case POSITION_TOP:
if(child.toString().contains("avd_launcher")){
String str = new String();
Slog.w(TAG, "xww addChild xxxxx begin");
this.FindChild((E)this, str);
Slog.w(TAG, "xww addChild xxxxx end");
}