---
title: 'WindowManagerService'
disqus: kyleAlien
---
WindowManagerService
===
## OverView of Content
[TOC]
## WMS 概述
WMS 全名是 WindowManagerService,它是客戶端 APP 的管理者,處於 SystemServer 進程,WMS 主要負責管理幾件事情
1. **窗口管理**
負責 Window 添加、更新、刪除,核心管理成員有 **`DisplayContent`、`WindowToken`、`WindowState`**
2. **窗口動畫**
Window 切換時,可以添加動畫,讓 Window 切換時更加自然,動畫由 WMS 的動畫子系統負責,該系統是 **`WindowAnimator`**
3. **輸入系統的中轉**
當使用者對視窗觸控 or 輸入時,都會觸發 InputManagerService 會對觸摸事件進行處理,將事件通過 WMS 傳遞到合適的窗口進行處理 (這時 WMS 就是 **中轉站**)
4. **Surface 管理**
WMS 並不具備 Window 繪製的功能,**每個 Window 都有一個 Surface 來繪製**,而 WMS 負責 Surface 的分配
## WMS 啟動 - [SystemServer](https://android.googlesource.com/platform/frameworks/base/+/master/services/java/com/android/server/SystemServer.java)
* WMS 是就是 WindowManagerService,它是系統服務,說到系統服務自然就會想到 SystemServer,那就讓我們來看看 WMS 是如何被 SystemServer 喚起的
1. SystemServer 透過 WMS#main 方法啟動
2. 把 WMS 以 Context#WINDOW_SERVICE (**window**) 設定到 ServiceManager 中
3. 把啟動的 WMS 對象設定給 AMS 服務
```java=
// SystemServer.java
private void run() {
... 省略部分
// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
// @ WMS 是在 OtherServices 啟動
startOtherServices(t);
} catch (Throwable ex) {
... 省略 Log
throw ex;
} /* 省略 finally */
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
t.traceBegin("StartWindowManagerService");
// WMS needs sensor service ready
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
// 1. 啟動 WMS
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
// 2. 對 ServiceManager 添加服務 "window"
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
t.traceEnd();
// 3. 與 AMS 產生關係
t.traceBegin("SetWindowManagerService");
mActivityManagerService.setWindowManager(wm);
t.traceEnd();
} /* 省略 catch */
}
```
* 在 WMS 啟動後會透過 `onInitReady`、`displayReady`、`systemReady` 來完成 WMS 的後續動作 (這些方法之後會介紹)
```java=
// SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
// 初始化準備
wm.onInitReady();
... 省略部分
try {
wm.displayReady();
} catch (Throwable e) {
reportWtf("making display ready", e);
}
wm.systemReady();
} /* 省略 catch */
}
```
### [WMS](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java) - main 函數
* 透過 DisplayThread 中的 Handler#runWithScissors 創建 WMS 對象 (也就是創建 WMS 的線程與 SystemServer 線程不同)
* Handler#**runWithScissors** 方法是透過鎖來達成同步任務,保證該 Runnable 會先被 DisplayThread 的 Looper 先執行,執行完後才回到 SystemServer 的 Thread
> 透過 synchronized、wait 鎖住 SystemServer Thread
>
> 
```java=
// WindowManagerService.java
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
// @ 查看 main 方法
return main(context, im, showBootMsgs, onlyCore, policy, atm,
new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,
SurfaceControl.Builder::new);
}
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, ... 省略部分參數) {
// 創建新 Thread
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
surfaceControlFactory), 0);
// 執行完 runWithScissors 中的 Runnable 任務後才會返回
return sInstance;
}
```
## [HandlerThread](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/HandlerThread.java) - 創建 Looper
這裡特別介紹了 HandlerThread 這個類,^1^ 它繼承於 Thread 並且會在 run 方法中自動 ,**^2^ 建立該 Thread 對象專屬的 Looper 對象,但並 ++不主動創建 Handler 對象++ (在這創建的 Handler 並不安全)**
```java=
// HandlerThread.java
public class HandlerThread extends Thread {
... 省略部分方法
@Override
public void run() {
mTid = Process.myTid();
// 準備該 Thread 專用的 Looper & MessageQueue 對象
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
// 通知所有等待的 Thread, Looper 已經創建完成
notifyAll();
}
Process.setThreadPriority(mPriority);
// Looper 準備好
onLooperPrepared();
// 準備開始運行 Loop 不斷循環處理 Message 任務
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) { // 以當前對象作為鎖
while (isAlive() && mLooper == null) {
try {
wait(); // 直到 Looper 創建
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
// 在需要時才創建 (但線程不安全)
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
}
```
> 
### [DisplayThread](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/DisplayThread.java) - 創建 WMS 對象
:::success
WMS 就是在 DisplayThread 類中被啟動,**DisplayThread 可以說是 WMS 的 MainThread**
:::
* DisplayThread 可以創建安全 Handler,其主要功能是:處理 **低延遲顯示** 的相關操作,並只能由 WindowManager、DisplayManager、InputManager 執行快速操作
* 從上面可以看到 DisplayThread 繼承於 ServiceThread (而它繼承於 HandlerThread),所以 **它會在執行 run 方法時自動創建 Looper 對象**,鑒於 HandlerThread 創建的 Handler 並不安全,所以 DisplayThread 這裡自己創建 Handler (使用類鎖)
```java=
// DisplayThread.java
public final class DisplayThread extends ServiceThread {
private static DisplayThread sInstance;
private static Handler sHandler;
// 單例模式
private DisplayThread() {
// DisplayThread runs important stuff, but these are not as important as things running in
// AnimationThread. Thus, set the priority to one lower.
super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new DisplayThread();
sInstance.start();
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
sHandler = new Handler(sInstance.getLooper());
}
}
public static DisplayThread get() {
// 類鎖
synchronized (DisplayThread.class) {
// 創建 DisplayThread 對象
ensureThreadLocked();
return sInstance;
}
}
// 透過 DisplayThread.class 類鎖來達成安全創建
public static Handler getHandler() {
// 類鎖
synchronized (DisplayThread.class) {
// 創建 DisplayThread 對象
ensureThreadLocked();
return sHandler;
}
}
}
```
:::success
* 在取得 DisplayThread 類時,該類的 Thread 就已經啟動 (透過#ensureThreadLocked 方法啟動 Thread),這時再對該類放置任務就會開始執行
* **Binder Thread 傳遞的訊息可以透過 DisplayThread 傳遞給 WMS**
:::
* 傳遞事件給 WMS 有兩種方式
1. 直接呼叫 WMS function,即時傳送
```java=
// WindowManagerService.java
@Override
public boolean isKeyguardLocked() {
// mPolicy 類型 WindowManagerPolicy
return mPolicy.isKeyguardLocked();
}
```
2. 透過 DisplayThread 的 Looper 將事件丟入 WMS Thread (DisplayThread) 中
```java=
// WindowManagerService.java
final H mH = new H();
final class H extends android.os.Handler {
...
}
@Override
public void setAnimationScale(int which, float scale) {
if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
"setAnimationScale()")) {
throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
}
scale = fixScale(scale);
switch (which) {
case 0: mWindowAnimationScaleSetting = scale; break;
case 1: mTransitionAnimationScaleSetting = scale; break;
case 2: mAnimatorDurationScaleSetting = scale; break;
}
// Persist setting
mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE);
}
```
> 
### [UiThread](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/services/core/java/com/android/server/UiThread.java) 類
* UiThread 與 DisplayThread 差不多,但多添加了一個 `dispose` 方法,來停止 Looper,並結束該對象 (置為 null),在 `initPolicy()`、`systemReady()` 會使用到
```java=
// UiThread.java
public final class UiThread extends ServiceThread {
private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
private static UiThread sInstance;
private static Handler sHandler;
private UiThread() {
super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
}
@Override
public void run() {
// Make sure UiThread is in the fg stune boost group
Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
super.run();
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new UiThread();
sInstance.start();
final Looper looper = sInstance.getLooper();
looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
looper.setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
}
public static UiThread get() {
synchronized (UiThread.class) {
ensureThreadLocked();
return sInstance;
}
}
public static Handler getHandler() {
synchronized (UiThread.class) {
ensureThreadLocked();
return sHandler;
}
}
/**
* Disposes current ui thread if it's initialized. Should only be used in tests to set up a
* new environment.
*/
@VisibleForTesting
public static void dispose() {
synchronized (UiThread.class) {
if (sInstance == null) {
return;
}
// 執行完 runWithScissors 才會往下執行
getHandler().runWithScissors(sInstance::quit, 0 /* timeout */);
sInstance = null;
}
}
}
```
### [AnimationThread](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/AnimationThread.java) 類
* AnimationThread 與 DisplayThread 差不多,但多添加了一個 dispose 方法,來停止 Looper,並結束該對象 (置為 null)
```java=
// AnimationThread.java
public final class AnimationThread extends ServiceThread {
private static AnimationThread sInstance;
private static Handler sHandler;
private AnimationThread() {
super("android.anim", THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new AnimationThread();
sInstance.start();
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
sHandler = new Handler(sInstance.getLooper());
}
}
public static AnimationThread get() {
synchronized (AnimationThread.class) {
ensureThreadLocked();
return sInstance;
}
}
public static Handler getHandler() {
synchronized (AnimationThread.class) {
ensureThreadLocked();
return sHandler;
}
}
// 使用到 HandlerThread#quit 方法,停止 Looper
@VisibleForTesting
public static void dispose() {
synchronized (AnimationThread.class) {
if (sInstance == null) {
return;
}
getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
sInstance = null;
}
}
}
```
## SystemServer - WMS 啟動後續
複習一下:在 SystemService 啟動 WMS 後會隨之調用到 WMS#**`onInitReady` 方法** -> `displayReady` 方法 -> `systemReady` 方法
```java=
// SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
// 初始化準備
wm.onInitReady();
... 省略部分
try {
wm.displayReady();
} catch (Throwable e) {
reportWtf("making display ready", e);
}
wm.systemReady();
} /* 省略 catch */
}
```
### [WMS](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java#1209) 創建
* 前面有提到 WindowManagerService#`main` 方法會透過 DisplayThread (Thread) 創建 WMS 的實例,在這裡就會創建 **H 類**,而它的 **Looper 就是當前 Thread 也就是 DisplayThread**
```java=
// WindowManagerService.java
// 當沒有指定 Looper 就會依現在 Thread 的 Looper
final H mH = new H(); // 也就是 DisplayThread 的 Looper
WindowManagerPolicy mPolicy;
final WindowAnimator mAnimator;
RootWindowContainer mRoot;
final class H extends android.os.Handler {
...
}
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, DisplayWindowSettingsProvider
displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
... 省略部分
// WMS 持有 InputManagerService 引用
mInputManager = inputManager;
...
// 取得 DisplayManagerService 代理
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mPolicy = policy; // ++ SystemServer 傳進來的實例是 PhoneWindowManager 類 ++
// 取得 WMS 代理
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
// Window 動畫
mAnimator = new WindowAnimator(this);
// 所有 Window 的根節點 (RootWindowContainer 對象)
mRoot = new RootWindowContainer(this);
}
```
### [WMS](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java)#onInitReady - 初始化 WindowManagerPolicy
* WMS#**onInitReady** 函數:**取得 UiThread (另外一個 Thread) 的 Handler,並 ==初始化 [WindowManagerPolicy](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java)== (實作呼叫 PhoneWindowManager#init 函數)**
```java=
// WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
WindowManagerPolicy mPolicy; // 實作是 ++ PhoneWindowManager 類 ++
public void onInitReady() {
// @ 重點分析 initPolicy 函數
initPolicy();
... 省略部分
}
private void initPolicy() {
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}
}
// ---------------------------------------------
// WindowManagerPolicy.java
public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
... 省略部分
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs);
// ----------------------------------------------
// PhoneWindowManager.java
public class PhoneWindowManager implements WindowManagerPolicy {
... 省略部分
private class PolicyHandler extends Handler {
... 省略部分
}
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
// 省略部分 ... 後面介紹
mHandler = new PolicyHandler(); // 該 Handler 使用 UiThread's Looper
}
}
```
:::info
* 從這裡可以知道,`WindowManagerPolicy` & `WMS` & `SystemServer` 都在不同 Thread 中運作
:::
### [WMS](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java)#displayReady - 準備顯示
1. 標示 WindowAnimator 初始化完成
2. 重新配置設定,保證 DisplayWindowSettings 設定都有被正常使用
3. 透過 ActivityTaskManager 來更新設置
```java=
// WindowManagerService.java
WindowManagerPolicy mPolicy;
final WindowAnimator mAnimator;
// 在 WMS construct 被初始化
RootWindowContainer mRoot;
public void displayReady() {
synchronized (mGlobalLock) { // ActivityTaskManagerService 中的對象
if (mMaxUiWidth > 0) {
mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
}
applyForcedPropertiesForDefaultDisplay();
// 1. 標示初始化完成
mAnimator.ready();
mDisplayReady = true;
// Reconfigure all displays to make sure that forced properties and
// DisplayWindowSettings are applied.
// 2. 重新配置設定,保證 DisplayWindowSettings 設定都有被正常使用
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
// 硬體是否是可觸控螢幕
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
// 硬體是否是 假的可觸控螢幕
mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_FAKETOUCH);
}
try {
// 3. 透過 ActivityTaskManager 來更新設置
mActivityTaskManager.updateConfiguration(null);
} catch (RemoteException e) {
}
}
```
### [WMS](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java)#systemReady - 服務準備完成
* WMS 服務準備完成
```java=
// WindowManagerService.java
public void systemReady() {
mSystemReady = true;
mPolicy.systemReady();
mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
mHasHdrSupport = queryHdrSupport();
mPrimaryDisplayOrientation = queryPrimaryDisplayOrientation();
mPrimaryDisplayPhysicalAddress =
DisplayAddress.fromPhysicalDisplayId(SurfaceControl.getPrimaryPhysicalDisplayId());
UiThread.getHandler().post(mSettingsObserver::loadSettings);
IVrManager vrManager = IVrManager.Stub.asInterface(
ServiceManager.getService(Context.VR_SERVICE));
if (vrManager != null) {
try {
final boolean vrModeEnabled = vrManager.getVrModeState();
synchronized (mGlobalLock) {
vrManager.registerListener(mVrStateCallbacks);
if (vrModeEnabled) {
mVrModeEnabled = vrModeEnabled;
mVrStateCallbacks.onVrStateChanged(vrModeEnabled);
}
}
} catch (RemoteException e) {
// Ignore, we cannot do anything if we failed to register VR mode listener
}
}
}
```
### WMS 啟動流程圖
> 
## WMS 重點
### WMS IPC - Binder 通訊
* 這裡涉及三個對象 `WMS`、`Activity`、`AMS`,其關係如下圖
1. **`WMS`、`AMS` 其實是在同一個 Process (SystemServer)**
2. **`Session` 是 WMS 中的匿名 Binder,用來處理每個 View 的小需求**
> 下圖紅代表 Binder Server、綠代表 Binder Client
>
> 
### WMS 組織 - ActivityRecord、WindowState
* App 開啟一個 Activity
1. Activity 在 **AMS 對應的對象是 ActivityRecord**,**^\*^ ActivityRecord 在 WMS 中對應的是 AppWindowToken**
> * WMS 也需要控制 AMS 中的 ActivityRecord
2. Activity 在 **WMS 對應的對象是 WindowState**
> 
### 窗口屬性 - Layer Type
* Android 支援多種窗口,並且會將窗口分為三類,定義在 [**WindowManager#LayoutParams**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/WindowManager.java) 中
1. **Application Window**:普通 App 應用就是使用以下窗口類型 (列出幾種舉例),區間為 **1 ~ 99** 之間
| Value | 名稱 | 說明 |
| -------- | -------- | -------- |
| 1 | `FIRST_APPLICATION_WINDOW` | 應用類視窗的起始值 |
| 1 | `TYPE_BASE_APPLICATION` | 其他應用都可覆蓋在該 Window 之上 |
| 2 | `TYPE_APPLICATION` | 一般的應用窗口 |
| 3 | `TYPE_APPLICATION_STARTING` | 應用程式啟動前的畫面 (用在加載某個畫面之前的預前畫面) |
| 4 | `TYPE_DRAWN_APPLICATION` | 在繪畫完成前等待 |
| 99 | `LAST_APPLICATION_WINDOW` | 應用視窗的結束值 |
```java=
// WindowManager#LayoutParams
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int TYPE_BASE_APPLICATION = 1;
public static final int TYPE_APPLICATION = 2;
public static final int TYPE_APPLICATION_STARTING = 3;
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99;
...
}
```
2. **Sub Window**:附加在應用之上的視窗,一般稱為 **子窗口**,其值區間為 **1000 ~ 1999** 之間
| Value | 名稱 | 說明 |
| -------- | -------- | -------- |
| 1000 | `FIRST_SUB_WINDOW` | SubWindow 的起始值 |
| 1000 | `TYPE_APPLICATION_PANEL` | 該 SubWindow 顯示在依附的 App 之上 |
| 1001 | `TYPE_APPLICATION_MEDIA` | 顯示有關 video 的 SubWindow |
| 1002 | `TYPE_APPLICATION_SUB_PANEL` | 顯示在依附的 app 之上,**也在其他 SubWinow 之上** |
| 1003 | `TYPE_APPLICATION_ATTACHED_DIALOG` | Dialog 類型的 Window |
| 1004 | `TYPE_APPLICATION_MEDIA_OVERLAY` | 顯示在 `TYPE_APPLICATION_MEDIA ` 還有底下的應用視窗之間 |
| 1005 | `TYPE_APPLICATION_ABOVE_SUB_PANEL` | 比 `TYPE_APPLICATION_SUB_PANEL` 更上層的 Window |
| 1999 | `LAST_SUB_WINDOW` | SubWindow 的結束值 |
```java=
// WindowManager#LayoutParams
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
public static final int FIRST_SUB_WINDOW = 1000;
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;
public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
...
public static final int LAST_SUB_WINDOW = 1999;
}
```
3. **System Window**:系統使用的 Window 視窗 (以下列出幾種),區間為 **2000 ~ 2999** 之間
| Value | 名稱 | 說明 |
| -------- | -------- | -------- |
| 2000 | `FIRST_SYSTEM_WINDOW` | System Window 的起始值 |
| 2001 | `TYPE_STATUS_BAR` | Status bar 的 Window |
| 2002 | `TYPE_SEARCH_BAR` | 搜尋 Bar 的 Window |
| 2038 | `TYPE_APPLICATION_OVERLAY` | 覆蓋於其他 Activity 視窗 |
| 2999 | `LAST_SYSTEM_WINDOW` | System Window 的結束值 |
```java=
// WindowManager#LayoutParams
public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
public static final int FIRST_SYSTEM_WINDOW = 2000;
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;
...
public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;
...
public static final int LAST_SYSTEM_WINDOW = 2999;
}
```
:::warning
* 透過該值來決定 Window 應該要放置的層級 (Layer),但 **如果一個視窗中有多個相同層級的應用又該如何決定呢** ?
> 看下一小節
:::
### [WindowState](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/wm/WindowState.java) 初始化 - 決定 Base Layer
* 從 WindState 建構函數可以知道,Base Layer 數值可以從 WindowManagerPolicy#`getWindowLayerLw` 方法取得
:::info
* 這邊也可以看到
1. Stub Window 的 Base Layer 取決於 Parent Window
2. BaseLayer 決定出來後要加上 10000 & 篇移值 1000
3. mSubLayer 決定子窗口應該要在父窗口的偏移植
:::
```java=
// WindowManagerPolicyConstants.java
// 保留給多 Window (相同 Layer)
int TYPE_LAYER_MULTIPLIER = 10000;
// 保留給多 Window (相同 Layer),Z 軸偏移量
int TYPE_LAYER_OFFSET = 1000
// ---------------------------------------------------------------
// WindowState.java
final WindowManagerPolicy mPolicy;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, WindowManager.LayoutParams a,
... 省略部分入參) {
// 複製 `WindowManager.LayoutParams`
mAttrs.copyFrom(a);
...
mPolicy = mWmService.mPolicy;
...
// 判斷目前 Window 是否是 SubWindow
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// 保留空間給多個相同 Layer 等級的 Window
// @ 查看 getWindowLayerLw 方法
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow) // 1.
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; // 2.
// SubWindow
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
...
} else {
// @ 查看 getWindowLayerLw 方法
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
...
}
}
```
1. [**WindowManagerPolicy**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java) 透過傳入的 `WindowState` 決定 Window 基礎 Layer 層級 (數值越高,越接近使用者 & 上層)
```java=
// WindowManagerPolicy.java
default int getWindowLayerLw(WindowState win) {
return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
}
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
return getWindowLayerFromTypeLw(type, canAddInternalSystemWindow,
false /* roundedCornerOverlay */);
}
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
boolean roundedCornerOverlay) {
// Always put the rounded corner layer to the top most.
if (roundedCornerOverlay && canAddInternalSystemWindow) {
return getMaxWindowLayer();
}
// 1 ~ 99 之間
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
return APPLICATION_LAYER; // APPLICATION_LAYER 是 2
}
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:
case TYPE_DOCK_DIVIDER:
case TYPE_QS_DIALOG:
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
return 4;
case TYPE_INPUT_CONSUMER:
return 5;
case TYPE_SYSTEM_DIALOG:
return 6;
case TYPE_TOAST:
// toasts and the plugged-in battery thing
return 7;
case TYPE_PRIORITY_PHONE:
// SIM errors and unlock. Not sure if this really should be in a high layer.
return 8;
case TYPE_SYSTEM_ALERT:
// like the ANR / app crashed dialogs
// Type is deprecated for non-system apps. For system apps, this type should be
// in a higher layer than TYPE_APPLICATION_OVERLAY.
return canAddInternalSystemWindow ? 12 : 9;
case TYPE_APPLICATION_OVERLAY:
return 11;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
return 13;
case TYPE_INPUT_METHOD_DIALOG:
// on-screen keyboards and other such input method user interfaces go here.
return 14;
case TYPE_STATUS_BAR:
return 15;
... 省略部分 case
default:
Slog.e("WindowManager", "Unknown window type: " + type);
return 3;
}
}
```
3. [**WindowManagerPolicy**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/policy/WindowManagerPolicy.java)#`getSubWindowLayerFromTypeLw` 方法:決定子窗口在父窗口中的偏移量
:::info
從這裡可以看出來子窗口可能在 父窗口的上面、也能在下面
:::
```java=
// WindowManagerPolicy.java
default int getSubWindowLayerFromTypeLw(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
}
Slog.e("WindowManager", "Unknown sub-window type: " + type);
return 0;
}
```
### 窗口屬性 - 決定最終 Layer 層級
* 詳細的 Window 視窗層級會在 WMS 中決定,**窗口數值越高,越接近 User** (有可能視窗中有 3 個 Window Type 是 TYPE_APPLICATION)
```java=
// WindowManagerService.java
public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
... 省略部分入參) {
...
int result = 0;
boolean configChanged;
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
// WindowState 是 Activity 在 WMS 的代表
final WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return 0;
}
final DisplayContent displayContent = win.getDisplayContent();
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
...
if (imMayMove) {
displayContent.computeImeTarget(true /* updateImeTarget */);
if (toBeDisplayed) {
// 重新計算 Layer 層級
// @ 追蹤 assignWindowLayers 方法
displayContent.assignWindowLayers(false /* setLayoutNeeded */);
}
}
return result;
}
```
[**DisplayContent**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java)#**assignWindowLayers** 方法:準備重新計算該 Window 真正的 Layer 層級
```java=
// DisplayContent.java
void assignWindowLayers(boolean setLayoutNeeded) {
...
// @ 追蹤 assignChildLayers 方法
assignChildLayers(getSyncTransaction());
if (setLayoutNeeded) {
setLayoutNeeded();
}
...
}
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
assignRelativeLayerForIme(t, false /* forceUpdate */);
// @ 追中 super.assignChildLayers
super.assignChildLayers(t);
}
```
最終會呼叫到 [**WindowState**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/wm/WindowState.java)#assignChildLayers 方法:WindowState 繼承於 [**WindowContainer**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java) 而其中會儲存該視窗的所有 Window,所以 `assignChildLayers` 行為會迭代所有的 Window 並重新賦予 layer 數值
```java=
// WindowContainer.java
// 以 Z 軸儲存所有 Window
protected final WindowList<E> mChildren = new WindowList<E>();
// -----------------------------------------------------------------
// WindowState.java
public void assignChildLayers(Transaction t) {
// Main Window 已經計算並保存好,而呼叫該 Function,代表該 View 應該要在 Main Window 之上
// `PRESERVED_SURFACE_LAYER ` 為 1
int layer = PRESERVED_SURFACE_LAYER + 1;
// 迭代所有 Window 視窗
for (int i = 0; i < mChildren.size(); i++) {
final WindowState w = mChildren.get(i);
// `APPLICATION_MEDIA_OVERLAY` 比起 `APPLICATION_MEDIA` 還上層
if (w.mAttrs.type == TYPE_APPLICATION_MEDIA) {
...
} else if (w.mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
...
} else {
// @ 追蹤 WindowState#assignLayer
w.assignLayer(t, layer);
}
// 遞迴呼叫 assignChildLayers 方法
w.assignChildLayers(t);
// layer 層級 + 1
layer++;
}
}
```
UML 關係如下
> 
Struct 結構如下
> 
* WindowContainer 就會直接透過 SurfaceControler 設定 Layer 層級
```java=
// WindowState.java
@Override
void assignLayer(Transaction t, int layer) {
if (mStartingData != null) {
// The starting window should cover the task.
t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
return;
}
// See comment in assignRelativeLayerForImeTargetChild
if (needsRelativeLayeringToIme()) {
getDisplayContent().assignRelativeLayerForImeTargetChild(t, this);
return;
}
// @ 追蹤 super.assignLayer
super.assignLayer(t, layer);
}
// ---------------------------------------------------------
// WindowContainer.java
void assignLayer(Transaction t, int layer) {
// 正在顯示則不調整
if (mTransitionController.isPlaying()) return;
final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
if (mSurfaceControl != null && changed) {
// @ 查看 setLayer
setLayer(t, layer);
mLastLayer = layer;
mLastRelativeToLayer = null;
}
}
protected void setLayer(Transaction t, int layer) {
if (mSurfaceFreezer.hasLeash()) {
// When the freezer has created animation leash parent for the window, set the layer
// there instead.
mSurfaceFreezer.setLayer(t, layer);
} else {
// Route through surface animator to accommodate that our surface control might be
// attached to the leash, and leash is attached to parent container.
mSurfaceAnimator.setLayer(t, layer);
}
}
// ---------------------------------------------------------
// SurfaceFreezer.java
void setLayer(SurfaceControl.Transaction t, int layer) {
if (mLeash != null) {
// 最終設定 Layer
t.setLayer(mLeash, layer);
}
}
```
> 
### 窗口屬性 - LayoutParams
* Window 的統一屬性設定在 [**WindowManager#LayoutParams**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/WindowManager.java) 中,並且有分為 `type`、`Flags` 兩種設定
1. **Type**:上面已經說過,主要有分為 `Application Window`、`Sub Window`、`System Window` 三種
2. **Flag**:莫認為 0,以下列出幾個 (有滿多的)
| Value | Flag | 說明 |
| - | -------- | -------- |
| 0x00000001 | `FLAG_ALLOW_LOCK_WHILE_SCREEN_ON` | 只要該窗口可見,就允許鎖住屏幕 (可配合 `FLAG_KEEP_SCREEN_ON` 使用) |
| 0x00000002 | `FLAG_DIM_BEHIND` | 窗口後的 Window 都變淡 |
| 0x00000004 | `FLAG_BLUR_BEHIND` | 窗口後的 Window 變模糊 |
| 0x00000008 | `FLAG_NOT_FOCUSABLE` | 該 Window 視窗不可事件,事件會直接傳遞給後方 Window |
| 0x00000010 | `FLAG_NOT_TOUCHABLE` | 該窗口不接受任何事件 |
| 0x00000080 | `FLAG_KEEP_SCREEN_ON` | 只要該窗口可見,就保持螢幕亮起 |
使用 Window#setFlags 就可以設置
```java=
Window w = activity.getWindow();
w.setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
```
* System UI 控制:System UI 的設定定義在 [**View**](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/View.java) 中,針對每個 View 個別設置
| Value | Flag | 說明 |
| - | -------- | -------- |
| 0 | `SYSTEM_UI_FLAG_VISIBLE` | 設定 System UI 可見 |
| 0x00000002 | `SYSTEM_UI_FLAG_HIDE_NAVIGATION` | 設定 Navigtion Bar 不可見 |
| 0x00000004 | `SYSTEM_UI_FLAG_FULLSCREEN` | 螢幕全屏 |
| 0x00000100 | `SYSTEM_UI_FLAG_LAYOUT_STABLE` | 盡量保持 UI 布局的穩定性 |
| 0x00000400 | `SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN` | 從螢幕 (0, 0) 開始繪製,也就是會從 Status Bar 開始繪製 |
## Activity 啟動
這裡用一張簡易的流程圖來回憶一下 Acitivty 的啟動流程 (僅列出重點),並從 ActivityRecord#**showStartingWindow** 繼續往下分析就可以看到 AMS 與 WMS 之間的關係

### [ActivityRecord](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/ActivityRecord.java) - showStartingWindow 啟動動畫 AnimationThread 使用
* 先來看一下 ActivityRecord 類的繼承關係,可以看到 **ActivityRecord 也是 WindowContainer 的子類** (WindowContainer 是泛型,可以包含多個 WindowContainer)
```java=
// WindowContainer.java
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable {
// 以 z 軸來儲存 Window 元素
protected final WindowList<E> mChildren = new WindowList<E>();
...
}
```
* 接這來看 Window 相關類的關係圖
> 
* 在回到 Activity 啟動的過程中會使用中到 ActivityRecord#**showStartingWindow** 方法顯示 Window 啟動畫面
| Window 類型 | 說明 |
| ---------------------------------- | ------------------------------------------------------------ |
| `STARTING_WINDOW_TYPE_NONE` | 不添加 Starting Window |
| `STARTING_WINDOW_TYPE_SNAPSHOT` | 當 APP 啟動後並切換到後台,Android 會替 APP 快照(類似截圖),當 APP 再次回到前景 (使用) 就會使用這個 |
| `STARTING_WINDOW_TYPE_SPLASH_SCREEN` | 默認行為,與 APP 主題有關 |
```java=
// ActivityRecord.java
// 啟動視窗
StartingData mStartingData;
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
boolean startActivity, ActivityRecord sourceRecord) {
... 省略部分
// @ 分析 addStartingWindow 函數
final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev, newTask || newSingleActivity, taskSwitch, isProcessRunning(),
allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty);
... debug 訊息
}
boolean addStartingWindow(/* 省略參數 */) {
... 省略部分
// 若已經找 (啟動視窗) 到則不再尋找
if (mStartingData != null) {
return false;
}
// 從 WindowContainer 中找到啟動視窗
// @ 查看 findMainWindow 類
final WindowState mainWin = findMainWindow();
if (mainWin != null && mainWin.mWinAnimator.getShown()) {
// App already has a visible window...why would you want a starting window?
return false;
}
// @ 查看 getStartingWindowType 方法
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, snapshot);
... 省略部分
// SplashScreenStartingData 實作 StartingData 抽象類
mStartingData = new SplashScreenStartingData(mWmService, pkg,
resolvedTheme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
getMergedOverrideConfiguration(), typeParameter);
// @ 繼續分析 scheduleAddStartingWindow 方法
scheduleAddStartingWindow();
return true;
}
// 透過 ActivityRecord 決定啟動 Window 類型
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated,
TaskSnapshot snapshot) {
// 對照上面的表
if ((newTask || !processRunning || (taskSwitch && !activityCreated))
&& !isActivityTypeHome()) {
// 第一次啟動...
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else if (taskSwitch && allowTaskSnapshot) {
if (isSnapshotCompatible(snapshot)) {
return STARTING_WINDOW_TYPE_SNAPSHOT;
}
if (!isActivityTypeHome()) {
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
}
return STARTING_WINDOW_TYPE_NONE;
} else {
return STARTING_WINDOW_TYPE_NONE;
}
}
WindowState findMainWindow(boolean includeStartingApp) {
WindowState candidate = null;
for (int j = mChildren.size() - 1; j >= 0; --j) {
final WindowState win = mChildren.get(j);
final int type = win.mAttrs.type;
// No need to loop through child window as base application and starting types can't be
// child windows.
if (type == TYPE_BASE_APPLICATION
|| (includeStartingApp && type == TYPE_APPLICATION_STARTING)) {
if (win.mAnimatingExit) {
candidate = win;
} else {
return win;
}
}
}
return candidate;
}
void scheduleAddStartingWindow() {
if (StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) {
// Debug 用
mAddStartingWindow.run();
} else {
// 注意:我們真的想做 sendMessageAtFrontOfQueue()
// 因為我們想在任何其他排隊的消息之前盡快處理消息。
if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Enqueueing ADD_STARTING");
// mWmService 就是 WindowManagerService,而 mAnimationHandler 就是 Handler
// @ mAnimationHandler 準備分析
mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}
}
}
```
* 在這裡可以看到 ActivityRecord 會將自己的 Runnable 透過 WMS#mAnimationHandler (就是 Handler) 推到 **AnimationThread 的線程**
> `mAddStartingWindow` 下個小節說明
```java=
// WindowManagerService.java
final Handler mAnimationHandler = new Handler(
AnimationThread.getHandler().getLooper()
);
```
> 
### [ActivityRecord](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/ActivityRecord.java) - AddStartingWindow 添加啟動視窗
* 先來查看一下 ActivityRecord 推送到 WMS#**mAnimationHandler** 的 Runnable 任務
```java=
// ActivityRecord.java
private final AddStartingWindow mAddStartingWindow = new AddStartingWindow();
// 複習一下~
void scheduleAddStartingWindow() {
if (StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) {
... 省略
} else {
// 注意:我們真的想做 sendMessageAtFrontOfQueue()
// 因為我們想在任何其他排隊的消息之前盡快處理消息。
if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
... Log 訊息
mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
}
}
}
// @ 分析 AddStartingWindow 類
private class AddStartingWindow implements Runnable {
// run 會被 WMS#AnimationHandler 線程呼叫
@Override
public void run() {
// Can be accessed without holding the global lock
final StartingData startingData;
synchronized (mWmService.mGlobalLock) {
// There can only be one adding request, silly caller!
if (!StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER) {
// Debug 用
mWmService.mAnimationHandler.removeCallbacks(this);
}
if (mStartingData == null) {
// 動畫被取消
... 省略 Log 訊息
return;
}
startingData = mStartingData;
}
... 省略 Log 訊息
WindowManagerPolicy.StartingSurface surface = null;
try {
// createStartingSurface 是抽象方法,具體邏輯由子類完成
// 目前來說就是使用 ++SplashScreenStartingData 類++
surface = startingData.createStartingSurface(ActivityRecord.this);
} catch (Exception e) {
Slog.w(TAG, "Exception when adding starting window", e);
}
if (surface != null) {
boolean abort = false;
synchronized (mWmService.mGlobalLock) {
// If the window was successfully added, then we need to remove it.
if (mStartingData == null) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Aborted starting %s: startingData=%s",
ActivityRecord.this, mStartingData);
mStartingWindow = null;
mStartingData = null;
abort = true;
} else {
mStartingSurface = surface;
}
if (!abort) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Added starting %s: startingWindow=%s startingView=%s",
ActivityRecord.this, mStartingWindow, mStartingSurface);
}
}
if (abort) {
surface.remove(false /* prepareAnimation */);
}
} else {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
ActivityRecord.this);
}
}
}
```
* StartingData 是抽象類,而在目前的狀況,實作者是 [**SplashScreenStartingData 類**](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/SplashScreenStartingData.java) (addStartingWindow 內創建的對象就是 SplashScreenStartingData)
```java=
// SplashScreenStartingData.java
class SplashScreenStartingData extends StartingData {
... 省略部分
SplashScreenStartingData(WindowManagerService service, String pkg, int theme,
CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
int logo, int windowFlags, Configuration mergedOverrideConfiguration, int typeParams) {
super(service, typeParams);
... 省略部分
}
@Override
StartingSurface createStartingSurface(ActivityRecord activity) {
// 1. mService 就是 WindowManagerService
// 2. mStartingSurfaceController 就是 StartingSurfaceController
return mService.mStartingSurfaceController.createSplashScreenStartingSurface(
activity, mPkg, mTheme, mCompatInfo, mNonLocalizedLabel, mLabelRes, mIcon,
mLogo, mWindowFlags, mMergedOverrideConfiguration,
activity.getDisplayContent().getDisplayId());
}
@Override
boolean needRevealAnimation() {
return true;
}
}
```
* 呼叫 [**StartingSurfaceController**](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/StartingSurfaceController.java) 類的 `createSplashScreenStartingSurface` 方法,這個方法會呼叫到 WMS 中的 mPolicy (**也就是 [PhoneWindowManager 類](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/policy/PhoneWindowManager.java)**)
```java=
// StartingSurfaceController.java
StartingSurface createSplashScreenStartingSurface(ActivityRecord activity, String packageName,
int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) {
if (!DEBUG_ENABLE_SHELL_DRAWER) {
// WMS 中的 mPolicy 實作類是 PhoneWindowManager
return mService.mPolicy.addSplashScreen(activity.token, activity.mUserId, packageName,
theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
overrideConfig, displayId);
}
synchronized (mService.mGlobalLock) {
final Task task = activity.getTask();
if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(
task, activity, theme, null /* taskSnapshot */)) {
return new ShellStartingSurface(task);
}
}
return null;
}
```
> 
### ViewRootImpl - 繪製 View
* 回顧一下:我們目前是在添加 Activity 啟動 Window 的路上,前面幾個步驟介紹了 AMS 對 WMS 添加 Activity 的啟動畫面 **showStartingWindow** ~
* 透過 [**PhoneWindowManager**](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/policy/PhoneWindowManager.java)#`addSplashScreen` 會創建 PhoneWindow 對象,並設定 Window 的 WindowManager#LayoutParams 屬性,之後在取得 WindowManager 後呼叫 addView
1. 創建 PhoneWindow 對象 (Window 的實作類)
2. 設定 Window 對象的 WindowManager#LayoutParams (預設 type 類型是 Application)
3. **將 Activity#appToken ==也就是 App 的 ApplicationThread==** 賦予給 WMS,方便之後調用
4. 透過 context#getSystemService 取得 WMS 的代理類,並呼叫 WMS#addView 方法 (其實是透過 Session 通知 WMS 添加 Window)
```java=
// PhoneWindowManager.java
@Override
public StartingSurface addSplashScreen(IBinder appToken, int userId, String packageName,
int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) {
... 省略部分
WindowManager wm = null;
View view = null;
try {
... 省略部分
// 484 很孰悉 ~ ? 在分析 xml 創建 View 的時候也會看到它
final PhoneWindow win = new PhoneWindow(context); // 創建 PhoneWindow
... 省略部分
// 設定 Window 用的 LayoutParams
win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
final WindowManager.LayoutParams params = win.getAttributes(); // 設定 LayoutParams
// appToken 是 App 的 ApplicationThread
params.token = appToken;
... 省略部分
addSplashscreenContent(win, context);
// 取得 WindowManager
wm = (WindowManager) context.getSystemService(WINDOW_SERVICE);
// 取得 Decor View (沒有的話就創建)
view = win.getDecorView();
... 省略 Log
wm.addView(view, params); // 呼叫 WMS#addView !!
return view.getParent() != null ? new SplashScreenSurface(view, appToken) : null;
} /* catch、finally */
return null;
}
```
* 而 WindowManager 是 interface,它的實作類是 [**WindowManagerImpl**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/WindowManagerImpl.java),在其中有一個 WindowManagerGlobal 對象
> WindowManagerGlobal 是一個進程單例對象,WindowManagerGlobal 就是一個 **橋接模式設計**,也是透過它來與 WMS 通訊
```java=
// WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyTokens(params);
// @ 查看 addView 方法
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
}
```
> 
* 最後呼叫到 [**WindowManagerGlobal**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/WindowManagerGlobal.java)#addView 方法,WindowManagerGlobal 類會管理該 ++進程中所有的 ViewRootImpl & Window & LayoutParams++
```java=
// WindowManagerGlobal.java
private final Object mLock = new Object();
// 進程中所有的 View
private final ArrayList<View> mViews = new ArrayList<View>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
// 基礎判空
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (display == null) {
throw new IllegalArgumentException("display must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
// 父 Window 判斷
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);
} else {
// If there's no parent, then hardware acceleration for this view is
// set from the application's hardware acceleration setting.
final Context context = view.getContext();
if (context != null
&& (context.getApplicationInfo().flags
& ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
}
ViewRootImpl root;
View panelParentView = null;
// 添加 View 的流程使用 鎖
synchronized (mLock) {
... 省略部分
// 創建 ViewRootImpl 對象
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
// 準備繪製
root.setView(view, wparams, panelParentView, userId);
} /* 省略 catch */
}
}
```
> 
* 步驟到 [**ViewRootImpl**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewRootImpl.java) 後有兩個重點
1. 透過 ViewRootImpl#mWindow (內部類 W) 與 WMS 通訊 WindowSession 也是一個系統服務
成員 mWindow 在 ViewRootImpl 創建時被賦予,並且 mWindow 是 ViewRootImpl 的內部類,它繼承 IWindow.Stub (作為 Binder 的 Server 端)
> **W 它是 WMS 調用客戶端的接口** (之後當 Window 產生變化時會通知IWindow.Stub)
```java=
// ViewRootImpl.java
final W mWindow;
public ViewRootImpl(@UiContext Context context, Display display, IWindowSession session,
boolean useSfChoreographer) {
... 省略
mWindow = new W(this);
}
static class W extends IWindow.Stub {
W(ViewRootImpl viewAncestor) {
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
}
... 省略
}
```
2. 與 WMS 通訊成功後,就會進入 View 的繪製流程 (執行 onMeasure、onLayout、onDraw)
```java=
// ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
setView(view, attrs, panelParentView, UserHandle.myUserId());
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
... 省略部分
requestLayout();
... 省略部分
}
}
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
// 分析
scheduleTraversals();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 將 mTraversalRunnable 任務添加到 Handler 中
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
... 省略部分
performTraversals();
... 省略部分
}
}
// 該函數很長,只會列出幾個我們常見的要點 (其中包含了本地的繪製,WMS 通訊...)
private void performTraversals() {
... 省略部分
try {
... 省略部分
// 參數放入 mWindow,之後讓 WMS 作回調 ~ !!!
// WindowSession 也是一個系統服務
// @ 分析 addToDisplayAsUser
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
... 省略部分
} /* 省略 catch、finally */
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
... 省略部分
if (!mStopped || wasReportNextDraw) {
// 會執行 onMeasure
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
... 省略部分
}
}
... 省略部分
if (didLayout) {
// 會執行 onLayout
performLayout(lp, mWidth, mHeight);
}
... 省略部分
if (!cancelDraw) {
performDraw();
}
... 省略部分
}
```
:::info
* WindowSession 也是一個系統服務
不過它是一個匿名服務,必須透過 WMS 才可以取得 WindowSession 對象
:::
> 
### 透過 WMS 取得 [Session](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/Session.java) - addToDisplayAsUser
* 先來看一下 ViewRootImpl 的 Session 是如何取得
> 透過 WindowManagerGlobal 取得 Session
```java=
// ViewRootImpl.java
public ViewRootImpl(Context context, Display display) {
// 透過 WindowManagerGlobal 取得 Session (Session 的代理類)
// @ 追 getWindowSession 方法
mWindowSession = WindowManagerGlobal.getWindowSession();
... 省略部分
}
// 複習一下上面的調用 performTraversals 方法的重點
private void performTraversals() {
... 省略部分
try {
... 省略部分
// 透過 mWindow 與 WMS 通訊
// WindowSession 也是一個系統服務
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
mTempControls);
... 省略部分
} /* 省略 catch、finally */
... 省略部分
}
```
* 從上面看到 Session 的取得是透過 WindowManagerGlobal 類:而 WindowManagerGlobal 則是透過 ^1.^ ServiceManager 取得 WMS,^2.^ 再透過創建 Session 給客戶端
```java=
// WindowManagerGlobal.java
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
// 追 getWindowManagerService 方法
IWindowManager windowManager = getWindowManagerService();
// 使用 WMS 間接取得 Session 服務,查看 openSession 方法
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;
}
}
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
// 1. 透過 ServiceManager 取得
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
if (sWindowManagerService != null) {
ValueAnimator.setDurationScale(
sWindowManagerService.getCurrentAnimatorScale());
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
```
* 在這邊就可以看到,**Session 是一個 ++匿名服務++**,它不能透過 ServiceManger 直接取得,**==Session 必須透過 WMS 取得該服務==,每個 ViewRootImpl 對應一個 Session 服務**
> 同時一個 View 也對應了一個 ViewRootImpl,也就是說一個 Session 對應一個 View
```java=
// WindowManagerService.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
// 每個 ViewRootImpl 對應一個 Session 服務
return new Session(this, callback);
}
```
> 
* 最後透過 Session#addToDisplayAsUser 來訪問 WMS#addWindow 方法
```java=
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
final WindowManagerService mService;
@Override
public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, InsetsVisibilities requestedVisibilities,
InputChannel outInputChannel, InsetsState outInsetsState,
InsetsSourceControl[] outActiveControls) {
// @ 呼叫到 WindowManagerService#addWindow 方法
// window -> ViewRootImpl 中的 W 類
return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId,
requestedVisibilities, outInputChannel, outInsetsState, outActiveControls);
}
}
```
> 
## [WindowManagerService](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java)
WindowManagerService 簡單理解起來是掌管該裝置所有的 Window 的上下關係 (z 軸的管理)、傳輸繪製任務到底層
> 先介紹 [**WindowManagerService**](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java) 幾個比較重要的成員變量
| 變量 | 說明 | 補充 |
| - | - | - |
| mPolicy : WindowManagerPolicy | 定義一個窗口策略所須遵循的 **++通用規範++**,並提供了 WindowManger 特定的 UI 行為 | WindowManager 是 interface,它的實作是 **PhoneWindowManager** |
| mSessions : ArraySet<Session\> | 它主要用於進程通訊,**其他的應用進程的 View 想要和 WMS 通訊,都要通過 Session 與 WMS 通訊** | 每個應用進程是透過 **WindowManagerGlobal 取得 Session** |
| **mWindowMap** : WindowHashMap | WindowHashMap 繼承 HashMap,**用來保存所有 ViewImpl**;Key: IBinder、Value: WindowState | Key 其實是 IWindow (ViewRootImpl 的內部類 W)、Value 是保存窗口訊息 |
| mFinishedStarting : ArrayList<AppWindowToken\> | AppWindowToken 的父類是 WindowToken 當 APP 要向 WMS 申請一個新窗口時就要給予這個 token 讓 WMS 驗證 | **每個 Activity 對應一個 AppWindowToken (一個 AppWindowToken 管理多個 WindowToken 視窗)** |
| mResizingWindows : ArrayList<WindowState\> | 用來儲存正在調整大小的視窗 | |
| mAnimator : WindowAnimator | 管理 Window 動畫 & 特效 | |
| mH : H | H 是 Handler 類型,它是屬於 **==DisplayThread== Looper** | 將消息給 WMS |
| mInputManager : InputManagerService | IMS 系統服務,當使用者有輸入訊息時,WMS 會給予一個適合的視窗 | |
> 
### [WMS](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/WindowManagerService.java) - addWindow 方法
* 上面有提及,APP 在添加視窗時會透過 WindowManagerGlobal#Session,而系統 Session 又會呼叫 WMS#**addWindow** 方法,由於該方法較長,以下分為 3 個階段來看
1. 檢查、取得 **DisplayContent**、判斷是否是子視窗
1. 檢查啟動權限:是否是系統窗口 & 使用者設定的權限... 等等
2. 取得 DisplayContent (該 WindowState 應該放置的視窗),判斷是否重複添加
3. 判斷是否是子視窗 (`FIRST_SUB_WINDOW` <= type <= `LAST_SUB_WINDOW`)
4. 從 mWindowMap 嘗試取得父窗口,如果目前視窗是子窗口,但 ParentWindow 取出的也是子窗口,就會返回錯誤 (ADD_BAD_SUBWINDOW_TOKEN)
5. 判斷 WindowManager 的各種 Type 類型,做相應的檢查處理
```java=
// WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, /*省略部分參數*/ ) {
... 省略部分
// 1. 檢查啟動權限:是否是系統窗口 & 使用者設定的權限... 等等 (傳入 type... 判斷)
int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
appOp);
if (res != ADD_OKAY) {
return res;
}
WindowState parentWindow = null;
... 省略部分
synchronized (mGlobalLock) {
if (!mDisplayReady) {
throw new IllegalStateException("Display has not been initialialized");
}
// 2. 取得 DisplayContent (該 WindowState 應該放置的視窗)
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
if (displayContent == null) {
ProtoLog.w(WM_ERROR, "Attempted to add window to a display that does "
+ "not exist: %d. Aborting.", displayId);
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
... 省略部分
// 3. 判斷窗口類型:當前是判斷是否是子視窗
if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
// 4. 如果是子窗口,嘗試取得父窗口 (attrs 是 LayoutParams)
parentWindow = windowForClientLocked(null, attrs.token, false);
// 判斷是否有 ParentWindow
if (parentWindow == null) {
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
// 並且 Parent 視窗不可以是子視窗
if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
}
}
... 省略部分
}
}
```
> 
2. **取得 Activity 的 AppWindowToken**
1. 若有 Parent 窗口,那它會與子窗口有相同的 Token (IBinder),也就是說 ParentWindow & SubWindow 有相同的 Token
2. 設定窗口類型 (如果有 ParentWindow,則使用 ParentWindow 的 type)
3. 依照狀況 **取得 WindowToken**,細節請看註解,這裡有多個 token 相關關鍵字容易混淆,我們以下表區分
| Token | 說明 | 補充 |
| -------- | -------- | - |
| `token` | 宣告為 WindowToken 類型 | |
| `attrs.token` | 類型為 IBinder,代表該窗口的主人 | 如果有 Parent Window 窗口主人就轉為 Parent |
| | | |
| | | |
> 
```java=
// WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, /*省略部分參數*/ ) {
... 省略部分
synchronized (mGlobalLock) {
ActivityRecord activity = null;
final boolean hasParent = parentWindow != null;
// 1. 若有 Parent 窗口,那它會與子窗口有相同的 Token
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
// 2. 設定窗口類型 (如果有父窗口,則使用父窗口的 type)
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
boolean addToastWindowRequiresToken = false;
final IBinder windowContextToken = attrs.mWindowContextToken;
// 若是沒有 token 會依照情況做創建
if (token == null) {
if (!unprivilegedAppCanCreateTokenWith(parentWindow, callingUid, type,
rootType, attrs.token, attrs.packageName)) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
// 如果有 Parent 就優先使用 Parent 的 token
if (hasParent) {
// Use existing parent window token for child windows.
token = parentWindow.mToken;
} else if (mWindowContextListenerController.hasListener(windowContextToken)) {
... 省略部分
} else {
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
// 如果 AMS 中沒有 Token 就會創建一個
// 創建 WindowToken
token = new WindowToken.Builder(this, binder, type)
.setDisplayContent(displayContent)
.setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
.setRoundedCornerOverlay(isRoundedCornerOverlay)
.build();
}
} else if (rootType >= FIRST_APPLICATION_WINDOW
&& rootType <= LAST_APPLICATION_WINDOW) { //應用類型窗口
// 從 token 中取得 ActivityRecord
activity = token.asActivityRecord();
... 判斷是否可取到 Activity 等等,無法取得則返回錯誤
} else if (...) {
... 省略其他判斷
}
... 省略部分
}
}
```
> 
如果是應用窗口,可以發現 WMS 儲存的 Token 與 AMS 中的 AcitivtyRecord 有關係
```java=
// 從 token 中取得 ActivityRecord
activity = token.asActivityRecord();
```
> 
3. 保存 Window 狀態、Client 訊息、判斷顯示視窗、做調整
1. **==創建 WindowState==**,保存 Window 的所有訊息狀態
2. 判斷 Client 視窗狀態
3. 檢查顯示視窗
4. 依照情況修正 LayoutParams
5. 緩存資料在 WMS 中
* `mWindowMap` 集合添加 IWindow 視窗
* `WindowToken` 集合添加到 WindowStete 內
6. 透過 DisplayPolicy#**addWindowLw** 添加 Window 到系統中
7. **使用 `assignChildLayers` 方法,==重新分配 Layer 層級==**
```java=
// WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
int displayId, /*省略部分參數*/ ) {
... 省略部分
synchronized (mGlobalLock) {
... 省略部分
// 1. 保存 Window 的所有訊息狀態 (View 的狀態)
// 存入相對應的 token (WindowToken)
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
if (win.mDeathRecipient == null) {
// 2. 客戶端已經死亡,不必繼續往下執行
return WindowManagerGlobal.ADD_APP_EXITING;
}
// 3. 檢查顯示視窗
if (win.getDisplayContent() == null) {
... log msg
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
// 4. 依照情況修正 LayoutParams
displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
win.setRequestedVisibilities(requestedVisibilities);
attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), callingUid, callingPid);
// 檢查 Type 是否合法
res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
if (res != ADD_OKAY) {
return res;
}
... 省略部分
win.attach(); // WindowState#attach
// 5. mWindowMap 添加 IWindow 視窗
mWindowMap.put(client.asBinder(), win); // View Binder(ViewRootImpl#W) 作為 Key,存入 State
... 省略部分
// 5. WindowStete 添加到 WindowToken 內
win.mToken.addWindow(win);
// 6. 將 Window 加入系統中
displayPolicy.addWindowLw(win, attrs);
... 省略部分
// 7. 重新分配 Layer 層級
win.getParent().assignChildLayers();
}
Binder.restoreCallingIdentity(origId);
return res;
}
```
> 
* 總結一下 addWindow 方法
1. 對添加的 Window 進行檢查
2. WindowToken 相關處理,如果可以創建的話就由 WMS 創建,或是有 ParentWindow 也可以直接使用
> 應用視窗 ActivityRecord 也可以看做 Token
3. WindowState 保存每個 IWindow (ViewRootImpl),並將 WindowState 存入 WindowToken
4. 創建 & 配置 DisplayContent,完成窗口添加到系統的準備工作
### WMS 刪除 Window
// TODO:
## Appendix & FAQ
:::info
參考
https://ljd1996.github.io/2020/08/27/Android-Window%E6%9C%BA%E5%88%B6%E5%8E%9F%E7%90%86/
:::
###### tags: `Android Framework`