Android8.0系統(tǒng)源碼WMS(二)之理解WindowManagerService

一、WMS的職責(zé)

WMS是Android中重要的服務(wù),它是WindowManager的管理者,WMS無(wú)論對(duì)于應(yīng)用開(kāi)發(fā)還是Framework開(kāi)發(fā)都是重要的知識(shí)點(diǎn),究其原因是因?yàn)閃MS有很多職責(zé),每個(gè)職責(zé)都會(huì)涉及重要且復(fù)雜的系統(tǒng),這使得WMS就像一個(gè)十字路口的交通燈一樣,沒(méi)有了這個(gè)交通燈,十字路口就無(wú)法正常通車(chē),WMS的職責(zé)只要有以下幾點(diǎn)。

1、窗口管理
WMS是窗口的管理者,它負(fù)責(zé)窗口的啟動(dòng)、添加和刪除,另外窗口的大小和層級(jí)也是由WMS進(jìn)行管理的。窗口管理的核心成員由DisplayContent、WindowToken和WindowState。
2、窗口動(dòng)畫(huà)
窗口間進(jìn)行切換時(shí),使用窗口動(dòng)畫(huà)可以顯得更炫一些,窗口動(dòng)畫(huà)由WMS的動(dòng)畫(huà)子系統(tǒng)來(lái)負(fù)責(zé),動(dòng)畫(huà)子系統(tǒng)的管理者為WindowAnimator。
3、輸入系統(tǒng)的中轉(zhuǎn)站
通過(guò)對(duì)窗口的觸摸從而產(chǎn)生觸摸事件,InputManagerService(IMS)會(huì)對(duì)觸摸事件進(jìn)行處理,它會(huì)尋找一個(gè)最合適的窗口來(lái)處理觸摸反饋信息,WMS是窗口的管理者,它作為輸入系統(tǒng)的中轉(zhuǎn)站再合適不過(guò)。
4、Surface管理
窗口并不具備繪制的功能,因此每個(gè)窗口都需要有一塊Surface來(lái)供自己繪制,為每個(gè)窗口分配Surface時(shí)由WMS來(lái)完成的。

WMS的職責(zé)

從上圖可以看出WMS很復(fù)雜,與它關(guān)聯(lián)的由窗口管理、窗口動(dòng)畫(huà)、輸入系統(tǒng)和Surface,它們每一個(gè)都是重要且負(fù)責(zé)的系統(tǒng)。

二、WMS的創(chuàng)建過(guò)程

1)WMS涉及的知識(shí)點(diǎn)非常多,但是無(wú)論這些知識(shí)點(diǎn)如何多,我們還是十分有必要先知道WMS時(shí)如何創(chuàng)建的。WMS時(shí)在SystemServer進(jìn)程中創(chuàng)建的,SystemServer的run方法關(guān)鍵代碼如下所示:

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

 private void run() {
        try {
            ...代碼省略...
            Looper.prepareMainLooper();//1創(chuàng)建消息Looper
            System.loadLibrary("android_servers");//2加載動(dòng)態(tài)庫(kù)libandroid_servers.so
            performPendingShutdown();
            createSystemContext();//3初始化系統(tǒng)的Context
            mSystemServiceManager = new SystemServiceManager(mSystemContext);//4創(chuàng)建系統(tǒng)服務(wù)管理者
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();
        }
        // 開(kāi)啟服務(wù)
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices();//5啟動(dòng)引導(dǎo)服務(wù)
            startCoreServices();//6啟動(dòng)核心服務(wù)
            startOtherServices();//7啟動(dòng)其他服務(wù),WMS在該方法中被啟動(dòng)
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }
      ...代碼省略...
    }

SystemServer的run方法中會(huì)調(diào)用startOtherServices方法,WMS就是在該方法中被啟動(dòng)的。

