一、基本概念
1、窗口显示架构图
多窗口的核心原理其实就是分栈和设置栈边界
2、Android的窗口分类
Android应用程序窗口,这个是最常见的(拥有自己的WindowToken)譬如:Activity与Dialog
Android应用程序子窗口(必须依附到其他非子窗口才能存在,通常这个被依附的窗口类型Activity窗口) 例如:PopupWindow
Android系统窗口,其中我们最最常见的就是Toast窗口了
3、StackId
【Id:0】Home Stack,这个是Launcher所在的Stack。 其实还有一些系统界面也运行在这个Stack上,例如近期任务
【Id:1】FullScren Stack,全屏的Activity所在的Stack。 但其实在分屏模式下,Id为1的Stack只占了半个屏幕。
【Id:2】Freeform模式的Activity所在Stack
【Id:3】Docked Stack 下文中我们将看到,在分屏模式下,屏幕有一半运行了一个固定的应用,这个就是这里的Docked Stack
【Id:4】Pinned Stack 这个是画中画Activity所在的Stack
4、窗口管理中涉及的几个重要概念
IWindow: APP端窗口暴露给WMS的抽象实例,同时也是WMS向APP端发送消息的Binder通道,它在APP端的实现为W
IWindowSession:WMS服务用于提供给ViewRootImpl来和其进行跨Binder通信的接口
WindowState:WMS端窗口的令牌,与IWindow窗口一一对应,是WMS管理窗口的重要依据
WindowToken:是窗口的令牌,也是窗口分组的依据,在WMS端,和分组对应的数据结构是WindowToken
Token:是在AMS构建Activity对应的ActivityRecord时里面的IApplicationToken的实例,会在Activity创建过程中传递到AMS中,并且Token会在Activity从创建到显示的过程中会在App进程和AMS,WMS之间进行传递
ActivityManagerService
Activity管理机制的Binder服务端,属于一个系统服务。用于管理Activity的各种行为,控制Activity的生命周期,派发消息事件,低内存管理等等。实现了IBinder接口,可以用于进程间通信
ActivityStarter
用来负责处理Activity的Intent和Flags, 还有关联相关的Stack和TaskRecord
ActivityManagerProxy
AMS服务代理端,第三方应用借助该类实现对AMS的远程RPC请求
ActivityRecord
顾名思义,该数据结构和我们的Activiyt相对应,存储者Activiyt的相关信息,并且每个ActivityRecord会对应到一个TaskRecord,ActivityRecord中类型为TaskRecord的成员task,记录所属的Task,这里有一点需要注意的是Activity和ActivityRecord并不是一对一的,而是一对多,因为一个Actitiy可能存在多个启动方式进而导致存在多个ActivityRecord
TaskRecord
一个TaskRecord由一个或者多个ActivityRecord组成,这就是我们常说的任务栈,具有后进先出的特点
ActivityStack
用来管理TaskRecord,它有一个ArrayList类型的成员mTaskHistory,用于存储TaskRecord,系统总是显示位于栈顶的Activity
ActivityDisplay
ActivityDisplay表示一个屏幕,Android支持三种屏幕:主屏幕,外接屏幕(HDMI等),虚拟屏幕(投屏)。一般情况下,即只有主屏幕时,ActivityStackSupervisor与ActivityDisplay都是系统唯一;
ActivityDisplay是ActivityStackSupervisor的内部类,它相当于一个工具类,封装了移除和添加ActivityStack的方法
ActivityStackSupervisor
负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。
mHomeStack管理的是Launcher相关的Activity栈
mFocusedStack管理的是当前显示在前台Activity的Activity栈
mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈
5、AMS和WMS交互图
6、AMS与WMS任务栈对应关系
AMS和WMS在应用窗口这块是有对应关系:
ActivityDisplay----------DisplayContent
ActivityStack------------TaskStack
TaskRecord-------------Task
ActivityRecord----------AppWindowToken
AMS这边依次为:
ActivityDisplay->ActivityStack->TaskRecord->ActivityRecord
WMS依次分为:
DisplayContent(TaskStackContainer)->TaskStack->Task->AppWindowToken
二、窗口添加并计算
1、Activity窗口尺寸
ViewRootImpl.setView()开始窗口视图的添加
/**
这里我们分析的是Activity的DecorView窗口视图添加的逻辑,所以此时不存在父视图的概念,
不会走到这里,此时的panelParentView为null
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
//顶层DecorView
mView = view;
.......
//添加窗口到WMS,mWindow(Binder类型W,传给WMS以便WMS可以调用应用进程方法)
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
//mTmpFrame为WMS计算得到的窗口尺寸
setFrame(mTmpFrame);
......
}
}
}
通过Seesion.java最终调到WindowManagerService.addWindow
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {
int res = mPolicy.checkAddPermission(attrs, appOp);
//...
synchronized(mWindowMap) {
//...
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent == null) {
Slog.w(TAG, "Attempted to add window to a display that does not exist: "
+ displayId + ". Aborting.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
//...
WindowToken token = mTokenMap.get(attrs.token);
//...
// 新的WindowState对象在其构造函数中根据窗口类型初始化了其主序mBaseLayer和mSubLayer
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
......
return res;
}
WindowState.WindowState构造初始化
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
...
//如果是子窗口,使用它依附的窗口类型来计算
if ((mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW)) {
mBaseLayer = mPolicy.windowTypeToLayerLw(
attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;//计算mBaseLayer,关键点1
//表示子窗口和父窗口的相对位置
mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);//计算mSubLayer,关键点2
...
} else {
//非子窗口,直接使用窗口类型来计算
//注:TYPE_LAYER_MULTIPLIER的值是10000,TYPE_LAYER_OFFSET的值是1000
mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
+ WindowManagerService.TYPE_LAYER_OFFSET;
mSubLayer = 0;//无效,仅在子窗口中有用
...
}
...
}
WindowManagerPolicy.windowTypeToLayerLw
计算主窗口位置
//根据类型返回窗口的种类,从1-31,
public int windowTypeToLayerLw(int type) {
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
return 2;
}
switch (type) {
case TYPE_UNIVERSE_BACKGROUND:
return 1;
case TYPE_PRIVATE_PRESENTATION:
return 2;
case TYPE_WALLPAPER:
// wallpaper is at the bottom, though the window manager may move it.
return 2;
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
return 4;
...
case TYPE_HIDDEN_NAV_CONSUMER:
return 30;
/// M:JB migration
case TYPE_TOP_MOST:
return 31;
}
Log.e(TAG, "Unknown window type: " + type);
return 2;
}
WindowManagerPolicy.subWindowTypeToLayerLw
计算子窗口位置
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
}
Log.e(TAG, "Unknown sub-window type: " + type);
return 0;
}
WindowManagerService.getLayoutHintLw: 计算窗口的大小
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets,