以下分析基于Android S.
简述 在我们开始分析WMS是怎么管理不同应用的Window的时,有点一头雾水,不知如何下手。那么我们还是从单个Activity的Window被添加至WMS中来入手。
从上文中我们知道PhoneWindow是通过IWindowSession被添加的,在ViewRoontImpl中调用了addToDisplayAsUser:
1 2 3 4 res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), userId, mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets, mTempControls);
这里的mWindow是ViewRootImpl.W类的对象,用于WMS和该Window通信。
一. Activity的Window被添加至WMS mWindowSession是ViewRootImpl被创建时通过IWindowManager在WMS中创建并返回的。这个我们回顾下:
1.1 Session.addToDisplayAsUser 1 2 3 4 5 6 7 public int addToDisplayAsUser (IWindow window, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, int userId, InsetsState requestedVisibility, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { return mService.addWindow(this , window, attrs, viewVisibility, displayId, userId, requestedVisibility, outInputChannel, outInsetsState, outActiveControls); }
这里的mService自然就是WMS本身了。
1.2 WMS.addWindow 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public int addWindow (Session session, IWindow client, LayoutParams attrs, int viewVisibility, int displayId, int requestUserId, InsetsState requestedVisibility, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { ...... final int type = attrs.type; synchronized (mGlobalLock) { ...... final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token); ...... ActivityRecord activity = null ; final boolean hasParent = parentWindow != null ; WindowToken token = displayContent.getWindowToken( hasParent ? parentWindow.mAttrs.token : attrs.token); ...... if (token == null ) { if (hasParent) { ...... } else { final IBinder binder = attrs.token != null ? attrs.token : client.asBinder(); token = new WindowToken (this , binder, type, false , displayContent, session.mCanAddInternalSystemWindow, isRoundedCornerOverlay); } } ... final WindowState win = new WindowState (this , session, client, token, parentWindow, appOp[0 ], attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow); ...... win.attach(); mWindowMap.put(client.asBinder(), win); ...... win.mToken.addWindow(win); ...... ...... }
1.2.1 WMS.getDisplayContentOrCreate 1 2 3 4 5 6 7 8 9 10 11 private DisplayContent getDisplayContentOrCreate (int displayId, IBinder token) { if (token != null ) { final WindowToken wToken = mRoot.getWindowToken(token); if (wToken != null ) { return wToken.getDisplayContent(); } } return mRoot.getDisplayContentOrCreate(displayId); }
这里首先遍历所有的DisplayContent尝试找到保存该token的WindowToken,自然是没有的,我们是第一次添加。
mRoot是WMS服务启动时创建的RootWindowContainer对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 DisplayContent getDisplayContentOrCreate (int displayId) { DisplayContent displayContent = getDisplayContent(displayId); if (displayContent != null ) { return displayContent; } if (mDisplayManager == null ) { return null ; } final Display display = mDisplayManager.getDisplay(displayId); if (display == null ) { return null ; } displayContent = new DisplayContent (display, this ); addChild(displayContent, POSITION_BOTTOM); return displayContent; } DisplayContent getDisplayContent (int displayId) { for (int i = getChildCount() - 1 ; i >= 0 ; --i) { final DisplayContent displayContent = getChildAt(i); if (displayContent.mDisplayId == displayId) { return displayContent; } } return null ; }
这里为了便于后续分析,先看看相关的类图:
从类的成员变量上推测:
WindowState: 代表Activity在WMS中的Window
DisplayContent: 管理显示窗口以及显示区域
DisplayPolicy: 管理显示窗口的可视化,决定哪些窗口可以有焦点,可以被”看见”(mFocusedWindow)
注意到这些类图里有很多都使用了WindowContainer,这个类中最重要的是一个WindowList类的成员,该类就是一个继承了ArrayList的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class WindowList <E> extends ArrayList <E> { void addFirst (E e) { add(0 , e); } E peekLast () { return size() > 0 ? get(size() - 1 ) : null ; } E peekFirst () { return size() > 0 ? get(0 ) : null ; } }
简单包装了ArrayList, 实现了三个方法:
addFirst: 将元素添加至index为0的位置,原先元素的index依次+1
peekLast: 获取集合最后一个元素
peekFirst: 获取集合第一个元素
1.2.1.1 DisplayContent 的创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 DisplayContent(Display display, RootWindowContainer root) { super (root.mWindowManager, "DisplayContent" , FEATURE_ROOT); ...... mRootWindowContainer = root; ...... mDisplayPolicy = new DisplayPolicy (mWmService, this ); ...... mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate( mWmService, this , this , mImeWindowsContainer); ...... }
DisplayContent的初始化中做了很多工作,包括创建SurfaceControl等等,但这不是我们目前关注的。
DisplayContent是继承了RootDisplayArea, 其对应的Feature是FEATURE_ROOT,表示是该逻辑显示设备上的根显示区域
DisplayPolicy暂时不是我们关注的,主要了解下其是在这里初始化即可, 重点是初始化DisplayAreaPolicy。
1.2.1.2 DisplayAreaPolicy的初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate( mWmService, this , this , mImeWindowsContainer); static Provider fromResources (Resources res) { String name = res.getString( com.android.internal.R.string.config_deviceSpecificDisplayAreaPolicyProvider); if (TextUtils.isEmpty(name)) { return new DisplayAreaPolicy .DefaultProvider(); } ... } public DisplayAreaPolicy instantiate (WindowManagerService wmService, DisplayContent content, RootDisplayArea root, DisplayArea.Tokens imeContainer) { final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea (content, wmService, "DefaultTaskDisplayArea" , FEATURE_DEFAULT_TASK_CONTAINER); final List<TaskDisplayArea> tdaList = new ArrayList <>(); tdaList.add(defaultTaskDisplayArea); final HierarchyBuilder rootHierarchy = new HierarchyBuilder (root); rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList); if (content.isTrusted()) { configureTrustedHierarchyBuilder(rootHierarchy, wmService, content); } return new DisplayAreaPolicyBuilder ().setRootHierarchy(rootHierarchy).build(wmService); }
创建了名为”DefaultTaskDisplayArea”的显示区域-TaskDisplayArea,并将其放入层次结构生成器中,然后设置该层次结构生成器的相应参数,最后通过DisplayAreaPolicyBuilder实例化DisplayAreaPolicy。
注意传入的content和root都是DisplayContent本身。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private void configureTrustedHierarchyBuilder (HierarchyBuilder rootHierarchy, WindowManagerService wmService, DisplayContent content) { rootHierarchy.addFeature(new Feature .Builder(wmService.mPolicy, "WindowedMagnification" , FEATURE_WINDOWED_MAGNIFICATION) ...... if (content.isDefaultDisplay) { rootHierarchy.addFeature(new Feature .Builder(wmService.mPolicy, "HideDisplayCutout" , FEATURE_HIDE_DISPLAY_CUTOUT) ...... .addFeature(new Feature .Builder(wmService.mPolicy, "OneHandedBackgroundPanel" , FEATURE_ONE_HANDED_BACKGROUND_PANEL) ...... .addFeature(new Feature .Builder(wmService.mPolicy, "OneHanded" , FEATURE_ONE_HANDED) } rootHierarchy .addFeature(new Feature .Builder(wmService.mPolicy, "FullscreenMagnification" , FEATURE_FULLSCREEN_MAGNIFICATION) ...... .addFeature(new Feature .Builder(wmService.mPolicy, "ImePlaceholder" , FEATURE_IME_PLACEHOLDER) ...... }
因为这里的层次结构对应DisplayContent所处的DisplayId是默认的显示设备即DEFAULT_DISPLA,默认是添加6个FEATURE:
FEATURE_WINDOWED_MAGNIFICATION: 可以放大的显示区域(比如无障碍里的放大镜)
FEATURE_HIDE_DISPLAY_CUTOUT: 用于隐藏显示裁剪功能的显示区域
FEATURE_ONE_HANDED_BACKGROUND_PANEL:显示区域为单手背景层
FEATURE_ONE_HANDED: 单手功能的显示区域
FEATURE_FULLSCREEN_MAGNIFICATION: 可以放大的显示区域,但这个是整个显示放大
FEATURE_IME_PLACEHOLDER: 可以放置IME(输入法窗口)容器的显示区域
注意这里的顺序比较重要。
1.2.1.4 DisplayAreaPolicyBuilder.build 可以看到DisplayAreaPolicy的构建其实是采用build设计模式,最后由DisplayAreaPolicyBuilder生成DisplayAreaPolicy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Result build (WindowManagerService wmService) { validate(); mRootHierarchyBuilder.build(mDisplayAreaGroupHierarchyBuilders); List<RootDisplayArea> displayAreaGroupRoots = new ArrayList <>( mDisplayAreaGroupHierarchyBuilders.size()); for (int i = 0 ; i < mDisplayAreaGroupHierarchyBuilders.size(); i++) { HierarchyBuilder hierarchyBuilder = mDisplayAreaGroupHierarchyBuilders.get(i); hierarchyBuilder.build(); displayAreaGroupRoots.add(hierarchyBuilder.mRoot); } if (mSelectRootForWindowFunc == null ) { mSelectRootForWindowFunc = new DefaultSelectRootForWindowFunction ( mRootHierarchyBuilder.mRoot, displayAreaGroupRoots); } return new Result (wmService, mRootHierarchyBuilder.mRoot, displayAreaGroupRoots, mSelectRootForWindowFunc); } DefaultSelectRootForWindowFunction(RootDisplayArea displayRoot, List<RootDisplayArea> displayAreaGroupRoots) { mDisplayRoot = displayRoot; mDisplayAreaGroupRoots = Collections.unmodifiableList(displayAreaGroupRoots); }
这里返回的是DisplayAreaPolicyBuilder.Result类对象。并且其TaskDisplayArea是FEATURE_DEFAULT_TASK_CONTAINER,表示默认任务容器所在的显示区域。
1.2.2 WindowToken的创建 1 2 3 final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();token = new WindowToken (this , binder, type, false , displayContent, session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
这里的attrs.token我们之前也分析了,其实就是Activity里的mToken.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty, DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) { super (service); token = _token; windowType = type; mOptions = options; mPersistOnEmpty = persistOnEmpty; mOwnerCanManageAppTokens = ownerCanManageAppTokens; mRoundedCornerOverlay = roundedCornerOverlay; mFromClientToken = fromClientToken; if (dc != null ) { dc.addWindowToken(token, this ); } }
将该WindowToken添加到DisplayContent中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void addWindowToken (IBinder binder, WindowToken token) { ...... mTokenMap.put(binder, token); if (token.asActivityRecord() == null ) { token.mDisplayContent = this ; switch (token.windowType) { case TYPE_INPUT_METHOD: case TYPE_INPUT_METHOD_DIALOG: mImeWindowsContainer.addChild(token); break ; default : mDisplayAreaPolicy.addWindow(token); break ; } } }
这里的mDisplayAreaPolicy是该DisplayContent初始化时创建的,所以 mDisplayAreaPolicy.addWindow(token) 其实是调用了 DisplayAreaPolicyBuilder.Result.addWindow:
1 2 3 4 5 6 7 8 9 10 public void addWindow (WindowToken token) { DisplayArea.Tokens area = findAreaForToken(token); area.addChild(token); } DisplayArea.Tokens findAreaForToken (WindowToken token) { return mSelectRootForWindowFunc.apply(token.windowType, token.mOptions) .findAreaForToken(token); }
mSelectRootForWindowFunc一般都是DefaultSelectRootForWindowFunction:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public RootDisplayArea apply (Integer windowType, Bundle options) { if (mDisplayAreaGroupRoots.isEmpty()) { return mDisplayRoot; } if (options != null && options.containsKey(KEY_ROOT_DISPLAY_AREA_ID)) { final int rootId = options.getInt(KEY_ROOT_DISPLAY_AREA_ID); if (mDisplayRoot.mFeatureId == rootId) { return mDisplayRoot; } for (int i = mDisplayAreaGroupRoots.size() - 1 ; i >= 0 ; i--) { if (mDisplayAreaGroupRoots.get(i).mFeatureId == rootId) { return mDisplayAreaGroupRoots.get(i); } } } return mDisplayRoot; }
mSelectRootForWindowFunc.apply(token.windowType, token.mOptions).findAreaForToken(token)其实是根据Window类型和Window所在的显示屏幕来选择应该将此WindowToken放入哪个RootDisplayArea中存储。
一般来说,mDisplayAreaGroupRoots中只有一个元素,即mDisplayRoot,也就是DisplayContent(猜猜什么情况下会有多个DisplayContent?)。所以这个方法其实等效于:mDisplayRoot.findAreaForToken,这里的mDisplayRoot就是DisplayContent:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Nullable DisplayArea.Tokens findAreaForToken (WindowToken token) { return findAreaForToken(token.windowType, token.mOwnerCanManageAppTokens, token.mRoundedCornerOverlay); } @Nullable DisplayArea.Tokens findAreaForToken (int windowType, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) { int windowLayerFromType = mWmService.mPolicy.getWindowLayerFromTypeLw(windowType, ownerCanManageAppTokens, roundedCornerOverlay); if (windowLayerFromType == APPLICATION_LAYER) { throw new IllegalArgumentException ( "There shouldn't be WindowToken on APPLICATION_LAYER" ); } return mAreaForLayer[windowLayerFromType]; }
因为Activity对应的windowType是TYPE_BASE_APPLICATION,所以拿到的windowLayerFromType就是APPLICATION_LAYER,那么这里必然会抛出异常!这个疑问我们后续分析,先看返回值,这里最终是返回了RootDisplayArea中mAreaForLayer数组对应存储的对象,接下来我们看看这个数组是如何被创建。
二. RootDisplayArea的构造 2.1 HierarchyBuilder.build 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 private void build (@Nullable List<HierarchyBuilder> displayAreaGroupHierarchyBuilders) { final WindowManagerPolicy policy = mRoot.mWmService.mPolicy; final int maxWindowLayerCount = policy.getMaxWindowLayer() + 1 ; final DisplayArea.Tokens[] displayAreaForLayer = new DisplayArea .Tokens[maxWindowLayerCount]; final Map<Feature, List<DisplayArea<WindowContainer>>> featureAreas = new ArrayMap <>(mFeatures.size()); for (int i = 0 ; i < mFeatures.size(); i++) { featureAreas.put(mFeatures.get(i), new ArrayList <>()); } PendingArea[] areaForLayer = new PendingArea [maxWindowLayerCount]; final PendingArea root = new PendingArea (null , 0 , null ); Arrays.fill(areaForLayer, root); final int size = mFeatures.size(); for (int i = 0 ; i < size; i++) { final Feature feature = mFeatures.get(i); PendingArea featureArea = null ; for (int layer = 0 ; layer < maxWindowLayerCount; layer++) { if (feature.mWindowLayers[layer]) { if (featureArea == null || featureArea.mParent != areaForLayer[layer]) { featureArea = new PendingArea (feature, layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(featureArea); } areaForLayer[layer] = featureArea; } else { featureArea = null ; } } } PendingArea leafArea = null ; int leafType = LEAF_TYPE_TOKENS; for (int layer = 0 ; layer < maxWindowLayerCount; layer++) { int type = typeOfLayer(policy, layer); if (leafArea == null || leafArea.mParent != areaForLayer[layer] || type != leafType) { leafArea = new PendingArea (null , layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(leafArea); leafType = type; if (leafType == LEAF_TYPE_TASK_CONTAINERS) { addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]); addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer], displayAreaGroupHierarchyBuilders); leafArea.mSkipTokens = true ; } else if (leafType == LEAF_TYPE_IME_CONTAINERS) { leafArea.mExisting = mImeContainer; leafArea.mSkipTokens = true ; } } leafArea.mMaxLayer = layer; } root.computeMaxLayer(); root.instantiateChildren(mRoot, displayAreaForLayer, 0 , featureAreas); mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas); }
此方法使用以下属性构造图层层次结构:
每个Feature映射到一组显示区域(PendingArea)
添加窗口后,对于该窗口类型所属的每个要素,它都是该要素的相应显示区域之一的后代。
保持Z顺序,即如果Z范围(区域)表示显示区域内的窗口层集: 对于每对DisplayArea同级(a,b),其中a低于b,它保持 max(z-range(a)) <= min(z-range(b))
下面的算法迭代地创建这样一个层次结构: -最初,所有窗口都附加到根目录。 -对于每个feature,我们通过在层上循环创建一组显示区域 -如果该feature确实适用于当前层,我们需要为它找到一个显示区域以满足(2) -如果当前feature也适用于前一层(满足(3)),并且应用于前一层的最后一个特征与应用于当前层的最后一个特征相同(满足(2)),我们可以重用前一层的区域 -否则,我们将在应用于当前层的最后一个功能下面创建一个新的显示区域
云里雾里的,看不懂啊, 将这段代码分成四个部分,逐一解析。
2.2 build的第一部分 - layer, feature 2.2.1 layer类型 – HierarchyBuilder.typeOfLayer 此方法获取layer对应的类型:
1 2 3 4 5 6 7 8 9 10 11 private static int typeOfLayer (WindowManagerPolicy policy, int layer) { if (layer == APPLICATION_LAYER) { return LEAF_TYPE_TASK_CONTAINERS; } else if (layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD) || layer == policy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD_DIALOG)) { return LEAF_TYPE_IME_CONTAINERS; } else { return LEAF_TYPE_TOKENS; } }
首先这里的layer类型有三种:
LEAF_TYPE_TOKENS: tokens的layer
LEAF_TYPE_TASK_CONTAINERS: 作为Task的layer
LEAF_TYPE_IME_CONTAINERS: 作为输入法的layer
其次当layer=2时,其type为LEAF_TYPE_TASK_CONTAINERS;当layer=15或16时,其type为LEAF_TYPE_IME_CONTAINERS;其余layer都是LEAF_TYPE_TOKENS类型。
2.2.2 WindowManagerPolicy.getWindowLayerFromTypeLw 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 default int getWindowLayerFromTypeLw (int type, boolean canAddInternalSystemWindow, boolean roundedCornerOverlay) { if (roundedCornerOverlay && canAddInternalSystemWindow) { return getMaxWindowLayer(); } if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { return APPLICATION_LAYER; } switch (type) { case TYPE_WALLPAPER: return 1 ; ...... case TYPE_POINTER: return 35 ; default : Slog.e("WindowManager" , "Unknown window type: " + type); return 3 ; } }
这里就可以解答刚刚的疑问了,为什么layer数量是36了,在考虑上面Window类型和Layer类型的对应,可以想到,layer类型的也是其Z轴的位置!
Window类型
值
作用
Layer(Z轴)
TYPE_WALLPAPER
2013
壁纸窗口
1
[FIRST_APPLICATION_WINDOW, LAST_APPLICATION_WINDOW]
[1, 99]
应用窗口
2
TYPE_PRESENTATION TYPE_PRIVATE_PRESENTATION TYPE_DOCK_DIVIDER TYPE_QS_DIALOG TYPE_PHONE
2037 2030 2034 2035 2002
*在外部显示器上显示的窗口 *在专用屏幕上方显示的窗口 *显示调整docked堆栈大小的窗口 *用于快速设置的窗口 *phone窗口,比如来电窗口
3
TYPE_SEARCH_BAR TYPE_VOICE_INTERACTION_STARTING
2001 2033
*搜索栏窗口,位于屏幕顶部 *语音交互层的启动窗口
4
TYPE_VOICE_INTERACTION
2031
语音交互层窗口
5
TYPE_INPUT_CONSUMER
2022
systemUI栏隐藏时使用输入事件的窗口
6
TYPE_SYSTEM_DIALOG
2008
从状态栏滑出的面板窗口
7
TYPE_TOAST
2005
临时通知窗口,即toast窗口
8
TYPE_PRIORITY_PHONE
2007
优先电话UI界面
9
TYPE_SYSTEM_ALERT
2003
系统窗口,比如低电Dialog或者ANR之类
10或者13
TYPE_APPLICATION_OVERLAY
2038
应用覆盖窗口,在所有窗口的上方 但在关键系统窗口(如状态栏)的下方 需要SYSTEM_ALERT_WINDOW权限
12
TYPE_INPUT_METHOD
2011
内部输入法窗口,显示在普通用户界面上方。 可以调整应用窗口的大小或平移,以在显示 此窗口时保持输入焦点可见
15
TYPE_INPUT_METHOD_DIALOG
2012
显示在当前输入法窗口上方的内部输入法 对话框窗口
16
TYPE_STATUS_BAR
2000
状态栏
17
TYPE_STATUS_BAR_ADDITIONAL
2041
用于在屏幕的非常规部分(即屏幕的左侧或 底部)显示状态栏窗口
18
TYPE_NOTIFICATION_SHADE
2040
状态栏下拉的通知栏窗口和keyguard
19
TYPE_STATUS_BAR_SUB_PANEL
2017
从状态栏滑出的面板窗口
20
TYPE_KEYGUARD_DIALOG
2009
keyguard创建的对话框窗口
21
TYPE_VOLUME_OVERLAY
2020
音量调整窗口
22
TYPE_SYSTEM_OVERLAY
2006
系统覆盖窗口,需要显示在所有其他窗口之上。 这些窗口不能获取输入焦点,否则会干扰keyguard
23或者11
TYPE_NAVIGATION_BAR
2019
导航栏窗口,即虚拟按键的窗口
24
TYPE_NAVIGATION_BAR_PANEL
2024
导航栏面板窗口
25
TYPE_SCREENSHOT
2036
截图窗口,用于屏幕截图动画、区域选择和UI
26
TYPE_SYSTEM_ERROR
2010
内部系统错误窗口
27或者10
TYPE_MAGNIFICATION_OVERLAY
2027
放大覆盖窗口。启用辅助功能放大时,用于 突出显示的放大部分
28
TYPE_DISPLAY_OVERLAY
2026
显示覆盖窗口。用于模拟辅助显示设备
29
TYPE_DRAG
2016
拖放窗口
30
TYPE_ACCESSIBILITY_OVERLAY
2032
无障碍辅助窗口
31
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
2039
无障碍辅助放大窗口
32
TYPE_SECURE_SYSTEM_OVERLAY
2015
安全系统覆盖窗口。 这些窗口不能获取输入焦点,否则会干扰keyguard
33
TYPE_BOOT_PROGRESS
2021
开机动画之后的启动对话框窗口
34
TYPE_POINTER
2018
鼠标指针窗口。如轨迹追踪球
35
-
roundedCornerOverlay=true canAddInternalSystemWindow=true
圆角层,始终在最上面
36
在分析DisplayArea的构造时,首先需要了解下这些类的作用:Feature、Feature.Builder、HierarchyBuilder:
2.2.3 DisplayAreaPolicyBuilder.Feature的构造 1 2 3 4 5 6 7 static class Feature { private final String mName; private final int mId; private final boolean [] mWindowLayers; private final NewDisplayAreaSupplier mNewDisplayAreaSupplier; ...... }
注意mWindowLayers是一个boolean数组,这里的feature有如下几种:
Feature Name
ID
Function
FEATURE_ROOT
0
表示该逻辑显示设备上的根显示区域
FEATURE_DEFAULT_TASK_CONTAINER
1
默认任务容器所在的显示区域
FEATURE_WINDOW_TOKENS
2
无Activity的显示区域
FEATURE_ONE_HANDED
3
单手功能的显示区域
FEATURE_WINDOWED_MAGNIFICATION
4
可以放大的显示区域。包含在{@link WindowManager.LayoutParams#TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY}下面的所有窗口
FEATURE_FULLSCREEN_MAGNIFICATION
5
可以放大的显示区域,但这个是整个显示放大
FEATURE_HIDE_DISPLAY_CUTOUT
6
用于隐藏显示裁剪功能的显示区域
FEATURE_IME_PLACEHOLDER
7
可以放置IME容器的显示区域。当IME目标改变时,如果IME容器可能被重表示为该层次结构,那么应该在每个根层次结构上启用。
FEATURE_ONE_HANDED_BACKGROUND_PANEL
8
显示区域为单手背景层,防止用户在打开暗主题时,无法清楚地识别屏幕已进入单手模式。
FEATURE_SYSTEM_LAST
10000
系统特征显示区的最后一个id,作为边界
FEATURE_VENDOR_FIRST
10001
供应商特定的显示区域定义可以从该值开始
FEATURE_VENDOR_LAST
20001
供应商特定的显示区域定义用该值作为边界
FEATURE_RUNTIME_TASK_CONTAINER_FIRST
20002
可以在运行时创建的任务显示区域以此值开始
2.2.4 DisplayAreaPolicyBuilder.Feature.Builder 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 static class Builder { private final WindowManagerPolicy mPolicy; private final String mName; private final int mId; private final boolean [] mLayers; private NewDisplayAreaSupplier mNewDisplayAreaSupplier = DisplayArea::new ; private boolean mExcludeRoundedCorner = true ; Builder(WindowManagerPolicy policy, String name, int id) { mPolicy = policy; mName = name; mId = id; mLayers = new boolean [mPolicy.getMaxWindowLayer() + 1 ]; } Feature build () { if (mExcludeRoundedCorner) { mLayers[mPolicy.getMaxWindowLayer()] = false ; } return new Feature (mName, mId, mLayers.clone(), mNewDisplayAreaSupplier); } ...... }
注意看这里的mLayers,也是一个boolean数组,是一一对应36个layer的。
接下来看看 DisplayAreaPolicyBuilder.Feature.Builder 中关键方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 Builder all () { Arrays.fill(mLayers, true ); return this ; } Builder and (int ... types) { for (int i = 0 ; i < types.length; i++) { int type = types[i]; set(type, true ); } return this ; } Builder except (int ... types) { for (int i = 0 ; i < types.length; i++) { int type = types[i]; set(type, false ); } return this ; } Builder upTo (int typeInclusive) { final int max = layerFromType(typeInclusive, false ); for (int i = 0 ; i < max; i++) { mLayers[i] = true ; } set(typeInclusive, true ); return this ; } private void set (int type, boolean value) { mLayers[layerFromType(type, true )] = value; if (type == TYPE_APPLICATION_OVERLAY) { mLayers[layerFromType(type, true )] = value; mLayers[layerFromType(TYPE_SYSTEM_ALERT, false )] = value; mLayers[layerFromType(TYPE_SYSTEM_OVERLAY, false )] = value; mLayers[layerFromType(TYPE_SYSTEM_ERROR, false )] = value; } } private int layerFromType (int type, boolean internalWindows) { return mPolicy.getWindowLayerFromTypeLw(type, internalWindows); }
接下来我们通过分析FEATURE_WINDOWED_MAGNIFICATION和FEATURE_IME_PLACEHOLDER的构造,来理解,这个Feature的作用
2.2.4.1 FEATURE_WINDOWED_MAGNIFICATION 1 2 3 4 5 6 7 rootHierarchy.addFeature(new Feature .Builder(wmService.mPolicy, "WindowedMagnification" , FEATURE_WINDOWED_MAGNIFICATION) .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new ) .build());
FEATURE_WINDOWED_MAGNIFICATION的feature构造,注释上标记的是代表可以放大的显示区域(比如无障碍里的放大镜),名称是”WindowedMagnification”:
首先调用 Builder.upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY), TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY的layer对应Z轴值为32,也就是mLayer中0~31的值都是true
调用except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY),将其对应的layer值32置为false
2.2.4.2 FEATURE_IME_PLACEHOLDER 1 2 3 4 rootHierarchy.addFeature(new Feature .Builder(wmService.mPolicy, "ImePlaceholder" , FEATURE_IME_PLACEHOLDER) .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG) .build());
FEATURE_IME_PLACEHOLDER的feature构造,注释上标记的是代表可以放置IME(输入法窗口)容器的显示区域,只有一个最简单的and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG), 也就是仅仅将该feature中mWindowLayers里对应TYPE_INPUT_METHOD(15)和TYPE_INPUT_METHOD_DIALOG(16)的layer置位true, 其他都是false.
好了,大致明白Feature的构造过程,以及mWindowLayers中的值来源,现在在回过头继续看 HierarchyBuilder.build 过程。
2.3 build第二部分–PendingArea的构造 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 final int size = mFeatures.size();for (int i = 0 ; i < size; i++) { final Feature feature = mFeatures.get(i); PendingArea featureArea = null ; for (int layer = 0 ; layer < maxWindowLayerCount; layer++) { if (feature.mWindowLayers[layer]) { if (featureArea == null || featureArea.mParent != areaForLayer[layer]) { featureArea = new PendingArea (feature, layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(featureArea); } areaForLayer[layer] = featureArea; } else { featureArea = null ; } } }
以默认的DisplayContent为例,有6个FEATURE:
Feature名
操作
mWindowLayers中为true的元素
mWindowLayers中为false的元素
FEATURE_WINDOWED_MAGNIFICATION
.upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY) .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
[0,31]
[32,36]
FEATURE_HIDE_DISPLAY_CUTOUT
.all() .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,TYPE_NOTIFICATION_SHADE)
all
17,19,24,25
FEATURE_ONE_HANDED_BACKGROUND_PANEL
.upTo(TYPE_WALLPAPER)
0
[1,36]
FEATURE_ONE_HANDED
.all() .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
all
24,25
FEATURE_FULLSCREEN_MAGNIFICATION
.all() .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG TYPE_MAGNIFICATION_OVERLAY, TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL)
all
15,16,24,25,32
FEATURE_IME_PLACEHOLDER
.and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
15,16
all
第一个feature-FEATURE_WINDOWED_MAGNIFICATION里的mWindowLayers是[0,31]为true,其他位为false, 当此feature遍历完毕之后,areaForLayer数组中[0,31]的元素都是同一个新创建的PA,记为PA_for_WF_0(其mParent为root), 其他元素都是指向root,而且现在root.mChildren中的唯一元素就是PA_for_WF_0. areaForLayer中的结果如下:
[0,31] = PA_for_WF_0(其mParent为root)
[32,36]= root
FEATURE_HIDE_DISPLAY_CUTOUT里除了17,19,24,25号其余都是true:
当第二个for循环开始时,featureArea为null, 会新建一个PA, 记为PA_for_HDC_0, 并将其保存到root.mChildren中
依次将areaForLayer[0,16]置为PA_for_HDC_0
当layer为17时,因为FEATURE_HIDE_DISPLAY_CUTOUT.mWindowLayers[17]为false, 所以会将featureArea重置为null, 继续
当layer为18时,而FEATURE_HIDE_DISPLAY_CUTOUT.mWindowLayers[18]为true, 所以又创建一个PA, 记为PA_for_HDC_18,并将areaForLayer[18]置为PA_for_HDC_18
重复制止遍历完毕
现在areaForLayer中的结果如下:
[0,16] = PA_for_HDC_0 (此PA的mParent为PA_for_WF_0)
[17] = PA_for_WF_0
[18] = PA_for_HDC_18 (此PA的mParent为PA_for_WF_0)
[19] = PA_for_WF_0
[20,23]= PA_for_HDC_20 (此PA的mParent为PA_for_WF_0)
[24,25]= PA_for_WF_0
[26,31]= PA_for_HDC_26 (此PA的mParent为PA_for_WF_0)
[32,35]= PA_for_HDC_32 (此PA的mParent为root)
[36] = root
root.mChildren结果中保存PA_for_WF_0、PA_for_HDC_0、PA_for_HDC_18、PA_for_HDC_20及PA_for_HDC_26,PA_for_HDC_32
这么分析不够直观,我们画个图来看看:
然后其他的feature过程省略,直接看结果:
于此同时,各个PA中的mParent指向如下:
注意每个PA中的mChildren集合包含所有以该PA为mParent的PA. 其子PA按从上到下,从左到右的顺序依次被添加到该PA中。
2.4 build第三部分–创建Tokens 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 PendingArea leafArea = null ;int leafType = LEAF_TYPE_TOKENS;for (int layer = 0 ; layer < maxWindowLayerCount; layer++) { int type = typeOfLayer(policy, layer); if (leafArea == null || leafArea.mParent != areaForLayer[layer] || type != leafType) { leafArea = new PendingArea (null , layer, areaForLayer[layer]); areaForLayer[layer].mChildren.add(leafArea); leafType = type; if (leafType == LEAF_TYPE_TASK_CONTAINERS) { addTaskDisplayAreasToApplicationLayer(areaForLayer[layer]); addDisplayAreaGroupsToApplicationLayer(areaForLayer[layer], displayAreaGroupHierarchyBuilders); leafArea.mSkipTokens = true ; } else if (leafType == LEAF_TYPE_IME_CONTAINERS) { leafArea.mExisting = mImeContainer; leafArea.mSkipTokens = true ; } } leafArea.mMaxLayer = layer; }
这段循环看起来和第二段中的循环类似,从Z轴最底层往上依次遍历37个layer。typeOfLayer这个我们已经分析过了: 其次当layer=2(也就是APPLICATION_LAYER)时,其type为LEAF_TYPE_TASK_CONTAINERS;当layer=15或16时,其type为LEAF_TYPE_IME_CONTAINERS;其余layer都是LEAF_TYPE_TOKENS类型:
layer=0时,layerType=LEAF_TYPE_TOKENS, 创建一个PA,记为PA_TOKENS_0, 其mParent指向areaForLayer[0], 也即是 PA_for_FM_0, 并将该PA添加到PA_for_FM_0的mChildren中。
layer=1时,layerType=LEAF_TYPE_TOKENS, 现在leafArea就是PA_TOKENS_0, 所以此次循环仅仅是将PA_TOKENS_0.mMaxLayer改成当前layer也就是1.
layer=2时,layerType=LEAF_TYPE_TASK_CONTAINERS, 新建一个PA, 记为 PA_TASK_2, 其mParent指向areaForLayer[2],即 PA_for_FM_2
layer=3时,layerType=LEAF_TYPE_TOKENS, 创建一个PA,记为PA_TOKENS_3, 其mParent指向areaForLayer[3], 还是 PA_for_FM_2
最终结果如下:
上图中,leafArea的命名方式是 PA_layerType_minLayer_max_Layer. 箭头指向的方向就是其parent方向。
2.4.1 HierarchyBuilder.addTaskDisplayAreasToApplicationLayer 1 2 3 4 5 6 7 8 9 10 11 12 13 private void addTaskDisplayAreasToApplicationLayer (PendingArea parentPendingArea) { final int count = mTaskDisplayAreas.size(); for (int i = 0 ; i < count; i++) { PendingArea leafArea = new PendingArea (null , APPLICATION_LAYER, parentPendingArea); leafArea.mExisting = mTaskDisplayAreas.get(i); leafArea.mMaxLayer = APPLICATION_LAYER; parentPendingArea.mChildren.add(leafArea); } }
现在我们知道传入的parentPendingArea就是上面构造的areaForLayer[APPLICATION_LAYER], 即 PA_for_FM_2!
这里就是把mTaskDisplayAreas中所有的TaskDisplayArea保存到PA_for_FM_2中, 最后结果如下:
2.5 build第四部分–创建DisplayArea 1 2 3 4 5 6 7 8 9 root.computeMaxLayer(); root.instantiateChildren(mRoot, displayAreaForLayer, 0 , featureAreas); mRoot.onHierarchyBuilt(mFeatures, displayAreaForLayer, featureAreas);
2.5.1 计算最大layer 1 2 3 4 5 6 int computeMaxLayer () { for (int i = 0 ; i < mChildren.size(); i++) { mMaxLayer = Math.max(mMaxLayer, mChildren.get(i).computeMaxLayer()); } return mMaxLayer; }
有上面的图可以知道,root的children中最大的mMaxLayer为PA_TOKENS_36_36, 值为36。
2.5.2 遍历PA树生成DisplayArea 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void instantiateChildren (DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer, int level, Map<Feature, List<DisplayArea<WindowContainer>>> areas) { mChildren.sort(Comparator.comparingInt(pendingArea -> pendingArea.mMinLayer)); for (int i = 0 ; i < mChildren.size(); i++) { final PendingArea child = mChildren.get(i); final DisplayArea area = child.createArea(parent, areaForLayer); if (area == null ) { continue ; } parent.addChild(area, WindowContainer.POSITION_TOP); if (child.mFeature != null ) { areas.get(child.mFeature).add(area); } child.instantiateChildren(area, areaForLayer, level + 1 , areas); } }
mChildren中只有三个PA, 分别是: PA_for_WF_0, PA_for_HDC_32以及PA_TOKENS_36_36.
这个方法不难看出,就是简单的遍历我们之前创建的PA树,然后给出了root之外的所有PA生成其对应的DisplayArea。
注意这里的传入的parent就是mRoot, 也就是DisplayContent,所以DisplayContent.mChildren中存入的元素就是此时构建的DisplayArea。
2.5.2.1 PendingArea.createArea 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 private DisplayArea createArea (DisplayArea<DisplayArea> parent, DisplayArea.Tokens[] areaForLayer) { if (mExisting != null ) { if (mExisting.asTokens() != null ) { fillAreaForLayers(mExisting.asTokens(), areaForLayer); } return mExisting; } if (mSkipTokens) { return null ; } DisplayArea.Type type; if (mMinLayer > APPLICATION_LAYER) { type = DisplayArea.Type.ABOVE_TASKS; } else if (mMaxLayer < APPLICATION_LAYER) { type = DisplayArea.Type.BELOW_TASKS; } else { type = DisplayArea.Type.ANY; } if (mFeature == null ) { final DisplayArea.Tokens leaf = new DisplayArea .Tokens(parent.mWmService, type, "Leaf:" + mMinLayer + ":" + mMaxLayer); fillAreaForLayers(leaf, areaForLayer); return leaf; } else { return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type, mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId); } }
这里会创建PendingArea对应的DisplayArea,对于我们的PA树来说,有且只有两个PA的mExisting不为null: PA_TASK_2_2_tda和PA_IME_15_16!
这里我们先看看PA_TASK_2_2_tda的DisplayArea的创建:
1 2 3 4 5 6 7 8 if (mExisting != null ) { if (mExisting.asTokens() != null ) { fillAreaForLayers(mExisting.asTokens(), areaForLayer); } return mExisting; }
我们知道PA_TASK_2_2_tda的mExisting就是1.2.1.2 DisplayAreaPolicy的初始化 中创建的”DefaultTaskDisplayArea”
final TaskDisplayArea defaultTaskDisplayArea = new TaskDisplayArea(content, wmService, “DefaultTaskDisplayArea”, FEATURE_DEFAULT_TASK_CONTAINER);
而TaskDisplayArea又是继承了DisplayArea, 其asTokens直接返回了null, 所以说PA_TASK_2_2_tda的DisplayArea就是其mExisting!
接下来是PA_IME_15_16的DisplayArea的创建:
因为mImeContainer是在DisplayContent初始化过程中创建的ImeContainer类的对象,其就是Tokens的子类。所以mExisting.asTokens()确实不为null:
1 2 3 4 5 private void fillAreaForLayers (DisplayArea.Tokens leaf, DisplayArea.Tokens[] areaForLayer) { for (int i = mMinLayer; i <= mMaxLayer; i++) { areaForLayer[i] = leaf; } }
其实就是将displayAreaForLayer中从minLayer到maxLayer都改成该PA的mExisting. 也就是 displayAreaForLayer[15], displayAreaForLayer[16]为mImeContainer!
当mExisting为null时PA对应的DisplayArea的创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 DisplayArea.Type type; if (mMinLayer > APPLICATION_LAYER) { type = DisplayArea.Type.ABOVE_TASKS; } else if (mMaxLayer < APPLICATION_LAYER) { type = DisplayArea.Type.BELOW_TASKS; } else { type = DisplayArea.Type.ANY; } if (mFeature == null ) { final DisplayArea.Tokens leaf = new DisplayArea .Tokens(parent.mWmService, type, "Leaf:" + mMinLayer + ":" + mMaxLayer); fillAreaForLayers(leaf, areaForLayer); return leaf; } else { return mFeature.mNewDisplayAreaSupplier.create(parent.mWmService, type, mFeature.mName + ":" + mMinLayer + ":" + mMaxLayer, mFeature.mId); }
PA的mFeature只有leafArea的mFeature才是null的(或者root,但是root不参与DisplayArea的创建):
当mFeature为null时,也就是当前PA是leafArea(即PA为TOKENS、TASK或者IME时),直接创建Tokens,然后进行displayAreaForLayer的填充
当mFeature不为null时,通过mNewDisplayAreaSupplier创建DisplayArea
当feature为FEATURE_WINDOWED_MAGNIFICATION,通过DisplayArea.Dimmable::new创建一个Dimmable
其余feature通过DisplayArea::new创建一个DisplayArea
所以遍历PA树生成DisplayArea就是将PA树除root节点之外,给每一个子PA创建一个DisplayArea.
经过这步骤之后,displayAreaForLayer[0~36]中的元素如下:
displayAreaForLayer[2] = PA_TASK_2_2_tda
displayAreaForLayer[15,16] = mImeContainer
其余元素皆为新建的DisplayArea.Tokens
2.5.3 RootDisplayArea.onHierarchyBuilt 1 2 3 4 5 6 7 8 9 10 11 void onHierarchyBuilt (ArrayList<Feature> features, DisplayArea.Tokens[] areaForLayer, Map<Feature, List<DisplayArea<WindowContainer>>> featureToDisplayAreas) { if (mHasBuiltHierarchy) { throw new IllegalStateException ("Root should only build the hierarchy once" ); } mHasBuiltHierarchy = true ; mFeatures = Collections.unmodifiableList(features); mAreaForLayer = areaForLayer; mFeatureToDisplayAreas = featureToDisplayAreas; }
很简单,仅仅是将传入的参数保存起来。并且将mHasBuiltHierarchy标记为true, 表明RootTaskDisplayArea仅仅需要构建一次层次结构。
三. 小结 Activity的Window被添加至WMS其实就是该Activity的ViewRootImpl中的W作为IWindow、存储该Activity窗口属性信息的LayoutParams以及InputChannel被传入WMS,然后生成WindowToken, 当然之后WindowToken自然是保存在DisplayContent.mTokenMap中,该map的key即对应Activity中的mToken(LocalActivityRecord)。
这里的DisplayContent是继承了RootDisplayArea, 其对应的Feature是FEATURE_ROOT,表示是该逻辑显示设备上的根显示区域。DisplayContent的初始化中做了很多工作,包括创建SurfaceControl,创建DisplayPolicy等等,重点是初始化DisplayAreaPolicy,而DisplayAreaPolicy的初始化过程中也同时构建了DisplayContent的层次结构器。
这个层次结构的初始化过程稍显复杂,可以看 HierarchyBuilder.build 上面的分析,大致分为四个部分:
第一部分 Layer的数量为37个,最上层是root, 默认DisplayArea的Feature有六个
第二部分 构造PA树
按照定义的顺序遍历feature,以便数组前面的Feature位于层次结构的顶部
依次编译该feature中定义的mWindowLayer数组,该数组由37个boolean值组成,从小到大一次对应37层layer
如果mWindowLayer[layer]的值为true, 那么根据需要创建子PA
第三部分 遍历第二部分创建的PA树,根据window类型创建对应叶子节点的PA
第四部分 为PA树的每个PA创建对应的DisplayArea,并将结果存储在RootDisplayArea(DisplayContent)中
接下来我们分析WindowToke到底是如何管理的,包括WindowState的作用,而且我们分析WindowState创建的时候发现会抛出异常,这个问题我们下篇文章分析。