理解 WindowManagerService

WMS 的职责

WMS 是 Android 中重要的服务,它是 WindowManager 的管理者,除此之外,它还有很多重要的职责,每个职责都会涉及重要且复杂的系统。

窗口管理

WMS 是窗口的管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由 WMS 进行管理的。窗口管理的核心成员有 DisplayContent、WindowToken 和 WindowState。

窗口动画

窗口间进行切换时,使用窗口动画可以显得更炫一些,窗口动画由 WMS 的动画子系统来负责,动画子系统的管理者为 WindowAnimator。

输入系统的中转站

通过对窗口的触摸从而产生触摸事件,InputManagerService(IMS)会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口的管理者,它作为输入系统的中转站再合适不过了。

Surface 管理

窗口并不具备绘制的能力,因此每个窗口都需要有一块 Surface 来供自己绘制,为每个窗口分配 Surface 是由 WMS 来完成的。

从 WMS 的职责可以看出 WMS 很复杂,与它关联的有窗口管理、

窗口动画、输入系统和 Surface,它们每一个都是重要且复杂的系统,本章只介绍其中的窗口管理,因为它和应用开发的关联比较紧密。


WMS 的创建过程

WMS 是在 SystemServer 进程中创建的,先查看 SystemServer 的 main 方法。SystemServer.java

1
2
3
4
public static void main(String[] args) {
// 调用了 SystemServer 的 run 方法。
new SystemServer().run();
}
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
private void run() {
try {
...
// 创建消息 Looper
Looper.prepareMainLooper();
// 加载了动态库 libandroid_servers.so
System.loadLibrary("android_servers");
performPendingShutdown();
// 创建系统的 Context。
createSystemContext();
// 创建 SystemServiceManager。它会对系统的服务进行创建、启动和生命周期管理。
mSystemServiceManager = new SystemServiceManager(mSystemContext);
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
SystemServerInitThreadPool.get();
} finally {
traceEnd();
}

try {
traceBeginAndSlog("StartServices");
// 官方将系统服务分为 3 种类型,这些服务的父类都是 SystemService。
// 启动引导服务,此方法中用 SystemServiceManager 启动了 ActivityManagerService、PowerManagerService、PackageManagerService 等服务。
startBootstrapServices();
// 启动核心服务,此方法中启动了 DropBoxManagerService、BatteryService、UsageStatsService 和 WebViewUpdateService。
startCoreServices();
// 其它服务是一些非紧要和不需要立即启动的服务。
// 启动其它服务,此方法中启动了 CameraService、AlarmManagerService、VrManagerService 等服务。
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...
}

WMS 就是其他服务的一种,查看 startOtherServices 方法中是如何启动 WMS 的。

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
/**
* 此方法用于启动其他服务,其他服务大概有 100 个左右,这里只列出了 WMS 以及和它相关的 IMS 的启动逻辑,剩余的* 其他服务的启动逻辑也都大同小异。
*/
private void startOtherServices() {
...
traceBeginAndSlog("InitWatchdog");
// 得到 Watchdog 的实例。(Watchdog 用来监控系统的一些关键服务的运行状况。)
final Watchdog watchdog = Watchdog.getInstance();
// 对 Watchdog 进行初始化。
watchdog.init(context, mActivityManagerService);
traceEnd();

traceBeginAndSlog("StartInputManagerService");
// 创建了 IMS,并赋值给 IMS 类型的 inputManager 对象。
inputManager = new InputManagerService(context);
traceEnd();

traceBeginAndSlog("StartWindowManagerService");
ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
mSensorServiceStart = null;
// 执行了 WMS 的 main 方法,其内部会创建 WMS。参数包含了 IMS 引用,因为 WMS 是输入事件的中转站。
// 可见,WMS 的 main 方法运行在 SystemServer 的 run 方法中,也就是说运行在 “system_server” 线程中。
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
// 将 WMS 注册到 ServiceManager 中。这样如果某个客户端想要使用 WMS,就需要先去 ServiceManager 中查询信息,然后根据信息与 WMS 所在的进程建立通信通路,客户端就可以使用 WMS 了。
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
// 将 IMS 注册到 ServiceManager 中。
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
traceEnd();
...
try {
// 初始化屏幕显示信息。
wm.displayReady();
} catch (Throwable e) {
reportWtf("making display ready", e);
}
...
try {
// 用来通知 WMS,系统的初始化工作已经完成,其内部调用了 WindowManagerPolicy 的 systemReady 方法
wm.systemReady();
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
...
}

接下来查看 WMS 的 main 方法。WindowManagerService.java

1
2
3
4
5
6
7
8
9
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
WindowManagerPolicy policy) {
// DisplayThread 是一个单例的前台线程,这个线程用来处理需要低延时显示的相关操作,并只能由 WindowManager、DisplayManager 和 InputManager 实时执行快速操作。
DisplayThread.getHandler().runWithScissors(() -> // Lambda 表达式(Runnable 的 run 方法)
// 创建了 WMS 的实例。这个过程是运行在 Runnbale 的 run 方法中,而 Runnable 则传到了 DisplayThread 对应 Handler 的 runWithScissors 方法中,说明 WMS 的创建是运行在 android.display 线程中的。
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,onlyCore, policy), 0);
return sInstance;
}

接下来查看 Handler 的 runWithScissors 方法。Handler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public final boolean runWithScissors(final Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
// 根据每个线程只有一个 Looper 的原理来判断当前的线程(system_server 线程)是否是 Handler 所指向的线程(android.display 线程),如果是则直接执行 Runnable 的 run 方法,如果不是则调用 BlockingRunnable 的 postAndWait 方法,并将当前线程的 Runnable 作为参数传进去.
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
// BlockingRunnable 是 Handler 的内部类。
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
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
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;

public BlockingRunnable(Runnable task) {
mTask = task;
}

@Override
public void run() {
try {
//注释1: 执行了传入的 Runnable 的 run 方法(运行在 android.display 线程),执行完毕后在 finally 代码块中将 mDone 设置为 true,并调用 notifyAll() 唤醒处于等待状态的线程,这样就不会继续调用注释 2 处的 wait()。
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}

public boolean postAndWait(Handler handler, long timeout) {
// 将当前的 BlockingRunnable 添加到 Handler 的任务队列中。已知传入的 timeout 为 0。
if (!handler.post(this)) {
return false;
}

synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
//注释2: 如果 mDone 为 false,会一直调用 wait() 使得当前线程(system_server 线程)进入等待状态,等待的线程为 注释 1 处。
// 可知,system_server 线程等待的就是 android.display 线程,一直到 android.display 线程执行完毕再执行 system_server 线程,这是因为 android.display 线程内部执行了 WMS 的创建,而 WMS 的创建优先级要更高。
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}

WMS 的创建就到这里。最后查看 WMS 的构造方法。WindowManagerService.java

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
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
...
// 用来保存传进来的 IMS,这样 WMS 就持有了 IMS 的引用。
mInputManager = inputManager;
...
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
// 通过 DisplayManager 的 getDisplays() 得到 Display 数组(每个显示设备都有一个 Display 实例),接着遍历 Display 数组。
mDisplays = mDisplayManager.getDisplays();
for (Display display : mDisplays) {
// 将 Display 封装成 DisplayContent,DisplayContent 用来描述一块屏幕。
createDisplayContentLocked(display);
}
...
// 得到 AMS 的实例,并赋值给 mActivityManager,这样 WMS 就持有了 AMS 的引用。
mActivityManager = ActivityManager.getService();
...
// 创建了 WindowAnimator,它用于管理所有的窗口动画。
mAnimator = new WindowAnimator(this);
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
LocalServices.addService(WindowManagerInternal.class, new LocalService());
// 初始化了窗口管理策略的接口类 WindowManagerPolicy(WMP),它用来定义一个窗口策略所要遵循的通用规范。
initPolicy();
// 将自身也就是 WMS 通过 addMonitor 方法添加到 Watchdog 中,Watchdog 用来监控系统的一些关键服务的运行状况(比如传入的 WMS 的运行状况),这些被监控的服务都会实现 Watchdog.Monitor 接口。Watchdog 每分钟都会对被监控的系统服务进行检查,如果被监控的系统服务出现了死锁,则会杀死 Watchdog 所在的进程,也就是 SystemServer 进程。
Watchdog.getInstance().addMonitor(this);
...
}
1
2
3
4
5
6
7
8
9
10
11
12
private void initPolicy() {
// 和 WMS 的 main 方法的实现类似。
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
// 执行了 WMP 的 init 方法,WMP 是一个接口,init 方法具体在 PhoneWindowManager(PWM) 中实现。PWM 的 init 方法运行在 android.ui 线程中,它的优先级要高于 initPolicy 方法所在的 android.display 线程,因此 android.display 线程要等 PWM 的 init 方法执行完毕后,处于等待状态的 android.display 线程才会被唤醒从而继续执行下面的代码。
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}

三个线程之间的关系分为三个步骤来实现:

  • 首先在 system_server 线程中执行了 SystemServer 的 startOtherService 方法,在 startOtherService 方法中会调用 WMS 的 main 方法,main 方法会创建 WMS,创建的过程在 android.display 线程中实现,创建 WMS 的优先级更高,因此 system_server 线程要等 WMS 创建完成后,处于等待状态的 system_server 线程才会被唤醒从而继续执行下面的代码。
  • 在 WMS 的构造方法中会调用 WMS 的 initPolicy 方法,此方法又会调用 PWM 的 init 方法,PWM 的 init 方法在 android.ui 线程中运行,它的优先级要高于 android.display 线程,因为 android.display 线程要等 PWM 的 init 方法执行完毕后,处于等待状态的 android.display 线程才会被唤醒从而继续执行下面的代码。
  • PWM 的 init 方法执行完毕后,android.display 线程就完成 WMS 的创建,等待 system_server 线程被唤醒后继续执行 WMS 的 main 方法后的代码逻辑,比如 WMS 的 displayReady 方法用来初始化屏幕显示信息。

##

WMS 的重要成员

WMS 的部分成员变量如下:WindowManagerService.java

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
// WMP 类型变量。WMP 是窗口管理策略的接口类,用来定义一个窗口策略索要遵循的通用规范,并提供了 WindowManager 所有的特定的 UI 行为。它的具体实现类为 PhoneWindowManager,这个实现类在 WMS 创建时被创建。WMP 允许定制窗口层级和特殊窗口类型以及关键的调度和布局。
final WindowManagerPolicy mPolicy;
final IActivityManager mActivityManager;
final ActivityManagerInternal mAmInternal;
final AppOpsManager mAppOps;
final DisplaySettings mDisplaySettings;
...
// mSessions 是 ArraySet 类型的变量,元素类型为 Session,它主要用于进程间通信,其它的应用程序进程想要和 WMS 进程进行通信就需要经过 Session,并且每个应用程序进程都会对应一个 Session,WMS 保存这些 Session 用来记录所有向 WMS 提出窗口管理服务的客户端。
final ArraySet<Session> mSessions = new ArraySet<>();
// 用来保存 WMS 中各种窗口的集合。WindowHashMap 继承了 HashMap,它限制了 HashMap 的 key 值的类型为 IBinder,value 值的类型为 WindowState。WindowState 用于保存窗口的信息,在 WMS 中它用来描述一个窗口。
final WindowHashMap mWindowMap = new WindowHashMap();
// AppWindowToken 是 WindowToken 的子类。WindowToken 主要有两个作用:
// - 可以理解为窗口令牌,当应用程序想要向 WMS 申请新创建一个窗口,则需要向 WMS 出示有效的 WindowToken。AppWindowToken 作为其子类,主要用来描述应用程序的 WindowToken 结构,应用程序中每个 Activity 都对应一个 AppWindowToken。
// - WindowToken 会将同一个组件(比如同一个 Activity)的窗口(WindowState)集合在一起,方便管理。
// mFinishedStarting 就是用于存储已经完成启动的应用程序窗口(比如 Activity)的 AppWindowToken 的列表。
final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
// 存储了已经完成窗口绘制并且不需要展示任何已保存 surface 的应用程序窗口的 AppWindowToken。
final ArrayList<AppWindowToken> mFinishedEarlyAnim = new ArrayList<>();
// 存储了等待更换的应用程序窗口的 AppWindowToken,如果更换不及时,旧窗口就需要被处理。
final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>();
// 用来存储正在调整大小的窗口的列表。
final ArrayList<WindowState> mResizingWindows = new ArrayList<>();
// 是在内存耗尽时设置的,里面存有需要强制删除的窗口。
final ArrayList<WindowState> mPendingRemove = new ArrayList<>();
WindowState[] mPendingRemoveTmp = new WindowState[20];
// 里面存有需要被销毁的 surface。
final ArrayList<WindowState> mDestroySurface = new ArrayList<>();
// 里面存有窗口需要保存的等待销毁的 surface。
// 保存 surface 的意义在于,当窗口经历 Surface 变化时,窗口需要一直保持旧 Surface,直到新 Surface 的第一帧绘制完成。
final ArrayList<WindowState> mDestroyPreservedSurface = new ArrayList<>();
ArrayList<WindowState> mLosingFocus = new ArrayList<>();
final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
ArrayList<WindowState> mWaitingForDrawn = new ArrayList<>();
...
// 系统的 Handler 类,用于将任务加入到主线程的消息队列中,这样代码逻辑就会在主线程中执行。
final H mH = new H();
...
// 输入系统的管理者。
final InputManagerService mInputManager;
...
// 用于管理窗口的动画以及特效动画。
final WindowAnimator mAnimator;

Window 的添加过程

Window 的操作分为两大部分,WindowManager 处理部分和 WMS 处理部分,接下来看 WMS 处理部分。无论是系统窗口还是 Activity,它们的 Window 的添加过程都会调用 WMS 的 addWindow 方法:WindowManagerService.java

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
* WMS 的 addView 方法返回的是 addView 的各种状态,比如添加 Window 成功,无效的 display 等,这些状态被定义在 WindowManagerGlobal 中。
*/
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
InputChannel outInputChannel) {

int[] appOp = new int[1];
// 根据 Window 的属性,调用 WMP 的 checkAddPermission 方法来检查权限,具体在 PhoneWindowManager 的 checkAddPermission 方法中实现,如果没有权限则不会执行后续的代码逻辑。
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
...
synchronized(mWindowMap) {
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
// 通过 displayId 来获取窗口要添加到哪个 DisplayContent 上,如果没有找到 DisplayContent,则返回 WindowManagerGlobal.ADD_INVALID_DISPLAY 这一状态。(DisplayContent 用来描述一块屏幕)
final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
if (displayContent == null) {
Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
+ displayId + ". Aborting.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
...
// type 代表一个窗口的类型,它的数值介于 FIRST_SUB_WINDOW 和 LAST_SUB_WINDOW 之间(1000~1999),这个数值定义在 WindowManager 中,说明这个窗口是一个子窗口。
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
// attrs.token 是 IBinder 类型的对象,windowForClientLocked 方法内部会根据 attrs.token 作为 key 值从 mWindowMap 中得到该子窗口的父窗口。接着父窗口进行判断,如果父窗口为 null 或者 type 的取值范围不正确则会返回错误的状态。
parentWindow = windowForClientLocked(null, attrs.token, false);
if (parentWindow == null) {
Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
...
AppWindowToken atoken = null;
final boolean hasParent = parentWindow != null;
// 通过 DisplayContent 的 getWindowToken 方法得到 WindowToken。
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
// 如果有父窗口就将父窗口的 type 值赋值给 rootType,如果没有将当前窗口的 type 值赋值给 rootType。
final int rootType = hasParent ? parentWindow.mAttrs.type : type;

boolean addToastWindowRequiresToken = false;
if (token == null) {
// 当 rootType 等于 TYPE_INPUT_METHOD 或 TYPE_WALLPAPER 等值时,则返回状态值 WindowManagerGlobal.ADD_BAD_APP_TOKEN ,说明此时是不允许 WindowToken 为 null 的。
if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
Slog.w(TAG_WM, "Attempted to add application window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_INPUT_METHOD) {
Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_VOICE_INTERACTION) {
Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (rootType == TYPE_WALLPAPER) {
Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
...
if (type == TYPE_TOAST) {
if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
parentWindow)) {
Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
// 通过多次条件筛选,然后在此处隐式创建 WindowToken,这说明当我们添加窗口时可以不向 WMS 提供 WindowToken,前提是 rootType 和 type 的值不为前面条件判断筛选的值。
// 参数 false 是用来区分 WindowToken 隐式或显式创建的。false 代表隐式创建。
token = new WindowToken(this, binder, type, false, displayContent,
session.mCanAddInternalSystemWindow);
// 接下来在 WindowToken 不为 null 的情况下,根据 rootType 和 type 的值进行判断。
// 比如此处判断如果窗口为应用程序窗口。
} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
// 将 WindowToken 转换为专门针对应用程序窗口的 AppWindowToken,然后根据 AppWindowToken 的值进行后续的判断。
atoken = token.asAppWindowToken();
if (atoken == null) {
Slog.w(TAG_WM, "Attempted to add window with non-application token "
+ token + ". Aborting.");
return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
} else if (atoken.removed) {
Slog.w(TAG_WM, "Attempted to add window with exiting application token "
+ token + ". Aborting.");
return WindowManagerGlobal.ADD_APP_EXITING;
}
} else if (rootType == TYPE_INPUT_METHOD) {
if (token.windowType != TYPE_INPUT_METHOD) {
Slog.w(TAG_WM, "Attempted to add input method window with bad token "
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
...
// 创建 WindowState,它存有窗口的所有的状态信息,在 WMS 中它代表一个窗口。
// 参数中,this 指的是 WMS,client 指的是 IWindow,IWindow 会将 WMS 中窗口管理的操作回调给 ViewRootImpl,token 指的是 WindowToken。
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);
// 判断请求添加窗口的客户端是否已经死亡。
if (win.mDeathRecipient == null) {
Slog.w(TAG_WM, "Adding window client " + client.asBinder()
+ " that is dead, aborting.");
return WindowManagerGlobal.ADD_APP_EXITING;
}
// 窗口的 DisplayContent 是否为 null。
if (win.getDisplayContent() == null) {
Slog.w(TAG_WM, "Adding window to Display that has been removed.");
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
// 调用了 WMP 的 adjustWindowParamsLw 方法,该方法在 PhoneWindowManager 中实现,此方法会根据窗口的 type 对窗口的 LayoutParams 的一些成员变量进行修改。
mPolicy.adjustWindowParamsLw(win.mAttrs);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
// 调用了 WMP 的 prepareAddWindowLw 方法,用于准备将窗口添加到系统中。
res = mPolicy.prepareAddWindowLw(win, attrs);
...
win.attach();
// 将 WindowState 添加到 mWindowMap 中。
mWindowMap.put(client.asBinder(), win);
if (win.mAppOp != AppOpsManager.OP_NONE) {
int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(),
win.getOwningPackage());
if ((startOpResult != AppOpsManager.MODE_ALLOWED) &&
(startOpResult != AppOpsManager.MODE_DEFAULT)) {
win.setAppOpVisibilityLw(false);
}
}

final AppWindowToken aToken = token.asAppWindowToken();
if (type == TYPE_APPLICATION_STARTING && aToken != null) {
aToken.startingWindow = win;
if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
+ " startingWindow=" + win);
}

boolean imMayMove = true;
// 将 WindowState 添加到该 WindowState 对应的 WIndowToken 中(实际是保存在 WindowToken 的父类 WindowContainer 中),这样 WindowToken 就包含了同一个组件的 WindowState。
win.mToken.addWindow(win);
if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
setInputMethodWindowLocked(win);
imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
displayContent.computeImeTarget(true /* updateImeTarget */);
imMayMove = false;
} else {
if (type == TYPE_WALLPAPER) {
displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
...
}

addView 方法总结:主要做了如下 4 件事

  • 对所要添加的窗口进行检查,如果窗口不满足一些条件,就不会再执行下面的代码逻辑。
  • WindowToken 相关的处理,比如有的窗口类型需要提供 WindowToken,没有提供的话就不会执行下面的代码逻辑,有的窗口类型则需要由 WMS 隐式创建 WindowToken。
  • WindowState 的创建和相关处理,将 WindowToken 和 WindowState 相关联。
  • 创建和配置 DisplayContent,完成窗口添加到系统前的准备工作。

Window 的删除过程

为了表述的更易于理解,下面将要删除的 Window(View)简称为 V。从 WindowManagerGlobal 的 removeView 方法开始查看。WindowManagerGlobal.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void removeView(View view, boolean immediate) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}

synchronized (mLock) {
// 找到 V 在 View 列表的索引。
int index = findViewLocked(view, true);
View curView = mRoots.get(index).getView();
// 调用了 removeViewLocked 方法,并将索引传进去。
removeViewLocked(index, immediate);
if (curView == view) {
return;
}

throw new IllegalStateException("Calling with view " + view
+ " but the ViewAncestor is attached to " + curView);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void removeViewLocked(int index, boolean immediate) {
// 根据传入的索引在 ViewRootImpl 列表中获得 V 的 ViewRootImpl。
ViewRootImpl root = mRoots.get(index);
View view = root.getView();

if (view != null) {
// 得到 InputMethodManager 实例。
InputMethodManager imm = InputMethodManager.getInstance();
if (imm != null) {
// 调用 InputMethodManager 的 windowDismissed 方法来结束 V 的输入法相关的逻辑。
imm.windowDismissed(mViews.get(index).getWindowToken());
}
}
// 调用 ViewRootImpl 的 die 方法。
boolean deferred = root.die(immediate);
if (view != null) {
view.assignParent(null);
if (deferred) {
mDyingViews.add(view);
}
}
}

查看 ViewRootImpl 的 die 方法。ViewRootImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
boolean die(boolean immediate) {
// die 方法需要立即执行并且此时 ViewRootImpl 不再执行 performTraversals 方法。(mIsInTraversal 在执行 ViewRootImpl 的 performTraversals 方法时会被设置为 true,在 performTraversals 方法执行完时被设置为 false。)
if (immediate && !mIsInTraversal) {
// immediate 为 true(需要立即执行),并且 mIsInTraversal 值为 false。
doDie();
return false;
}

if (!mIsDrawing) {
destroyHardwareRenderer();
} else {
Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
" window=" + this + ", title=" + mWindowAttributes.getTitle());
}
mHandler.sendEmptyMessage(MSG_DIE);
return true;
}
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
void doDie() {
// 检查执行 doDie 方法的线程的正确性。此方法内部会判断执行 doDie 方法线程是否是创建 V 的原始线程,如果不是就会抛出异常,这是因为只有创建 V 的原始线程才能够操作 V。
checkThread();
if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
synchronized (this) {
// 防止 doDie 方法被重复调用。
if (mRemoved) {
return;
}
// 防止 doDie 方法被重复调用。
mRemoved = true;
// 如果 V 有子 View。
if (mAdded) {
// 销毁 View。
dispatchDetachedFromWindow();
}
// 如果 V 有子 View 并且不是第一次被添加,就会执行后面的代码逻辑。
if (mAdded && !mFirst) {
destroyHardwareRenderer();
if (mView != null) {
int viewVisibility = mView.getVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility;
if (mWindowAttributesChanged || viewVisibilityChanged) {
try {
if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
& WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
mWindowSession.finishDrawing(mWindow);
}
} catch (RemoteException e) {
}
}
mSurface.release();
}
}
mAdded = false;
}
// 执行了 WindowManagerGlobal 的 doRemoveView 方法。
WindowManagerGlobal.getInstance().doRemoveView(this);
}

查看 WindowManagerGlobal 的 doRemoveView 方法。WindowManagerGlobal.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void doRemoveView(ViewRootImpl root) {
// 在 WindowManagerGlobal 中维护了和 Window 操作相关的三个列表,doRemoveView 方法会从这三个列表中清除 V 对应的元素。
synchronized (mLock) {
// 找到 V 对应的 ViewRootImpl 在 ViewRootImpl 列表中的索引,接着根据这个索引从 ViewRootImpl 列表、布局参数列表和 View 列表中删除与 V 对应的元素。
final int index = mRoots.indexOf(root);
if (index >= 0) {
mRoots.remove(index);
mParams.remove(index);
final View view = mViews.remove(index);
mDyingViews.remove(view);
}
}
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
doTrimForeground();
}
}

查看 ViewRootImpl 的 doDie 方法中的 dispatchDetachedFromWindow 方法。ViewRootImpl.java

1
2
3
4
5
6
7
8
9
void dispatchDetachedFromWindow() {
...
try {
// 调用了 IWindowSession 的 remove 方法,IWindowSession 在 Server 端的实现为 Session。
mWindowSession.remove(mWindow);
} catch (RemoteException e) {
}
...
}

查看 Session 的 remove 方法。Session.java

1
2
3
public void remove(IWindow window) {
mService.removeWindow(this, window);
}

接着查看 WMS 的 removeWindow 方法。WindowManagerService.java

1
2
3
4
5
6
7
8
9
10
11
void removeWindow(Session session, IWindow client) {
synchronized(mWindowMap) {
// 获取 Window 对应的 WindowState,WindowState 用于保存窗口的信息,在 WMS 中它用来描述一个窗口。
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return;
}
// 调用了 WindowState 的 removeIfPossible 方法。
win.removeIfPossible();
}
}

查看 WindowState 的 removeIfPossible 方法。WindowState.java

1
2
3
4
5
@Override
void removeIfPossible() {
super.removeIfPossible();
removeIfPossible(false /*keepVisibleDeadWindow*/);
}
1
2
3
4
5
6
7
8
9
10
11
private void removeIfPossible(boolean keepVisibleDeadWindow) {
// 条件判断过滤,满足其中一个条件就会 return,推迟删除操作。比如 V 正在运行一个动画,这时就得推迟删除操作,直到动画完成。
...
// 满足这些条件判断过滤后会执行此方法。
removeImmediately();
if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) {
mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
}
mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
Binder.restoreCallingIdentity(origId);
}
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
@Override
void removeImmediately() {
super.removeImmediately();
// mRemoved 为 ture 意味着正在执行删除 Window 操作。
// 防止重复删除操作。
if (mRemoved) {
if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
"WS.removeImmediately: " + this + " Already removed...");
return;
}
// 防止重复删除操作。
mRemoved = true;

...
// 如果当前要删除的 Window 是 StatusBar 或者 NavigationBar 就会将这个 Window 从对应的控制器中删除。
mPolicy.removeWindowLw(this);
disposeInputChannel();
mWinAnimator.destroyDeferredSurfaceLocked();
mWinAnimator.destroySurfaceLocked();
// 将 V 对应的 Session 从 WMS 的 ArraySet<Session> mSession 中删除并清除 Session 对应的 SurfaceSession 资源(SurfaceSession 是 SurfaceFlinger 的一个连接,通过这个连接可以创建 1 个或者多个 Surface 并渲染到屏幕上。)
mSession.windowRemovedLocked();
try {
mClient.asBinder().unlinkToDeath(mDeathRecipient, 0);
} catch (RuntimeException e) {

}
// 调用了 WMS 的 postWindowRemoveCleanupLocked 方法用于对 V 进行一些集中的清理工作。
mService.postWindowRemoveCleanupLocked(this);
}

Window 的删除过程可以简单地总结为以下 4 点:

  • 检查删除线程的正确性,如果不正确就抛出异常。
  • 从 ViewRootImpl 列表、布局参数列表和 View 列表中删除与 V 对应的元素。
  • 判断是否可以直接执行删除操作,如果不能就推迟删除操作。
  • 执行删除操作,清理和释放与 V 相关的一切资源。

备注

注:基于 Android 8.0 版本源码

参考资料:

Android 进阶解密

单词音标: