Android解析WindowManagerService(一)WMS的誕生

劉望舒發表於2017-10-09

相關文章
Android系統啟動系列
Android深入四大元件系列
Android應用程式啟動過程系列
Android解析WindowManager系列

前言

此前我用多篇文章介紹了WindowManager,這個系列我們來介紹WindowManager的管理者WMS,首先我們先來學習WMS是如何產生的。本文原始碼基於Android 8.0,與Android 7.1.2相比有一個比較直觀的變化就是Java FrameWork採用了Lambda表示式。

1.WMS概述

WMS是系統的其他服務,無論對於應用開發還是Framework開發都是重點的知識,它的職責有很多,主要有以下幾點:

視窗管理

WMS是視窗的管理者,它負責視窗的啟動、新增和刪除,另外視窗的大小和層級也是由WMS進行管理的。視窗管理的核心成員有DisplayContent、WindowToken和WindowState。

視窗動畫

視窗間進行切換時,使用視窗動畫可以顯得更炫一些,視窗動畫由WMS的動畫子系統來負責,動畫子系統的管理者為WindowAnimator。

輸入系統的中轉站

通過對視窗的觸控從而產生觸控事件,InputManagerService(IMS)會對觸控事件進行處理,它會尋找一個最合適的視窗來處理觸控反饋資訊,WMS是視窗的管理者,因此,WMS“理所應當”的成為了輸入系統的中轉站。

Surface管理

視窗並不具備有繪製的功能,因此每個視窗都需要有一塊Surface來供自己繪製。為每個視窗分配Surface是由WMS來完成的。

WMS的職責可以簡單總結為下圖。

2.WMS的誕生

WMS的知識點非常多,在瞭解這些知識點前,我們十分有必要知道WMS是如何產生的。WMS是在SyetemServer程式中啟動的,不瞭解SyetemServer程式的可以檢視在Android系統啟動流程(三)解析SyetemServer程式啟動過程這篇文章。
先來檢視SyetemServer的main方法:
frameworks/base/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {
       new SystemServer().run();
}複製程式碼

main方法中只呼叫了SystemServer的run方法,如下所示。
frameworks/base/services/java/com/android/server/SystemServer.java

  private void run() {
         try {
            System.loadLibrary("android_servers");//1
            ...
            mSystemServiceManager = new SystemServiceManager(mSystemContext);//2
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // Prepare the thread pool for init tasks that can be parallelized
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();//3
            startCoreServices();//4
            startOtherServices();//5
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
    ...
    }複製程式碼

run方法程式碼很多,這裡擷取了關鍵的部分,在註釋1處載入了libandroid_servers.so。在註釋2處建立SystemServiceManager,它會對系統的服務進行建立、啟動和生命週期管理。接下來的程式碼會啟動系統的各種服務,在註釋3中的startBootstrapServices方法中用SystemServiceManager啟動了ActivityManagerService、PowerManagerService、PackageManagerService等服務。在註釋4處的方法中則啟動了BatteryService、UsageStatsService和WebViewUpdateService。註釋5處的startOtherServices方法中則啟動了CameraService、AlarmManagerService、VrManagerService等服務,這些服務的父類為SystemService。從註釋3、4、5的方法名稱可以看出,官方把大概80多個系統服務分為了三種型別,分別是引導服務、核心服務和其他服務,其中其他服務為一些非緊要和一些不需要立即啟動的服務,WMS就是其他服務的一種。
我們來檢視startOtherServices方法是如何啟動WMS的:

frameworks/base/services/java/com/android/server/SystemServer.java

 private void startOtherServices() {
 ...
            traceBeginAndSlog("InitWatchdog");
            final Watchdog watchdog = Watchdog.getInstance();//1
            watchdog.init(context, mActivityManagerService);//2
            traceEnd();
            traceBeginAndSlog("StartInputManagerService");
            inputManager = new InputManagerService(context);//3
            traceEnd();
            traceBeginAndSlog("StartWindowManagerService");
            ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE);
            mSensorServiceStart = null;
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore, new PhoneWindowManager());//4
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);//5
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);//6
            traceEnd();   
           ... 
           try {
            wm.displayReady();//7
               } catch (Throwable e) {
            reportWtf("making display ready", e);
              }
           ...
           try {
            wm.systemReady();//8
               } catch (Throwable e) {
            reportWtf("making Window Manager Service ready", e);
              }
            ...      
}複製程式碼

startOtherServices方法用於啟動其他服務,其他服務大概有70多個,上面的程式碼只列出了WMS以及和它相關的IMS的啟動邏輯,剩餘的其他服務的啟動邏輯也都大同小異。
在註釋1、2處分別得到Watchdog例項並對它進行初始化,Watchdog用來監控系統的一些關鍵服務的執行狀況,後文會再次提到它。在註釋3處建立了IMS,並賦值給IMS型別的inputManager物件。註釋4處執行了WMS的main方法,其內部會建立WMS,需要注意的是main方法其中一個傳入的引數就是註釋1處建立的IMS,WMS是輸入事件的中轉站,其內部包含了IMS引用並不意外。結合上文,我們可以得知WMS的main方法是執行在SystemServer的run方法中,換句話說就是執行在"system_server"執行緒”中,後面會再次提到"system_server"執行緒。
註釋5和註釋6處分別將WMS和IMS註冊到ServiceManager中,這樣如果某個客戶端想要使用WMS,就需要先去ServiceManager中查詢資訊,然後根據資訊與WMS所在的程式建立通訊通路,客戶端就可以使用WMS了。註釋7處用來初始化顯示資訊,註釋8處則用來通知WMS,系統的初始化工作已經完成,其內部呼叫了WindowManagerPolicy的systemReady方法。
我們來檢視註釋4處WMS的main方法,如下所示。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService .java

 public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
            WindowManagerPolicy policy) {
        DisplayThread.getHandler().runWithScissors(() ->//1
                sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
                        onlyCore, policy), 0);
        return sInstance;
    }複製程式碼

在註釋1處呼叫了DisplayThread的getHandler方法,用來得到DisplayThread的Handler例項。DisplayThread是一個單例的前臺執行緒,這個執行緒用來處理需要低延時顯示的相關操作,並只能由WindowManager、DisplayManager和InputManager實時執行快速操作。註釋1處的runWithScissors方法中使用了Java8中的Lambda表示式,它等價於如下程式碼:

    DisplayThread.getHandler().runWithScissors(new Runnable() {
            @Override
            public void run() {
             sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs,
                        onlyCore, policy);//2
            }
        }, 0);複製程式碼

在註釋2處建立了WMS的例項,這個過程執行在Runnable的run方法中,而Runnable則傳入到了DisplayThread對應Handler的runWithScissors方法中,說明WMS的建立是執行在“android.display”執行緒中。需要注意的是,runWithScissors方法的第二個引數傳入的是0,後面會提到。來檢視Handler的runWithScissors方法裡做了什麼:

frameworks/base/core/java/android/os/Handler.java

 public final boolean runWithScissors(final Runnable r, long timeout) {
        if (r == null) {
            throw new IllegalArgumentException("runnable must not be null");
        }
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout must be non-negative");
        }
        if (Looper.myLooper() == mLooper) {//1
            r.run();
            return true;
        }
        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
    }複製程式碼

開頭對傳入的Runnable和timeout進行了判斷,如果Runnable為null或者timeout小於0則丟擲異常。註釋1處根據每個執行緒只有一個Looper的原理來判斷當前的執行緒("system_server"執行緒)是否是Handler所指向的執行緒("android.display"執行緒),如果是則直接執行Runnable的run方法,如果不是則呼叫BlockingRunnable的postAndWait方法,並將當前執行緒的Runnable作為引數傳進去 ,BlockingRunnable是Handler的內部類,程式碼如下所示。
frameworks/base/core/java/android/os/Handler.java

private static final class BlockingRunnable implements Runnable {
        private final Runnable mTask;
        private boolean mDone;
        public BlockingRunnable(Runnable task) {
            mTask = task;
        }
        @Override
        public void run() {
            try {
                mTask.run();//1
            } finally {
                synchronized (this) {
                    mDone = true;
                    notifyAll();
                }
            }
        }
        public boolean postAndWait(Handler handler, long timeout) {
            if (!handler.post(this)) {//2
                return false;
            }
            synchronized (this) {
                if (timeout > 0) {
                    final long expirationTime = SystemClock.uptimeMillis() + timeout;
                    while (!mDone) {
                        long delay = expirationTime - SystemClock.uptimeMillis();
                        if (delay <= 0) {
                            return false; // timeout
                        }
                        try {
                            wait(delay);
                        } catch (InterruptedException ex) {
                        }
                    }
                } else {
                    while (!mDone) {
                        try {
                            wait();//3
                        } catch (InterruptedException ex) {
                        }
                    }
                }
            }
            return true;
        }
    }複製程式碼

