fwrite

fwrite

好好生活
twitter
github
email

WMS

WMS 全名是 WindowManagerService,它是客戶端 APP 的管理者,處於 SystemServer 進程,WMS 主要負責管理幾件事情
窗口管理
負責 Window 添加、更新、刪除,核心管理成員有 DisplayContentWindowTokenWindowState
窗口動畫
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_SERVICEwindow)設定到 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 啟動後會透過 onInitReadydisplayReadysystemReady 來完成 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名稱說明
1FIRST_APPLICATION_WINDOW應用類視窗的起始值
1TYPE_BASE_APPLICATION其他應用都可覆蓋在該 Window 之上
2TYPE_APPLICATION一般的應用窗口
3TYPE_APPLICATION_STARTING應用程序啟動前的畫面(用在加載某個畫面之前的預前畫面)
4TYPE_DRAWN_APPLICATION在繪畫完成前等待
99LAST_APPLICATION_WINDOW應用視窗的結束值

Sub Window:附加在應用之上的視窗,一般稱為 子窗口,其值區間為 1000 ~ 1999 之間

Value名稱說明
1000FIRST_SUB_WINDOWSubWindow 的起始值
1000TYPE_APPLICATION_PANEL該 SubWindow 顯示在依附的 App 之上
1001TYPE_APPLICATION_MEDIA顯示有關 video 的 SubWindow
1002TYPE_APPLICATION_SUB_PANEL顯示在依附的 app 之上,也在其他 SubWindow 之上
1003TYPE_APPLICATION_ATTACHED_DIALOGDialog 類型的 Window
1004TYPE_APPLICATION_MEDIA_OVERLAY顯示在 TYPE_APPLICATION_MEDIA 還有底下的應用視窗之間
1005TYPE_APPLICATION_ABOVE_SUB_PANELTYPE_APPLICATION_SUB_PANEL 更上層的 Window
1999LAST_SUB_WINDOWSubWindow 的結束值

System Window:系統使用的 Window 視窗(以下列出幾種),區間為 2000 ~ 2999 之間

Value名稱說明
2000FIRST_SYSTEM_WINDOWSystem Window 的起始值
2001TYPE_STATUS_BARStatus bar 的 Window
2002TYPE_SEARCH_BAR搜尋 Bar 的 Window
2038TYPE_APPLICATION_OVERLAY覆蓋於其他 Activity 視窗
2999LAST_SYSTEM_WINDOWSystem 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中,並且有分為 typeFlags 兩種設定
Type:上面已經說過,主要有分為 Application WindowSub WindowSystem Window 三種
Flag:莫認為 0,以下列出幾個(有滿多的)

ValueFlag說明
0x00000001FLAG_ALLOW_LOCK_WHILE_SCREEN_ON只要該窗口可見,就允許鎖住螢幕(可配合 FLAG_KEEP_SCREEN_ON 使用)
0x00000002FLAG_DIM_BEHIND窗口後的 Window 都變淡
0x00000004FLAG_BLUR_BEHIND窗口後的 Window 變模糊
0x00000008FLAG_NOT_FOCUSABLE該 Window 視窗不可事件,事件會直接傳遞給後方 Window
0x00000010FLAG_NOT_TOUCHABLE該窗口不接受任何事件
0x00000080FLAG_KEEP_SCREEN_ON只要該窗口可見,就保持螢幕亮起

System UI 控制:System UI 的設定定義在 View 中,針對每個 View 個別設置

ValueFlag說明
0SYSTEM_UI_FLAG_VISIBLE設定 System UI 可見
0x00000002SYSTEM_UI_FLAG_HIDE_NAVIGATION設定 Navigtion Bar 不可見
0x00000004SYSTEM_UI_FLAG_FULLSCREEN螢幕全屏
0x00000100SYSTEM_UI_FLAG_LAYOUT_STABLE儘量保持 UI 布局的穩定性
0x00000400SYSTEM_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 : WindowHashMapWindowHashMap 繼承 HashMap,用來保存所有 ViewImpl;Key: IBinder、Value: WindowStateKey 其實是 IWindow(ViewRootImpl 的內部類 W)、Value 是保存窗口信息
mFinishedStarting : ArrayListAppWindowToken 的父類是 WindowToken 當 APP 要向 WMS 申請一個新窗口時就要給予這個 token 讓 WMS 驗證每個 Activity 對應一個 AppWindowToken(一個 AppWindowToken 管理多個 WindowToken 視窗)
mResizingWindows : ArrayList用來存儲正在調整大小的視窗
mAnimator : WindowAnimator管理 Window 動畫 & 特效
mH : HH 是 Handler 類型,它是屬於 DisplayThread Looper將消息給 WMS
mInputManager : InputManagerServiceIMS 系統服務,當使用者有輸入訊息時,WMS 會給予一個適合的視窗
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。