2)SystemServer的startOtherServices方法如下所示:

  private void startOtherServices() {
           ...代碼省略...
            traceBeginAndSlog("InitWatchdog");
            final Watchdog watchdog = Watchdog.getInstance();//1得到Watchdog實(shí)例,該對(duì)象可以用來(lái)監(jiān)視系統(tǒng)的一些關(guān)鍵服務(wù)的運(yùn)行狀況。
            watchdog.init(context, mActivityManagerService);//2對(duì)Watchdog實(shí)例進(jìn)行初始化
            traceEnd();
            traceBeginAndSlog("StartInputManagerService");
            inputManager = new InputManagerService(context);//3創(chuàng)建InputManagerService
            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執(zhí)行WMS的main方法,其內(nèi)部會(huì)創(chuàng)建WMS,
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);//5將WMS注冊(cè)到服務(wù)管理器中
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);//6將IMS注冊(cè)到服務(wù)管理器中
            traceEnd();
           ...代碼省略...        
        try {
            wm.displayReady();//7初始化屏幕顯示信息
        } catch (Throwable e) {
            reportWtf("making display ready", e);
        }
           ...代碼省略...       
        try {
            wm.systemReady();//8通知WMS,系統(tǒng)的初始化工作已經(jīng)完成,其內(nèi)部調(diào)用了WindowManagerPolicy的systemReady方法
        } catch (Throwable e) {
            reportWtf("making Window Manager Service ready", e);
        }
             ...代碼省略...       
    }

startOtherServices會(huì)獲取Watchdog實(shí)例并對(duì)實(shí)例進(jìn)行初始化,創(chuàng)建InputManagerService實(shí)例,并在注釋4處將該實(shí)例作為參數(shù)傳遞給WindowManagerService的main方法。

3)WindowManagerService 的main方法如下:

   public static WindowManagerService main(final Context context, final InputManagerService im,
            final boolean haveInputMethods, final boolean showBootMsgs, final boolean onlyCore,
            WindowManagerPolicy policy) {
           //1這里使用了java8中的Lambda表達(dá)式
           DisplayThread.getHandler().runWithScissors(() ->
           sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, onlyCore, policy)
            , 0);//2創(chuàng)建WMS實(shí)例對(duì)象
        return sInstance;
    }

DisplayThread是一個(gè)單例的前臺(tái)線程,這個(gè)線程用來(lái)處理需要低延時(shí)顯示的相關(guān)操作,并只能由WindowManager、DisplayManager和InputManager實(shí)時(shí)執(zhí)行快速操作。正是在DisplayThread的run方法中創(chuàng)建了WMS的實(shí)例,這就意味著WMS的創(chuàng)建時(shí)運(yùn)行在android.display線程中的。
4)來(lái)看下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) {
            r.run();
            return true;
        }
        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
    }
  • 對(duì)傳入的Runnable的timeout進(jìn)行判斷,如果Runnable為null或者timeout小于0則拋出異常。
  • 根據(jù)每個(gè)線程只有一個(gè)Looper的原理來(lái)判斷當(dāng)前線程(system_server線程)是否是Handler所指向的線程(android.display線程),如果是則直接執(zhí)行Runnable的run方法,否則調(diào)用BlockingRunnable的postAndWait方法,并將當(dāng)前線程的Runnable作為參數(shù)傳遞進(jìn)去。

5)BlockingRunnable是Handler的內(nèi)部類(lèi)。

 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處將當(dāng)前的BlockingRunnable添加到Handler的任務(wù)隊(duì)列中,上面第3步我們知道runWithScissors方法的第二個(gè)參數(shù)為0,因此timeout等于0,這樣如果mDone為false的話會(huì)一直調(diào)用注釋3處的wait方法使得當(dāng)前線程(system_server線程)進(jìn)入等待狀態(tài)。
  • 在注釋1處執(zhí)行了傳入的Runnable的run方法(運(yùn)行在android.display線程中),執(zhí)行完畢后finally代碼塊中將mDone設(shè)置為true,并調(diào)用noifyAll方法喚醒處于等待狀態(tài)的線程,這樣就不會(huì)繼續(xù)調(diào)用注釋3處的wait方法。

結(jié)合以上兩點(diǎn)我們可以得出一個(gè)結(jié)論,system_server線程會(huì)一直等待android.display線程執(zhí)行完畢才開(kāi)始執(zhí)行system_server線程,這是因?yàn)閍ndroid.display線程內(nèi)部執(zhí)行了WMS的創(chuàng)建,而WMS的創(chuàng)建優(yōu)先級(jí)要更高。

