WMS 全名是 WindowManagerService,它是客戶端 APP 的管理者,處於 SystemServer 進程,WMS 主要負責管理幾件事情
窗口管理
負責 Window 添加、更新、刪除,核心管理成員有 DisplayContent
、WindowToken
、WindowState
窗口動畫
Window 切換時,可以添加動畫,讓 Window 切換時更加自然,動畫由 WMS 的動畫子系統負責,該系統是 WindowAnimator
輸入系統的中轉
當使用者對視窗觸控或輸入時,都会觸發 InputManagerService 會對觸摸事件進行處理,將事件通過 WMS 傳遞到合適的窗口進行處理(這時 WMS 就是 中轉站)
Surface 管理
WMS 並不具備 Window 繪製的功能,每個 Window 都有一個 Surface 來繪製,而 WMS 負責 Surface 的分配
WMS 啟動 - SystemServer#
WMS 就是 WindowManagerService,它是系統服務,說到系統服務自然就會想到 SystemServer,那就讓我們來看看 WMS 是如何被 SystemServer 喚起的
SystemServer 透過 WMS#main
方法啟動
把 WMS 以 Context#WINDOW_SERVICE
(window)設定到 ServiceManager 中
把啟動的 WMS 物件設定給 AMS 服務
// 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 的後續動作(這些方法之後會介紹)
// 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 - main 函數#
透過 DisplayThread 中的 Handler#runWithScissors
創建 WMS 物件(也就是創建 WMS 的執行緒與 SystemServer 執行緒不同)
Handler#runWithScissors
方法是透過鎖來達成同步任務,保證該 Runnable 會先被 DisplayThread 的 Looper 先執行,執行完後才回到 SystemServer 的 Thread
// 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 - 創建 Looper#
// 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 - 創建 WMS 物件#
WMS 就是在 DisplayThread 類中被啟動,DisplayThread 可以說是 WMS 的 MainThread
DisplayThread 可以創建安全 Handler,其主要功能是:處理 低延遲顯示 的相關操作,並只能由 WindowManager、DisplayManager、InputManager 執行快速操作
從上面可以看到 DisplayThread 繼承於 ServiceThread(而它繼承於 HandlerThread),所以 它會在執行 run 方法時自動創建 Looper 對象,鑑於 HandlerThread 創建的 Handler 並不安全,所以 DisplayThread 這裡自己創建 Handler(使用類鎖)
// 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;
}
}
}
傳遞事件給 WMS 有兩種方式
直接呼叫 WMS function,即時傳送
// WindowManagerService.java
@Override
public boolean isKeyguardLocked() {
// mPolicy 類型 WindowManagerPolicy
return mPolicy.isKeyguardLocked();
}
透過 DisplayThread 的 Looper 將事件丟入 WMS Thread(DisplayThread)中
// 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 類#
UiThread 與 DisplayThread 差不多,但多添加了一個 dispose
方法,來停止 Looper,並結束該對象(置為 null),在 initPolicy()
、systemReady()
會使用到
// 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 類#
AnimationThread 與 DisplayThread 差不多,但多添加了一個 dispose 方法,來停止 Looper,並結束該對象(置為 null)
// 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 啟動後續#
// 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 創建#
前面有提到 WindowManagerService#main
方法會透過 DisplayThread(Thread)創建 WMS 的實例,在這裡就會創建 H 類,而它的 Looper 就是當前 Thread 也就是 DisplayThread
// 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#onInitReady
- 初始化 WindowManagerPolicy#
WMS#onInitReady
函數:取得 UiThread (另外一個 Thread) 的 Handler,並初始化 WindowManagerPolicy 實作呼叫 PhoneWindowManager#init 函數)
// 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
}
}
WMS#displayReady
- 準備顯示#
標示 WindowAnimator 初始化完成
重新配置設定,保證 DisplayWindowSettings 設定都有被正常使用
透過 ActivityTaskManager 來更新設定
// 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#systemReady
- 服務準備完成#
// 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 重點#
窗口屬性 - Layer Type#
Android 支持多種窗口,並且會將窗口分為三類,定義在 WindowManager#LayoutParams中
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 | 應用視窗的結束值 |
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 之上,也在其他 SubWindow 之上 |
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 的結束值 |
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 的結束值 |
WindowState 初始化 - 決定 Base Layer#
從 WindState 構造函數可以知道,Base Layer 數值可以從 WindowManagerPolicy#getWindowLayerLw
方法取得
// 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;
...
}
}
WindowManagerPolicy 透過傳入的 WindowState
決定 Window 基礎 Layer 層級(數值越高,越接近使用者 & 上層)
// 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;
}
}
透過傳入的 WindowState
決定 Window 基礎 Layer 層級(數值越高,越接近使用者 & 上層)
WindowManagerPolicy#getSubWindowLayerFromTypeLw
方法:決定子窗口在父窗口中的偏移量
// 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;
}
窗口屬性 - LayoutParams#
Window 的統一屬性設定在 WindowManager#LayoutParams中,並且有分為 type
、Flags
兩種設定
Type:上面已經說過,主要有分為 Application Window
、Sub Window
、System Window
三種
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 | 只要該窗口可見,就保持螢幕亮起 |
System UI 控制:System UI 的設定定義在 View 中,針對每個 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 開始繪製 |
WindowManagerService 簡單理解起來是掌管該裝置所有的 Window 的上下關係(z 軸的管理)、傳輸繪製任務到底層
變數 | 說明 | 補充 |
---|---|---|
mPolicy : WindowManagerPolicy | 定義一個窗口策略所須遵循的 通用規範,並提供了 WindowManger 特定的 UI 行為 | WindowManager 是 interface,它的實作是 PhoneWindowManager |
mSessions : ArraySet | 它主要用於進程通信,其他的應用進程的 View 想要和 WMS 通信,都要透過 Session 與 WMS 通信 | 每個應用程序是透過 WindowManagerGlobal 取得 Session |
mWindowMap : WindowHashMap | WindowHashMap 繼承 HashMap,用來保存所有 ViewImpl;Key: IBinder、Value: WindowState | Key 其實是 IWindow(ViewRootImpl 的內部類 W)、Value 是保存窗口信息 |
mFinishedStarting : ArrayList | AppWindowToken 的父類是 WindowToken 當 APP 要向 WMS 申請一個新窗口時就要給予這個 token 讓 WMS 驗證 | 每個 Activity 對應一個 AppWindowToken(一個 AppWindowToken 管理多個 WindowToken 視窗) |
mResizingWindows : ArrayList | 用來存儲正在調整大小的視窗 | |
mAnimator : WindowAnimator | 管理 Window 動畫 & 特效 | |
mH : H | H 是 Handler 類型,它是屬於 DisplayThread Looper | 將消息給 WMS |
mInputManager : InputManagerService | IMS 系統服務,當使用者有輸入訊息時,WMS 會給予一個適合的視窗 |