Android的窗口系统由WindowManagerService管理,包括增加和删除窗口,确定窗口的大小和位置,以及实现窗口切换、窗口动画等功能。WindowManagerService名字较长,后面简称WMS
前言
一个小问题
在 Android 中Activity可以理解成 Android 中的一个页面,前面的章节我们说 SurfaceFlinger 最后会把 Surface 对应的 Layer 合成到屏幕上。那么Activity 和 Surface 的关系又是怎么关联的呢?
让我们一起排查下~~~
应用进程和WMS的联系
在学习WMS之前,我们先了解下应用和WMS之间的联系。对于应用来说:
-
ActivityActivity并不负责视图控制,它只是控制生命周期和处理事件- 真正控制视图的是
Window。一个Activity包含了一个Window,Window才是真正代表一个窗口 Activity就像一个控制器,统筹视图的添加与显示,以及通过其他回调方法,来与Window、以及View进行交互
-
WindowWindow是视图的承载器,内部持有一个DecorView,而这个DecorView才是view的根布局Window是一个抽象类,实际在Activity中持有的是其子类PhoneWindowPhoneWindow中有个内部类DecorView,通过创建DecorView来加载Activity中``传递的布局Window通过WindowManager将DecorView加载其中,并将DecorView交给ViewRoot,进行视图绘制以及其他交互
-
ViewRoot- 所有
View的绘制以及事件分发等交互都是通过它来执行或传递的 ViewRoot对应的实现类是ViewRootImpl类,它是连接WindowManagerService和DecorView的纽带View的三大流程:测量(measure)、布局(layout)、绘制 (draw))均通过ViewRoot来完成
- 所有
除了上面这三部分,还有一个是在Android应用中存在的一个唯一的WindowManagerGlobal对象,它们的类图关系如下:

应用中的Window对象
应用中的每个Activity对象都有一个类型为Window的成员变量mWindow,定义如下:
java
class Activity {
...
private Window mWindow;
...
}
Window对象在应用进程代表了一个窗口,这是一块矩形的图像绘制区域。
从WMS的角度来说,它并不关系应用中的各种View,他管理和调度的对象是Window。Activity中的View树不管多复杂,最后输出的也仅仅是一张各个View合成的图像而已。
Window是一个抽象类,在Activity类的attach()方法中会对成员变量mWindow进行初始化,代码如下:
java
final void attach(...) {
...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
}
attach()方法中mWindow实例化成了一个PhoneWindow对象。
而对于PhoneWindow对象,需要我们关注的部分是如下两个成员变量:
java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
...
}
-
mDecor的类型是DecorView,它是FrameLayout的子类,它可以被认为是Android视图树的根节点视图。DecorView作为顶级View,它加载的资源文件内部会包含一个android:id="@android:id/content"的ViewGroup- 这个
ViewGroup便是后面用来添加setContentView()方法传入的layout布局文件 DecorView具体加载哪种布局文件和主题有关,这部分在PhoneWindow的generateLayout()方法中体现
-
mContentParent的类型是ViewGroup,它其实就是android:id="@android:id/content"对应的组件- 跟踪
generateLayout()方法就会发现如下代码:
javaViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);contentParent创建完成后便会赋值给mContentParent,而此处的ID_ANDROID_CONTENT的定义是在Window.java中
javapublic static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content; - 跟踪
应用中的WindowManager对象
应用中的每个Activity对象都有一个类型为WindowManager的成员变量mWindowManager,定义如下:
java
class Activity {
...
private WindowManager mWindowManager;
...
}
mWindowManager用于和WMS通信,不过WindowManager是一个接口类,定义如下:
java
public interface WindowManager extends ViewManager {...}
mWindowManager也是在attach()方法中进行的初始化,相关代码如下:
java
final void attach(...) {
...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
mWindowManager = mWindow.getWindowManager();
...
}
在attach()方法中,对mWindowManager变量的赋值是调用mWindow的getWindowManager()方法完成的。
但是在这之前,attach()方法中还调用了mWindow对象的setWindowManager()方法。前面我们已经知道mWindow对象的类型是PhoneWindow,不过这个setWindowManager()方法是在基类Window中实现的,代码如下:
java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
public WindowManager getWindowManager() {
return mWindowManager;
}
在setWindowManager()方法中,调用了WindowManagerImpl类的createLocalWindowManager()方法创建了mWindowManager对象,这个方法也很简单:
java
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mContext, parentWindow);
}
createLocalWindowManager()方法中新创建了一个WindowManagerImpl对象,因此,每个Activity中的mWindowManager对象实际上是一个WindowManagerImpl对象,我们再看下这个类的定义:
java
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Context mContext;
private final Window mParentWindow;
...
}
在WindowManagerImpl中定义了一个mGlobal变量,它的值是通过WindowManagerGlobal.getInstance()得到的,看样子是个单例模式,代码如下:
java
public static WindowManagerGlobal getInstance() {
synchronized (WindowManagerGlobal.class) {
if (sDefaultWindowManager == null) {
sDefaultWindowManager = new WindowManagerGlobal();
}
return sDefaultWindowManager;
}
}
getInstance()方法中创建了一个全局唯一的WindowManagerGlobal对象并保存到静态变量sDefaultWindowManager中
而WindowManagerImpl中各种方法的实现只是在转调WindowManagerGlobal类中的方法,由此可见,一个应用中所有Activity都是通过这个进程内唯一的WindowManagerGlobal对象和WMS通信
WindowManagerGlobal类中还有3个重要的成员变量:
java
public final class WindowManagerGlobal {
...
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
private final ArrayList<WindowManager.LayoutParams> mParams =
new ArrayList<WindowManager.LayoutParams>();
...
}
mViews:保存了应用中所有顶层View对象,也就是DecorView(稍后细讲)mRoots:保存的是和顶层View对象关联的ViewRootImpl对象mParams:保存的是创建顶层View的layout参数
建立应用和WMS的联系
我们知道在ActivityThread中的handleResumeActivity()中会创建ViewRootImpl对象并进行显示,我们来看下ViewRootImpl中关键的几个变量:
java
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
...
final IWindowSession mWindowSession;
...
final W mWindow;
...
}
变量的初始化是在构造方法中,代码如下:
java
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
...
mWindow = new W(this);
...
}
重点是进行了mWindowSession和mWindow的创建,我们逐一看下
IWindowSession对象的创建
mWindowSession变量的类型是IWindowSession,它是WMS中某个Binder对象的引用对象,mWindowSession的值是通过WindowManagerGlobal的getWindowSession()方法获得的,代码如下:
java
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (
`sWindowSession`== null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
如果sWindowSession为空,先获取InputMethodManager对象,然后调用WMS的openSession()接口来进行创建,代码如下:
java
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext);
return session;
}
openSession()直接创建了一个Session对象,这个Session类我们图像显示部分简单介绍过,它是一个Binder服务类,简要定义如下:
java
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {...}
对于用户进程而言,获取到的便是这个Session对象的Binder引用对象,并保存在了WindowManagerGlobal的静态变量sWindowSession中。
因为WindowManagerGlobal在进程中属于单例的存在,因此,所有调用getWindowSession()方法返回的都是这个sWindowSession对象
因此,一个用户进程中的所有ViewRootImpl对象中的mWindowSession都引用的是相同的对象 。而这个mWindowSession对象的作用便是向WMS发起Window相关的Binder调用
应用进程通过
sWindowSession对象可以调用到WMS的功能方法了,那么WMS是如何通知或者控制应用进程的呢?
W
在图像显示部分已经介绍过ActivityThread的handleResumeActivity()方法了,最后会调用到WindowManagerGlobal对象的addView()方法,方法内容如下:
java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
root.setView(view, wparams, panelParentView);
}
...
}
}
addView()方法中最重要的是创建了ViewRootImpl对象,并通过setView()把它和顶层的View对象关联在了一起。setView()方法简要如下:
java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
...
requestLayout();
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, ...);
}
...
}
}
}
setView()方法比较长,我们需要关注的是:
- 方法中对
ViewRootImpl对象和顶层View之间的关联只会执行一次,如果mView不为空,不会再次赋值 - 方法中调用了
Session的addToDisplay()方法,更为重要的是参数mWindow
mWindow的类型是W,它是一个ViewRootImpl的静态内部类,定义如下:
java
static class W extends IWindow.Stub {
private final WeakReference<ViewRootImpl> mViewAncestor;
private final IWindowSession mWindowSession;
...
}
可以看出W是一个实现了IWindow接口的Binder服务类,并且在ViewRootImpl中通过Session.addToDisplay()方法将W的Binder引用对象传递给了WMS
我们看下源码中对IWindow接口的描述:
API back to a client window that the Window Manager uses to inform it of interesting things happening.
可以看出WMS通过IWindow接口来通知应用,接下来看下WMS中是如何处理这个对象的
秋地麻袋~,还记得我们前言中的问题吗,快看setView中的requestLayout方法
是不是勾起了作为应用开发者的回忆
Surface 和 Activity 的联系
ViewRootImpl.setView() 会触发 requestLayout(),最终执行到核心方法 performTraversals()(这是 View 绘制三大流程 Measure/Layout/Draw 的入口)
performTraversals() 800 多行。。。简要代码如下:
java
// 伪代码逻辑 ViewRootImpl.java
private void performTraversals() {
// ...
// 1. 通过 IPC 请求 WindowManagerService (WMS) 对窗口进行布局
// mSurface 是 ViewRootImpl 的成员变量
relayoutResult = mWindowSession.relayout(..., mSurface, ...);
// 2. WMS 在底层创建 SurfaceControl,并将 Native 层的 Surface 信息
// 回写(Copy)到 ViewRootImpl 的 mSurface 中。
// 后面会细讲
if (mSurface.isValid()) {
// Surface 此时已经准备好,可以合成了
}
// ...
performMeasure(...);
performLayout(...);
performDraw(...);
}
在 relayout 过程中,WMS 会与 SurfaceFlinger 通信,分配 Layer(图层)。WMS 将生成的 Surface 信息填充到 ViewRootImpl 传入的 mSurface 参数中。
这样,一个 Activity 就和 SurfaceFlinger 中的 Surface 产生了关联啦。
WMS中建立和应用的关系
前面提到ViewRootImpl对象会通过addToDisplay()方法将IWindow的Binder引用对象传递到WMS中,我们先看下addToDisplay()方法:
java
// 方法定义在 com.android.server.wm.Session 中
@Override
public int addToDisplay(IWindow window, ...) {
// mService 的类型便是 WindowManagerService
return mService.addWindow(this, window, ...);
}
调用了WMS的addWindow()方法,代码如下:
java
public int addWindow(Session session, IWindow client, ...) {
...
synchronized(mWindowMap) {
...
if (mWindowMap.containsKey(client.asBinder())) {
Slog.w(TAG_WM, "Window " + client + " is already added");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}
...
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
...
win.attach();
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
...
}
...
return res;
}
addWindow()方法代码在200多行,此处我们需要关注的部分是:
- 创建了
WindowState对象并添加到mWindowMap集合中 - 调用
WindowState对象的attach()方法
WindowState后面会详细介绍,此处的关键定义如下:
java
/** A window in the window manager. */
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
...
final Context mContext;
final Session mSession;
final IWindow mClient;
...
void attach() {
if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
mSession.windowAddedLocked(mAttrs.packageName);
}
}
mClient是应用进程中Binder服务对象W的引用对象mSession便是WMS对外封装的对象之一。以前面的addToDisplay()为例,实际上只是转调了WMS的addWindow()方法attach()方法也只是调用了mSession对象的windowAddedLocked()方法
继续看下windowAddedLocked()方法:
java
void windowAddedLocked(String packageName) {
mPackageName = packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName;
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}
windowAddedLocked()方法
- 首先检查了
mSurfaceSession的值,当为空时才会创建SurfaceSession对象- 前面图像显示部分介绍过,
SurfaceSession对象是用来创建Surface的
- 前面图像显示部分介绍过,
- 然后将
Session对象本身添加到WMS的mSessions列表中
到这里,应用进程就和WMS各自持有了对方的Binder引用对象,形成了一个双向Binder通道,示意图如下:

