Android P WMS简介
Android P WMS初始化过程
Android P WMS addwindow流程
Android P WMS removewindow流程
Android P WMS relayoutWindow流程
Android P WMS windowanimator
Android P WMS Surface
Android P WMS 问题种类和debug分析技巧
Android P WMS View System 简介
WMS是系统的其他服务,无论对于应用开发还是Framework开发都是重点的知识,它的职责有很多,主要有以下几点:
窗口管理
WMS是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS进行管理的。窗口管理的核心成员有DisplayContent、WindowToken和WindowState。
窗口动画
窗口间进行切换时,使用窗口动画可以显得更炫一些,窗口动画由WMS的动画子系统来负责,动画子系统的管理者为WindowAnimator。
输入系统的中转站
通过对窗口的触摸从而产生触摸事件,InputManagerService(IMS)会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息,WMS是窗口的管理者,因此,WMS“理所应当”的成为了输入系统的中转站。
Surface管理
窗口并不具备有绘制的功能,因此每个窗口都需要有一块Surface来供自己绘制。为每个窗口分配Surface是由WMS来完成的。
WMS的职责可以简单总结为下图。
windowState就是window,每个window都有一个surface来绘画,window本身是没法画的。
Window的类型
Android系统的Window有很多个,大体上来说,Framework定义了三种窗口类型;
系统Window
常见的系统Window有哪些呢?比如在手机电量低的时候,会有一个提示电量低的Window,我们输入文字的时候,会弹出输入法Window,还有搜索条Window,来电显示Window,Toast对应的Window,可以总结出来,系统Window是独立与我们的应用程序的,对于应用程序而言,我们理论上是无法创建系统Window,因为没有权限,这个权限只有系统进程有。
应用程序Window
所谓应用窗口指的就是该窗口对应一个Activity,因此,要创建应用窗口就必须在Activity中完成了。本节后面会分析Activity对应的Window的创建过程。
子Window
所谓的子Window,是说这个Window必须要有一个父窗体,比如PopWindow,Dialog是属于应用程序Window,这个比较特殊。
每一种窗口类型定义了一种对应的type
应用类型的窗口的type范围是1~99
应用类型的窗口
子窗口的type范围是1000~1999
子窗口
系统的窗口的type范围是2000以上
系统的窗口
系统窗口的type值>子窗口的type值>应用类型窗口的type值,一般来说,根据type值大小关系,可以推出系统窗口在子窗口的上面,子窗口在应用窗口的上面。
手机上采用的是层叠式布局,层叠式布局是一个三维的空间,将手机的水平方向作为X轴,竖直方向作为Y轴,还有一根垂直与屏幕从里朝外方向的虚拟的Z轴,所有窗口 (WindowState) 按照顺序排列在Z轴上,如下图。z轴坐标就是z-order,越大证明他的windowState越在前面。
3.1 、 mBaseLayer 主序 确认
-
@/frameworks/base/services/core/java/com/android/server/wm/WindowState.
java
-
WindowState
(WindowManagerService service, Session s, IWindow c, WindowToken token,
-
WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
-
int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
-
PowerManagerWrapper powerManagerWrapper) {
-
...
-
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
-
// The multiplier here is to reserve space for multiple
-
// windows in the same type layer.
-
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow
//mBaseLayer 主序
-
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
TYPE_LAYER_MULTIPLIER = 10000 TYPE_LAYER_OFFSET = 1000
-
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
//mSubLayer 次序
-
mIsChildWindow =
true;
-
-
if (DEBUG_ADD_REMOVE) Slog.v(TAG,
"Adding " +
this +
" to " + parentWindow);
-
parentWindow.addChild(
this, sWindowSubLayerComparator);
-
-
mLayoutAttached = mAttrs.type !=
-
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-
mIsImWindow = parentWindow.mAttrs.type == TYPE_INPUT_METHOD
-
|| parentWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
-
mIsWallpaper = parentWindow.mAttrs.type == TYPE_WALLPAPER;
-
}
else {
-
// The multiplier here is to reserve space for multiple
-
// windows in the same type layer.
-
mBaseLayer = mPolicy.getWindowLayerLw(
this)
-
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
-
mSubLayer =
0;
-
mIsChildWindow =
false;
-
mLayoutAttached =
false;
-
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
-
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
-
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
-
}
-
...
-
}
mBaseLayer =窗口类型×10000+1000,窗口类型判断如下
-
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
-
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
-
return APPLICATION_LAYER;
-
}
-
-
switch (type) {
-
case TYPE_WALLPAPER:
-
// wallpaper is at the bottom, though the window manager may move it.
-
return
1;
-
case TYPE_PRESENTATION:
-
case TYPE_PRIVATE_PRESENTATION:
-
return APPLICATION_LAYER;
-
case TYPE_DOCK_DIVIDER:
-
return APPLICATION_LAYER;
-
case TYPE_QS_DIALOG:
-
return APPLICATION_LAYER;
-
case TYPE_PHONE:
-
return
3;
-
case TYPE_SEARCH_BAR:
-
case TYPE_VOICE_INTERACTION_STARTING:
-
return
4;
-
case TYPE_VOICE_INTERACTION:
-
// voice interaction layer is almost immediately above apps.
-
return
5;
-
case TYPE_INPUT_CONSUMER:
-
return
6;
-
case TYPE_SYSTEM_DIALOG:
-
return
7;
-
case TYPE_TOAST:
-
// toasts and the plugged-in battery thing
-
return
8;
-
case TYPE_PRIORITY_PHONE:
-
// SIM errors and unlock. Not sure if this really should be in a high layer.
-
return
9;
-
case TYPE_SYSTEM_ALERT:
-
// like the ANR / app crashed dialogs
-
return canAddInternalSystemWindow ?
11 :
10;
-
case TYPE_APPLICATION_OVERLAY:
-
return
12;
-
case TYPE_DREAM:
-
// used for Dreams (screensavers with TYPE_DREAM windows)
-
return
13;
-
case TYPE_INPUT_METHOD:
-
// on-screen keyboards and other such input method user interfaces go here.
-
return
14;
-
case TYPE_INPUT_METHOD_DIALOG:
-
// on-screen keyboards and other such input method user interfaces go here.
-
return
15;
-
case TYPE_STATUS_BAR:
-
return
17;
-
case TYPE_STATUS_BAR_PANEL:
-
return
18;
-
case TYPE_STATUS_BAR_SUB_PANEL:
-
return
19;
-
case TYPE_KEYGUARD_DIALOG:
-
return
20;
-
case TYPE_VOLUME_OVERLAY:
-
// the on-screen volume indicator and controller shown when the user
-
// changes the device volume
-
return
21;
-
case TYPE_SYSTEM_OVERLAY:
-
// the on-screen volume indicator and controller shown when the user
-
// changes the device volume
-
return canAddInternalSystemWindow ?
22 :
11;
-
case TYPE_NAVIGATION_BAR:
-
// the navigation bar, if available, shows atop most things
-
return
23;
-
case TYPE_NAVIGATION_BAR_PANEL:
-
// some panels (e.g. search) need to show on top of the navigation bar
-
return
24;
-
case TYPE_SCREENSHOT:
-
// screenshot selection layer shouldn't go above system error, but it should cover
-
// navigation bars at the very least.
-
return
25;
-
case TYPE_SYSTEM_ERROR:
-
// system-level error dialogs
-
return canAddInternalSystemWindow ?
26 :
10;
-
case TYPE_MAGNIFICATION_OVERLAY:
-
// used to highlight the magnified portion of a display
-
return
27;
-
case TYPE_DISPLAY_OVERLAY:
-
// used to simulate secondary display devices
-
return
28;
-
case TYPE_DRAG:
-
// the drag layer: input for drag-and-drop is associated with this window,
-
// which sits above all other focusable windows
-
return
29;
-
case TYPE_ACCESSIBILITY_OVERLAY:
-
// overlay put by accessibility services to intercept user interaction
-
return
30;
-
case TYPE_SECURE_SYSTEM_OVERLAY:
-
return
31;
-
case TYPE_BOOT_PROGRESS:
-
return
32;
-
case TYPE_POINTER:
-
// the (mouse) pointer layer
-
return
33;
-
default:
-
Slog.e(
"WindowManager",
"Unknown window type: " + type);
-
return APPLICATION_LAYER;
-
}
-
}
3.2 、mSubLayer 子序的确认
SubLayer(称为子序),SubLayer值是用来描述一个窗口是否属于另外一个窗口的子窗口,或者说SubLayer值是用来确定子窗口和父窗口之间的相对位置的。
一个Activity中有三个子窗口WindowState1、WindowState2、WindowState3,WindowState1WindowState2在窗口A的前面,WindowState3在A的后面,这几个兄弟窗口为什么可以这样排序呢,这就是mSubLayer的作用,子序越大,则相对其他兄弟窗口越靠前,反之,越靠后,如果为负数,就处在父窗口的后面,如窗口A中的WindowState3,子序是根据窗口类型调用subWindowTypeToLayerLw确定的,subWindowTypeToLayerLw同样是在Window的构造方法中调用的。
-
public int subWindowTypeToLayerLw(int type) {
-
switch (type) {
-
case TYPE_APPLICATION_PANEL:
-
case TYPE_APPLICATION_ATTACHED_DIALOG:
-
return APPLICATION_PANEL_SUBLAYER;
//返回值是1
-
case TYPE_APPLICATION_MEDIA:
-
return APPLICATION_MEDIA_SUBLAYER;
//返回值是-2
-
case TYPE_APPLICATION_MEDIA_OVERLAY:
-
return APPLICATION_MEDIA_OVERLAY_SUBLAYER;
//返回值是-1
-
case TYPE_APPLICATION_SUB_PANEL:
-
return APPLICATION_SUB_PANEL_SUBLAYER;
//返回值是2
-
case TYPE_APPLICATION_ABOVE_SUB_PANEL:
-
return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER;
//返回值是3
-
}
-
Log.e(TAG,
"Unknown sub-window type: " + type);
-
return
0;
-
}
3.3 、窗口Z序的调整
当WindowState创建完成,并且被添加到WMS维持的数组里面后,就需要调用WindowLayersController的assignLayersLocked(windows),进行Z序的调整。
-
//参数windows是窗口列表
-
final void assignLayersLocked(WindowList windows) {
-
if (DEBUG_LAYERS) Slog.v(TAG_WM,
"Assigning layers based on windows=" + windows,
-
new RuntimeException(
"here").fillInStackTrace());
-
-
clear();
-
int curBaseLayer =
0;
-
int curLayer =
0;
-
boolean anyLayerChanged =
false;
-
//遍历窗口列表,上面通过Z序的计算公式计算出来的Z序值保存在WindowState的变量mBaseLayer
-
中,这个循环的意思是,遇到同类型的窗口,后一个窗口在前一个窗口的基础上偏移5。
-
for (
int i =
0, windowCount = windows.size(); i < windowCount; i++) {
-
final WindowState w = windows.get(i);
-
boolean layerChanged =
false;
-
-
int oldLayer = w.mLayer;
-
if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i >
0 && w.mIsWallpaper)) {
-
curLayer += WINDOW_LAYER_MULTIPLIER;
-
}
else {
-
curBaseLayer = curLayer = w.mBaseLayer;
-
}
-
// 更新该窗口的mAnimLayer,也就是动画显示时,该窗口的层级
-
assignAnimLayer(w, curLayer);
-
-
// TODO: Preserved old behavior of code here but not sure comparing
-
// oldLayer to mAnimLayer and mLayer makes sense...though the
-
// worst case would be unintentionalp layer reassignment.
-
if (w.mLayer != oldLayer || w.mWinAnimator.mAnimLayer != oldLayer) {
-
layerChanged =
true;
-
anyLayerChanged =
true;
-
}
-
-
// 将当前应用窗口的最高显示层级记录在mHighestApplicationLayer中
-
if (w.mAppToken !=
null) {
-
mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
-
w.mWinAnimator.mAnimLayer);
-
}
-
// 对于分屏等相关的窗口,它们的显示层级需要再次处理
-
collectSpecialWindows(w);
-
-
if (layerChanged) {
-
w.scheduleAnimationIfDimming();
-
}
-
}
-
-
// 调整特殊窗口的层级
-
adjustSpecialWindows();
-
-
//TODO (multidisplay): Magnification is supported only for the default display.
-
if (mService.mAccessibilityController !=
null && anyLayerChanged
-
&& windows.get(windows.size() -
1).getDisplayId() == Display.DEFAULT_DISPLAY) {
-
mService.mAccessibilityController.onWindowLayersChangedLocked();
-
}
-
-
if (DEBUG_LAYERS) logDebugLayers(windows);
-
}
Android AMS(六) Activity与WMS的连接过程之AppWindowToken
WmS详解(一)之token到底是什么?基于Android7.0源码
参考:
Android解析WindowManagerService(一)WMS的诞生
Android窗口系统第一篇---Window的类型与Z-Order确定
Android AMS(六) Activity与WMS的连接过程之AppWindowToken
WmS详解(一)之token到底是什么?基于Android7.0源码