6)接下來(lái)我們來(lái)查看一下WMS的構(gòu)造方法。

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

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
            WindowManagerPolicy policy) {
        ...代碼省略...
        mInputManager = inputManager; // 注釋1
        ...代碼省略...
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
        mDisplays = mDisplayManager.getDisplays(); // 注釋2
        for (Display display : mDisplays) {
            createDisplayContentLocked(display); // 注釋3
        }
        ...代碼省略...
        mActivityManager = ActivityManager.getService(); // 注釋4
        ...代碼省略...
        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
        ...代碼省略...
        mAnimator = new WindowAnimator(this); // 注釋5
        mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);

        LocalServices.addService(WindowManagerInternal.class, new LocalService());
        initPolicy(); // 注釋6
        Watchdog.getInstance().addMonitor(this); // 注釋7
        ...代碼省略...
    }

  • 注釋1處保存?zhèn)鬟f進(jìn)來(lái)的IMS,這樣WMS就持有了IMS的引用。
  • 注釋2處通過(guò)DisplayManager的getDisplay方法得到Display數(shù)組(每個(gè)顯示設(shè)備都有一個(gè)Display實(shí)例),接著遍歷Display數(shù)組。
  • 注釋3處的createDisplayContentLocked方法將Display封裝成DisplayContent,DisplayContent用來(lái)描述一塊屏幕。
  • 注釋4處得到AMS實(shí)例,并賦值給mActivityManager,這樣WMS就持有了AMS的引用。
  • 注釋5處創(chuàng)建WindowAnimator,用于管理所有的窗口動(dòng)畫(huà)。
  • 注釋6處初始化了窗口管理策略的接口類(lèi)WindowManagerPolicy(WMP),它用來(lái)定義一個(gè)窗口策略所要遵循的通用規(guī)范。
  • 注釋7處調(diào)用addMonitor方法將自身添加到watchdog中,Watchdog用來(lái)監(jiān)控系統(tǒng)的一些關(guān)鍵服務(wù)的運(yùn)行狀況,這些被監(jiān)控的服務(wù)都會(huì)實(shí)現(xiàn)Watchdog.Monitor接口。Watchdog每分鐘都會(huì)對(duì)被監(jiān)控的系統(tǒng)服務(wù)進(jìn)行檢查,如果被監(jiān)控的系統(tǒng)服務(wù)出現(xiàn)了死鎖,就會(huì)殺死Watchdog所在的進(jìn)程,也就是SystemServer進(jìn)程。

6)繼續(xù)來(lái)看注釋6處的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);//注釋1
            }
        }, 0);
    }

initPolicy方法和此前講的WMS的main方法的實(shí)現(xiàn)類(lèi)似,在注釋1處執(zhí)行了WMP的init方法,WMP是一個(gè)接口,init方法具體在PhoneWindowManager(PWM)中實(shí)現(xiàn)。PWM的init方法運(yùn)行在android.ui線程中,它的優(yōu)先級(jí)要高于initPolicy方法所在的android.display線程,因此android.display線程要等PWM的init方法執(zhí)行完畢后,處于等待狀態(tài)的android.display線程才會(huì)被喚醒從而繼續(xù)執(zhí)行下面的代碼。

三、WMS的創(chuàng)建過(guò)程的3個(gè)線程

上面WMS創(chuàng)建的過(guò)程中有提到3個(gè)線程,分別是system_server、android.display和android.ui,下圖是關(guān)于這三個(gè)線程的三個(gè)步驟。


三個(gè)線程之間的關(guān)系

1)首先在system_server線程中執(zhí)行了SystemServer的startOtherServices方法,在startOtherServices方法中會(huì)調(diào)用WMS的main方,main方法會(huì)創(chuàng)建WMS,創(chuàng)建的過(guò)程是在android.display線程中實(shí)現(xiàn)的,由于創(chuàng)建WMS的優(yōu)先級(jí)更高,因此system_server線程要等WMS創(chuàng)建完成后,處于等待狀態(tài)的system_server線程才會(huì)被喚醒從而繼續(xù)執(zhí)行下面的代碼。

2)在WMS的構(gòu)造方法中會(huì)調(diào)用WMS的initPolicy方法,在initPolicy方法中又會(huì)調(diào)用PWM的init方法,PWM的init方法在android.ui線程中運(yùn)行,它的優(yōu)先級(jí)要高于android.display線程,因此"android.display"線程要等PWM的init方法執(zhí)行完畢后,處于等待狀態(tài)的android.display線程才會(huì)被喚醒從而繼續(xù)執(zhí)行下面的代碼。

3)PWM的init方法執(zhí)行完畢后,android.display線程就完成了WMS的創(chuàng)建,等待的system_server線程被喚醒后繼續(xù)執(zhí)行WMS的main方法后的代碼邏輯,比如在前面第二部分第2步的注釋7的地方,WMS的displayReady方法用來(lái)初始化屏幕顯示信息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容