一、WMS的職責
WMS是Android中重要的服務,它是WindowManager的管理者,WMS無論對于應用開發還是Framework開發都是重要的知識點,究其原因是因為WMS有很多職責,每個職責都會涉及重要且復雜的系統,這使得WMS就像一個十字路口的交通燈一樣,沒有了這個交通燈,十字路口就無法正常通車,WMS的職責只要有以下幾點。
1、窗口管理
WMS是窗口的管理者,它負責窗口的啟動、添加和刪除,另外窗口的大小和層級也是由WMS進行管理的。窗口管理的核心成員由DisplayContent、WindowToken和WindowState。
2、窗口動畫
窗口間進行切換時,使用窗口動畫可以顯得更炫一些,窗口動畫由WMS的動畫子系統來負責,動畫子系統的管理者為WindowAnimator。
3、輸入系統的中轉站
通過對窗口的觸摸從而產生觸摸事件,InputManagerService(IMS)會對觸摸事件進行處理,它會尋找一個最合適的窗口來處理觸摸反饋信息,WMS是窗口的管理者,它作為輸入系統的中轉站再合適不過。
4、Surface管理
窗口并不具備繪制的功能,因此每個窗口都需要有一塊Surface來供自己繪制,為每個窗口分配Surface時由WMS來完成的。
從上圖可以看出WMS很復雜,與它關聯的由窗口管理、窗口動畫、輸入系統和Surface,它們每一個都是重要且負責的系統。
二、WMS的創建過程
1)WMS涉及的知識點非常多,但是無論這些知識點如何多,我們還是十分有必要先知道WMS時如何創建的。WMS時在SystemServer進程中創建的,SystemServer的run方法關鍵代碼如下所示:
frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
try {
...代碼省略...
Looper.prepareMainLooper();//1創建消息Looper
System.loadLibrary("android_servers");//2加載動態庫libandroid_servers.so
performPendingShutdown();
createSystemContext();//3初始化系統的Context
mSystemServiceManager = new SystemServiceManager(mSystemContext);//4創建系統服務管理者
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
SystemServerInitThreadPool.get();
} finally {
traceEnd();
}
// 開啟服務
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();//5啟動引導服務
startCoreServices();//6啟動核心服務
startOtherServices();//7啟動其他服務,WMS在該方法中被啟動
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...代碼省略...
}
SystemServer的run方法中會調用startOtherServices方法,WMS就是在該方法中被啟動的。
2)SystemServer的startOtherServices方法如下所示:
private void startOtherServices() {
...代碼省略...
traceBeginAndSlog("InitWatchdog");
final Watchdog watchdog = Watchdog.getInstance();//1得到Watchdog實例,該對象可以用來監視系統的一些關鍵服務的運行狀況。
watchdog.init(context, mActivityManagerService);//2對Watchdog實例進行初始化
traceEnd();
traceBeginAndSlog("StartInputManagerService");
inputManager = new InputManagerService(context);//3創建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執行WMS的main方法,其內部會創建WMS,
ServiceManager.addService(Context.WINDOW_SERVICE, wm);//5將WMS注冊到服務管理器中
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);//6將IMS注冊到服務管理器中
traceEnd();
...代碼省略...
try {
wm.displayReady();//7初始化屏幕顯示信息
} catch (Throwable e) {
reportWtf("making display ready", e);
}
...代碼省略...
try {
wm.systemReady();//8通知WMS,系統的初始化工作已經完成,其內部調用了WindowManagerPolicy的systemReady方法
} catch (Throwable e) {
reportWtf("making Window Manager Service ready", e);
}
...代碼省略...
}
startOtherServices會獲取Watchdog實例并對實例進行初始化,創建InputManagerService實例,并在注釋4處將該實例作為參數傳遞給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表達式
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, haveInputMethods, showBootMsgs, onlyCore, policy)
, 0);//2創建WMS實例對象
return sInstance;
}
DisplayThread是一個單例的前臺線程,這個線程用來處理需要低延時顯示的相關操作,并只能由WindowManager、DisplayManager和InputManager實時執行快速操作。正是在DisplayThread的run方法中創建了WMS的實例,這就意味著WMS的創建時運行在android.display線程中的。
4)來看下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);
}
- 對傳入的Runnable的timeout進行判斷,如果Runnable為null或者timeout小于0則拋出異常。
- 根據每個線程只有一個Looper的原理來判斷當前線程(system_server線程)是否是Handler所指向的線程(android.display線程),如果是則直接執行Runnable的run方法,否則調用BlockingRunnable的postAndWait方法,并將當前線程的Runnable作為參數傳遞進去。
5)BlockingRunnable是Handler的內部類。
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的任務隊列中,上面第3步我們知道runWithScissors方法的第二個參數為0,因此timeout等于0,這樣如果mDone為false的話會一直調用注釋3處的wait方法使得當前線程(system_server線程)進入等待狀態。
- 在注釋1處執行了傳入的Runnable的run方法(運行在android.display線程中),執行完畢后finally代碼塊中將mDone設置為true,并調用noifyAll方法喚醒處于等待狀態的線程,這樣就不會繼續調用注釋3處的wait方法。
結合以上兩點我們可以得出一個結論,system_server線程會一直等待android.display線程執行完畢才開始執行system_server線程,這是因為android.display線程內部執行了WMS的創建,而WMS的創建優先級要更高。
6)接下來我們來查看一下WMS的構造方法。
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處保存傳遞進來的IMS,這樣WMS就持有了IMS的引用。
- 注釋2處通過DisplayManager的getDisplay方法得到Display數組(每個顯示設備都有一個Display實例),接著遍歷Display數組。
- 注釋3處的createDisplayContentLocked方法將Display封裝成DisplayContent,DisplayContent用來描述一塊屏幕。
- 注釋4處得到AMS實例,并賦值給mActivityManager,這樣WMS就持有了AMS的引用。
- 注釋5處創建WindowAnimator,用于管理所有的窗口動畫。
- 注釋6處初始化了窗口管理策略的接口類WindowManagerPolicy(WMP),它用來定義一個窗口策略所要遵循的通用規范。
- 注釋7處調用addMonitor方法將自身添加到watchdog中,Watchdog用來監控系統的一些關鍵服務的運行狀況,這些被監控的服務都會實現Watchdog.Monitor接口。Watchdog每分鐘都會對被監控的系統服務進行檢查,如果被監控的系統服務出現了死鎖,就會殺死Watchdog所在的進程,也就是SystemServer進程。
6)繼續來看注釋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方法的實現類似,在注釋1處執行了WMP的init方法,WMP是一個接口,init方法具體在PhoneWindowManager(PWM)中實現。PWM的init方法運行在android.ui線程中,它的優先級要高于initPolicy方法所在的android.display線程,因此android.display線程要等PWM的init方法執行完畢后,處于等待狀態的android.display線程才會被喚醒從而繼續執行下面的代碼。
三、WMS的創建過程的3個線程
上面WMS創建的過程中有提到3個線程,分別是system_server、android.display和android.ui,下圖是關于這三個線程的三個步驟。
1)首先在system_server線程中執行了SystemServer的startOtherServices方法,在startOtherServices方法中會調用WMS的main方,main方法會創建WMS,創建的過程是在android.display線程中實現的,由于創建WMS的優先級更高,因此system_server線程要等WMS創建完成后,處于等待狀態的system_server線程才會被喚醒從而繼續執行下面的代碼。
2)在WMS的構造方法中會調用WMS的initPolicy方法,在initPolicy方法中又會調用PWM的init方法,PWM的init方法在android.ui線程中運行,它的優先級要高于android.display線程,因此"android.display"線程要等PWM的init方法執行完畢后,處于等待狀態的android.display線程才會被喚醒從而繼續執行下面的代碼。
3)PWM的init方法執行完畢后,android.display線程就完成了WMS的創建,等待的system_server線程被喚醒后繼續執行WMS的main方法后的代碼邏輯,比如在前面第二部分第2步的注釋7的地方,WMS的displayReady方法用來初始化屏幕顯示信息。