DecorView
关于DecorView,还是要从我们最熟悉的地方说起。
在Activity的onCreate()中调用setContentView()方法时,我们看下发生了什么:
java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
Activity的onCreate()调用的是Window类的setContentView(),这是个抽象方法,具体的实现在PhoneWindow.java中,代码如下:
java
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
}
...
}
如果mContentParent对象还没有创建出来,则会调用installDecor()方法,方法如下:
java
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
mDecor = generateDecor(-1); // 创建 DecorView
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor); // 为DecorView设置布局格式,并返回 mContentParent
}
}
installDecor()方法
-
先根据成员变量
mDecor是否为空来决定是否进行DecorView的创建- 对象的创建方法为
generateDecor(),内容如下:
javaprotected DecorView generateDecor(int featureId) { Context context; ... // 省略 context 的创建过程 return new DecorView(context, featureId, this, getAttributes()); } - 对象的创建方法为
-
然后通过
generateLayout()方法为创建好的DecorView设置布局格式,并返回mContentParent对象
我们再看下DecorView的定义
java
/** @hide */
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
...
}
其实就是个自定义的ViewGroup,只是这个DecorView在Android中作为顶级View去使用
WindowManagerService服务
WMS服务的启动,要从SystemServer中的startOtherServices()方法说起,关键代码如下:
java
private void startOtherServices() {
...
wm = WindowManagerService.main(..., new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
...
}
看下main()方法的定义:
java
public static WindowManagerService main(..., WindowManagerPolicy policy) {
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
onlyCore, policy), 0);
return sInstance;
}
main()方法主要是初始化了WindowManagerService对象,我们需要注意的是它的最后的参数WindowManagerPolicy policy,它的具体的实现类是PhoneWindowManager
再看下WindowManagerService的关键定义:
java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
...
final ArraySet<Session> mSessions = new ArraySet<>();
final WindowHashMap mWindowMap = new WindowHashMap();
final WindowManagerPolicy mPolicy;
...
private WindowManagerService(..., WindowManagerPolicy policy) {
...
mPolicy = policy;
...
}
}
其中的关键成员如下:
-
mSessions中储存的是Session服务类的对象,每个应用在WMS中都有一个对应的Session对象,它们都保存在mSessions中 -
mWindowMap中类型是WindowHashMap,保存的是所有窗口的WindowState对象。WindowHashMap定义如下:javaclass WindowHashMap extends HashMap<IBinder, WindowState> { }- 此处并未做任何删减哈,源码中就是简单地继承了
HashMap<IBinder, WindowState> WindowState表示一个窗口的所有属性,它便是是WMS中的窗口。等下细讲
- 此处并未做任何删减哈,源码中就是简单地继承了
-
mPolicy是WMS中执行窗口管理策略的对象,类型是WindowManagerPolicy,这是一个接口类- 从
SystemServer的startOtherServices()中可以看出具体的实现类是PhoneWindowManager - 在
Android中WMS只是负责窗口管理的框架部分,通过策略模式将框架和窗口实现细节进行了分离
- 从
对比9.0和5.0源码,WMS关于窗口部分设计变化很大,在了解Android如何添加一个窗口前,我们先看下Android中窗口类型的定义
窗口类型
在WMS中定义了3中窗口:应用窗口、子窗口和系统窗口,相关的定义都是在frameworks/base/core/java/android/view/WindowManager.java中,确切的说应该是在WindowManager.LayoutParams类中定义
应用窗口(application window)
应用窗口是Activity使用的全屏窗口,Android定义了4种不同类型的应用窗口
TYPE_BASE_APPLICATION:基础应用窗口,应用中所有窗口都位于它的上层。只能由系统创建TYPE_APPLICATION:Activity的顶层窗口,应用中最常见的一种TYPE_APPLICATION_STARTING:应用启动时由系统创建的窗口,显示一些信息,直到应用创建的窗口显示出来TYPE_DRAWN_APPLICATION:类似于普通的TYPE_APPLICATION,WMS针对类型额外增加了等待机制
子窗口(sub-window)
子窗口是指依附于应用窗口或系统窗口的窗口类型,它们一般随所依附的窗口一起出现或切换到后台。Android中定义了6种子窗口类型
TYPE_APPLICATION_PANEL:应用Panel窗口,显示在依附窗口的上层TYPE_APPLICATION_MEDIA:应用Media窗口,通常包含独立的Surface,显示在依附窗口的下层TYPE_APPLICATION_SUB_PANEL:应用子Panel窗口,显示在依附窗口和TYPE_APPLICATION_PANEL的上层TYPE_APPLICATION_ATTACHED_DIALOG:和TYPE_APPLICATION_PANEL类似,但是窗口的布局方式和Activity的顶层窗口相同TYPE_APPLICATION_MEDIA_OVERLAY:一种显示在TYPE_APPLICATION_MEDIA和所依附窗口之间的半透明窗口。一般用来显示Video的字幕或者相机的操作提示界面TYPE_APPLICATION_ABOVE_SUB_PANEL:一种显示在TYPE_APPLICATION_SUB_PANEL之上的窗口
系统窗口(system window)
系统窗口大都用于系统生成的UI中,一般比较独立,种类非常多,我们挑几个常见的看下
TYPE_STATUS_BAR:状态栏窗口,系统中只能有一个,在屏幕的最上方TYPE_SEARCH_BAR:搜索栏窗口,系统中只能有一个,在屏幕的最上方TYPE_PHONE:电话窗口,提供用户与电话的交互界面,通常位于所用应用窗口的上方,但是在状态栏的后面TYPE_SYSTEM_ALERT:系统警告窗口,位于所用应用窗口的上方TYPE_TOAST:临时通知窗口,显示一些提示信息
还有很多就不一一列举了,Android对系统窗口的定义有39种之多,源码中有着详细的注释,大家可以在WindowManager.java中找到(传送门)
那么WMS中是怎么定义窗口的呢?
WMS中窗口的设计
前面讲过(
WMS的addWindow()方法),当向WMS添加一个窗口时,WMS会为其创建一个WindowState。对于WindowState来说,它包含了一个窗口的所有属性,所以它是WMS中真正意义上的窗口
先看下WindowState的关键定义:
java
/** A window in the window manager. */
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
...
WindowToken mToken;
AppWindowToken mAppToken;
...
final int mBaseLayer;
final int mSubLayer;
}
WindowState继承了WindowContainer,又是和书中不一样的地方
对比5.0源码,很明显在
Window这部分Android做了重构(设计模式看上去像是组合模式),优化了类结构,抽象出了WindowContainer用来支撑起整个窗口体系
基于Android 9.0源码,窗口体系的关系梳理如下:

类图中涉及到的类的信息下:
-
WindowContainer- 成员变量
mChildren的类型是WindowList,看实现其实就是ArrayList<WindowState>。又因为WindowToken继承了WindowContainer,所以该成员变量子类都会继承过来 - 所有拥有相同
Token的窗口(WindowState)都会存放在mChildren中,
- 成员变量
-
WindowToken- 成员变量
token是IBinder对象,具有系统唯一性,向WMS的mWindowMap中添加对象时都是使用这个token值 - 定义了
AppWindowToken asAppWindowToken(),默认返回null
- 成员变量
-
AppWindowToken- 继承自
WindowToken并重写了AppWindowToken asAppWindowToken()方法,返回this - 这样便可以通过
asAppWindowToken()的返回值判断是那种Token
- 继承自
-
DisplayContent- 继承自
WindowContainer,真正意义上的屏幕,WMS中一个DisplayContent实例表示一个屏幕。多屏幕会对应多个实例 - 内部定义了4种存放
Window的容器,都是直接或间接继承自WindowContainer:mTaskStackContainers:用来保存所有的应用窗口mAboveAppWindowsContainers:用来保存显示在应用窗口的上面的非应用窗口mBelowAppWindowsContainers:用来保存显示在应用窗口的下面的非应用窗口mImeWindowsContainers:用来保存 IME Window
- 继承自
-
RootWindowContainer- 代表
WMS中窗口的根容器,所有DisplayContent的实例都会添加到其中 RootWindowContainer在WMS的构造方法中初始化为mRoot对象
- 代表
还是回到WindowState,类中定义了两个常量mBaseLayer和mSubLayer,通过这两个常量便可以确定一个Window所在的层级。这部分就不细讲了哈,涉及点有点多,后面用到再来补充吧,嘻嘻
我们重点看下面两个知识点:WMS的addWindow和relayoutWindow的设计
addWindow方法
addWindow()在WMS中建立和应用的关系已经介绍,不再赘述
relayoutWindow方法
前面介绍过,在Activity的onResume阶段,通过ViewRootImpl的setView方法开始渲染View的流程。
setView方法中会通过requestLayout()开始测量渲染,这个方法中有一个核心的逻辑就是调用WMS的relayoutWindow(),重新测量Window,简要流程如下:
java
//ViewRootImpl.java
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
...
scheduleTraversals();
}
}
private void performTraversals() {
...
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
...
}
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
...
int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurface);
...
return relayoutResult;
}
relayoutWindow()通过Session的relayout()方法调用到WMS的relayoutWindow()方法
java
@Override
public int relayout(IWindow window, int seq, ...) {
...
int res = mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outBackdropFrame, cutout,
mergedConfiguration, outSurface);
...
return res;
}
WMS中的relayoutWindow()代码比较复杂,我们简单看下:
java
public int relayoutWindow(...) {
...
synchronized(mWindowMap) {
// 从 mWindowMap 取出对应的 WindowState 对象
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return 0;
}
displayId = win.getDisplayId();
...
// 调用 WindowSurfacePlacer 的 performSurfacePlacement 方法
// 这个方法其实就是检查清理无用的 Surface 对象,为后面创建 Surface 做准备
// 详细的方法就不贴出来了,大家可以自行阅读
mWindowPlacerLocked.performSurfacePlacement(true /* force */);
if (shouldRelayout) {
result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);
try {
// 创建 Surface ,确切的说应该是创建 WindowSurfaceController 对象
// WindowSurfaceController 其实就是对 Surface 和 SurfaceControl 的封装
// Surface 和 SurfaceControl 的关系在十二章已经介绍啦
result = createSurfaceControl(outSurface, result, win, winAnimator);
}
...
} else {
...
}
if (focusMayChange) {
// 如果窗口发生了变化,调用 updateFocusedWindowLocked 方法重新测量窗口大小
// 这个方法才是真正的核心测量窗口大小逻辑
// 方法中会调用 DisplayContent.performLayout 方法开始真正的测量
if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
false /*updateInputWindows*/)) {
imMayMove = false;
}
}
...
win.mInRelayout = false;
}
...
}
在 WMS 的 relayoutWindow() 方法中,核心逻辑在于 createSurfaceControl 的调用。
java
result = createSurfaceControl(outSurface, result, win, winAnimator);
这里的参数 outSurface 至关重要。回看 ViewRootImpl 调用 relayout 的代码:
java
// ViewRootImpl.java
mWindowSession.relayout(..., mSurface);
我们可以明确看到,ViewRootImpl 将自己的成员变量 mSurface 传递给了 WMS。 在 WMS 内部,createSurfaceControl 会请求 SurfaceFlinger 创建图层(Layer),并将生成的 Native 层 Surface 信息回写(Copy)到传入的 outSurface 参数中。
这意味着: 当 relayoutWindow 调用返回时,应用进程 ViewRootImpl 中的 mSurface 对象就已经持有了真正的图形缓冲区引用,随后应用便可以利用这个 Surface 进行绘图。
怎么说~怎么说~。前言的问题是不是明了啦
总结
Android 的窗口系统是一个典型的 C/S 架构,由应用进程(Client)和 WindowManagerService(Server)共同构成:
应用端 (Client)
-
Activity负责生命周期,持有一个PhoneWindow对象来管理视图策略。 -
DecorView是视图树的根节点。 -
ViewRootImpl是核心管理者,它连接了 DecorView 和WMS,并持有Surface对象,负责发起绘制流程(Measure/Layout/Draw)。 -
WindowManagerGlobal是进程单例,负责管理当前进程所有的ViewRootImpl和View。
通信层 (IPC)
-
IWindowSession:应用向WMS发送请求的通道(如addToDisplay,relayout)。 -
IWindow(W类):WMS回调应用的通道(如窗口焦点变化、配置改变)。
服务端 (WMS)
-
WindowState:WMS中代表一个窗口的实体,保存窗口的所有属性。 -
WindowContainer:构建了层级化的窗口容器结构(DisplayContent->TaskStack->WindowState)。 -
Surface管理:WMS在relayoutWindow过程中计算窗口大小与位置,并与SurfaceFlinger通信创建SurfaceControl,最终将可用的Surface返回给应用端。