註釋2處將當前的BlockingRunnable新增到Handler的任務佇列中。前面runWithScissors方法的第二個引數為0,因此timeout等於0,這樣如果mDone為false的話會一直呼叫註釋3處的wait方法使得當前執行緒("system_server"執行緒)進入等待狀態,那麼等待的是哪個執行緒呢?我們往上看,註釋1處,執行了傳入的Runnable的run方法(執行在"android.display"執行緒),執行完畢後在finally程式碼塊中將mDone設定為true,並呼叫notifyAll方法喚醒處於等待狀態的執行緒,這樣就不會繼續呼叫註釋3處的wait方法。因此得出結論,"system_server"執行緒執行緒等待的就是"android.display"執行緒,一直到"android.display"執行緒執行完畢再執行"system_server"執行緒,這是因為"android.display"執行緒內部執行了WMS的建立,顯然WMS的建立優先順序更高些。
WMS的建立就講到這,最後我們來檢視WMS的構造方法:

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService .java

   private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
       ...
       mInputManager = inputManager;//1
       ...
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        mDisplays = mDisplayManager.getDisplays();//2
        for (Display display : mDisplays) {
            createDisplayContentLocked(display);//3
        }
       ...
        mActivityManager = ActivityManagerNative.getDefault();//4
       ...
        mAnimator = new WindowAnimator(this);//5
        mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
                com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
        LocalServices.addService(WindowManagerInternal.class, new LocalService());
        initPolicy();//6
        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);//7
     ...
    }複製程式碼

註釋1處用來儲存傳進來的IMS,這樣WMS就持有了IMS的引用。註釋2處通過DisplayManager的getDisplays方法得到Display陣列(每個顯示裝置都有一個Display例項),接著遍歷Display陣列,在註釋3處的createDisplayContentLocked方法會將Display封裝成DisplayContent,DisplayContent用來描述一快螢幕。
註釋4處得到AMS例項,並賦值給mActivityManager ,這樣WMS就持有了AMS的引用。註釋5處建立了WindowAnimator,它用於管理所有的視窗動畫。註釋6處初始化了視窗管理策略的介面類WindowManagerPolicy(WMP),它用來定義一個視窗策略所要遵循的通用規範。註釋7處將自身也就是WMS通過addMonitor方法新增到Watchdog中,Watchdog用來監控系統的一些關鍵服務的執行狀況(比如傳入的WMS的執行狀況),這些被監控的服務都會實現Watchdog.Monitor介面。Watchdog每分鐘都會對被監控的系統服務進行檢查,如果被監控的系統服務出現了死鎖,則會殺死Watchdog所在的程式,也就是SystemServer程式。

檢視註釋6處的initPolicy方法,如下所示。
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

   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);//1
            }
        }, 0);
    }複製程式碼

initPolicy方法和此前講的WMS的main方法的實現類似,註釋1處執行了WMP的init方法,WMP是一個介面,init方法的具體實現在PhoneWindowManager(PWM)中。PWM的init方法執行在"android.ui"執行緒中,它的優先順序要高於initPolicy方法所在的"android.display"執行緒,因此"android.display"執行緒要等PWM的init方法執行完畢後,處於等待狀態的"android.display"執行緒才會被喚醒從而繼續執行下面的程式碼。

在本文中共提到了3個執行緒,分別是"system_server"、"android.display"和"android.ui",為了便於理解,下面給出這三個執行緒之間的關係。

"system_server"執行緒中會呼叫WMS的main方法,main方法中會建立WMS,建立WMS的過程執行在"android.display"執行緒中,它的優先順序更高一些,因此要等建立WMS完畢後才會喚醒處於等待狀態的"system_server"執行緒。
WMS初始化時會執行initPolicy方法,initPolicy方法會呼叫PWM的init方法,這個init方法執行在"android.ui"執行緒,並且優先順序更高,因此要先執行完PWM的init方法後,才會喚醒處於等待狀態的"android.display"執行緒。
PWM的init方法執行完畢後會接著執行執行在"system_server"執行緒的程式碼,比如本文前部分提到WMS的
systemReady方法。

參考資料
《深入理解Android核心設計思想》第二版
《深入理解Android:卷III》
WMS—啟動過程
Android Watchdog原始碼簡析--Based on Android 6.0.1
Watchdog實現分析

相關文章