原文出處——>[Android應用程序窗口(Activity)與WindowManagerService服務的連接過程分析](http://blog.csdn.net/luoshengyang/article/details/8275938)
在前兩文中,我們分析了Activity組件的窗口對象和視圖對象的創建過程。Activity組件在其窗口對象和視圖對象創建完成之后,就會請求與WindowManagerService建立一個連接,即請求WindowManagerService為其增加一個WindowState對象,用來描述它的窗口狀態。在本文中,我們就詳細分析Activity組件與WindowManagerService的連接過程。
我們從兩方面來看Activity組件與WindowManagerService服務之間的連接。一方面是從Activity組件到WindowManagerService服務的連接,另一方面是從WindowManagerService服務到Activity組件的連接。從Activity組件到WindowManagerService服務的連接是以Activity組件所在的應用程序進程為單位來進行的。當一個應用程序進程在啟動第一個Activity組件的時候,它便會打開一個到WindowManagerService服務的連接,這個連接以應用程序進程從WindowManagerService服務處獲得一個實現了IWindowSession接口的Session代理對象來標志。從WindowManagerService服務到Activity組件的連接是以Activity組件為單位來進行的。在應用程序進程這一側,每一個Activity組件都關聯一個實現了IWindow接口的W對象,這個W對象在Activity組件的視圖對象創建完成之后,就會通過前面所獲得一個Session代理對象來傳遞給WindowManagerService服務,而WindowManagerService服務接收到這個W對象之后,就會在內部創建一個WindowState對象來描述與該W對象所關聯的Activity組件的窗口狀態,并且以后就通過這個W對象來控制對應的Activity組件的窗口狀態。
上述Activity組件與WindowManagerService服務之間的連接模型如圖1所示:
:-: 
圖1 Activity組件與WindowManagerService服務之間的連接模型
從圖1還可以看出,每一個Activity組件在ActivityManagerService服務內部,都對應有一個ActivityRecord對象,這個ActivityRecord對象是Activity組件啟動的過程中創建的,用來描述Activity組件的運行狀態,這一點可以參考前面Android應用程序啟動過程源代碼分析一文。這樣,每一個Activity組件在應用程序進程、WindowManagerService服務和ActivityManagerService服務三者之間就分別一一地建立了連接。在本文中,我們主要關注Activity組件在應用程序進程和WindowManagerService服務之間以及在WindowManagerService服務和ActivityManagerService服務之間的連接。
接下來我們就通過Session類、W類和WindowState類的實現來簡要描述Activity組件與WindowManagerService服務之間的連接,如圖2和圖3所示:
:-: 
圖2 W類的實現
:-: 
圖3 Session類和WindowState類的實現
W類實現了IWindow接口,它的類實例是一個Binder本地對象。從前面Android應用程序窗口(Activity)的視圖對象(View)的創建過程分析一文可以知道,一個Activity組件在啟動的過程中,會創建一個關聯的ViewRoot對象,用來配合WindowManagerService服務來管理該Activity組件的窗口狀態。在這個ViewRoot對象內部,有一個類型為W的成員變量mWindow,它是在ViewRoot對象的創建過程中創建的。
ViewRoot類有一個靜態成員變量sWindowSession,它指向了一個實現了IWindowSession接口的Session代理對象。當應用程序進程啟動第一個Activity組件的時候,它就會請求WindowManagerService服務發送一個建立連接的Binder進程間通信請求。WindowManagerService服務接收到這個請求之后,就會在內部創建一個類型為Session的Binder本地對象,并且將這個Binder本地對象返回給應用程序進程,后者于是就會得到一個Session代理對象,并且保存在ViewRoot類的靜態成員變量sWindowSession中。
有了這個Session代理對象之后,應用程序進程就可以在啟動Activity組件的時候,調用它的成員函數add來將與該Activity組件所關聯的一個W對象傳遞給WindowManagerService服務,后者于是就會得到一個W代理對象,并且會以這個W代理對象來創建一個WindowState對象,即將這個W代理對象保存在新創建的WindowState對象的成員變量mClient中。這個WindowState對象的其余成員變量的描述可以參考前面Android應用程序窗口(Activity)實現框架簡要介紹和學習計劃一文的圖7,這里不再詳述。
Session類的描述同樣可以參考前面Android應用程序窗口(Activity)實現框架簡要介紹和學習計劃一文,這里我們主要描述一下它的作用。從圖3可以看出,Session類實現了IWindowSession接口,因此,應用程序進程就可以通過保存在ViewRoot類的靜態成員變量sWindowSession所描述的一個Session代理對象所實現的IWindowSession接口來與WindowManagerService服務通信,例如:
1. 在Activity組件的啟動過程中,調用這個IWindowSession接口的成員函數add可以將一個關聯的W對象傳遞到WindowManagerService服務,以便WindowManagerService服務可以為該Activity組件創建一個WindowState對象。
2. 在Activity組件的銷毀過程中,調用這個這個IWindowSession接口的成員函數remove來請求WindowManagerService服務之前為該Activity組件所創建的一個WindowState對象,這一點可以參考前面Android應用程序鍵盤(Keyboard)消息處理機制分析一文的鍵盤消息接收通道注銷過程分析。
3. 在Activity組件的運行過程中,調用這個這個IWindowSession接口的成員函數relayout來請求WindowManagerService服務來對該Activity組件的UI進行布局,以便該Activity組件的UI可以正確地顯示在屏幕中。
我們再來看W類的作用。從圖2可以看出,W類實現了IWindow接口,因此,WindowManagerService服務就可以通過它在內部所創建的WindowState對象的成員變量mClient來要求運行在應用程序進程這一側的Activity組件來配合管理窗口的狀態,例如:
1. 當一個Activity組件的窗口的大小發生改變后,WindowManagerService服務就會調用這個IWindow接口的成員函數resized來通知該Activity組件,它的大小發生改變了。
2. 當一個Activity組件的窗口的可見性之后,WindowManagerService服務就會調用這個IWindow接口的成員函數dispatchAppVisibility來通知該Activity組件,它的可見性發生改變了。
3. 當一個Activity組件的窗口獲得或者失去焦點之后,WindowManagerService服務就會調用這個IWindow接口的成員函數windowFoucusChanged來通知該Activity組件,它的焦點發生改變了。
理解了Activity組件在應用程序進程和WindowManagerService服務之間的連接模型之后,接下來我們再通過簡要分析Activity組件在WindowManagerService服務和ActivityManagerService服務之間的連接。
Activity組件在WindowManagerService服務和ActivityManagerService服務之間的連接是通過一個AppWindowToken對象來描述的。AppWindowToken類的實現如圖4所示:
:-: 
圖4 AppWindowToken類的實現
每一個Activity組件在啟動的時候,ActivityManagerService服務都會內部為該Activity組件創建一個ActivityRecord對象,并且會以這個ActivityRecord對象所實現的一個IApplicationToken接口為參數,請求WindowManagerService服務為該Activity組件創建一個AppWindowToken對象,即將這個IApplicationToken接口保存在新創建的AppWindowToken對象的成員變量appToken中。同時,這個ActivityRecord對象還會傳遞給它所描述的Activity組件所運行在應用程序進程,于是,應用程序進程就可以在啟動完成該Activity組件之后,將這個ActivityRecord對象以及一個對應的W對象傳遞給WindowManagerService服務,后者接著就會做兩件事情:
1. 根據獲得的ActivityRecord對象的IApplicationToken接口來找到與之對應的一個AppWindowToken對象;
2. 根據獲得的AppWindowToken對象以及前面傳遞過來的W代理對象來為正在啟動的Activity組件創建一個WindowState對象,并且將該AppWindowToken對象保存在新創建的WindowState對象的成員變量mAppToken中。
順便提一下,AppWindowToken類是從WindowToken類繼續下來的。WindowToken類也是用來標志一個窗口的,不過這個窗口類型除了是應用程序窗口,即Activity組件窗口之外,還可以是其它的,例如,輸入法窗口或者壁紙窗口類型等,而AppWindowToken類只是用來描述Activity組件窗口。當WindowToken類是用來描述Activity組件窗口的時候,它的成員變量token指向的就是用來描述該Activity組件的一個ActivityRecord對象所實現的一個IBinder接口,而成員變量appWindowToken指向的就是其子類AppWindowToken對象。當另一方面,當WindowToken類是用來描述非Activity組件窗口的時候,它的成員變量appWindowToken的值就會等于null。這樣,我們就可以通過WindowToken類的成員變量appWindowToken的值來判斷一個WindowToken對象是否是用來描述一個Activity組件窗口的,即是否是用來描述一個應用程序窗口的。
上面所描述的Activity組件在ActivityManagerService服務和WindowManagerService服務之間以及應用程序進程和WindowManagerService服務之間的連接模型比較抽象,接下來,我們再通過三個過程來分析它們彼此之間的連接模型,如下所示:
1. ActivityManagerService服務請求WindowManagerService服務為一個Activity組件創建一個AppWindowToken對象的過程;
2. 應用程序進程請求WindowManagerService服務創建一個Session對象的過程;
3. 應用程序進程請求WindowManagerService服務為一個Activity組件創建一個WindowState對象的過程。
通過這三個過程的分析,我們就可以對應用程序進程、ActivityManagerService服務和WindowManagerService服務的關系有一個深刻的認識了。
#### **一. AppWindowToken對象的創建過程**
從前面Android應用程序啟動過程源代碼分析一文的Step 9可以知道,Activity組件在啟動的過程中,會調用到ActivityStack類的成員函數startActivityLocked,該函數會請求WindowManagerService服務為當前正在啟動的Activity組件創建一個AppWindowToken對象。接下來,我們就從ActivityStack類的成員函數startActivityLocked開始分析一個AppWindowToken對象的創建過程,如圖5所示:
:-: 
圖5 AppWindowToken對象的創建過程
這個過程可以分為3步,接下來我們就詳細分析每一個步驟。
**Step 1. ActivityStack.startActivityLocked**
~~~
public class ActivityStack {
......
final ActivityManagerService mService;
......
final ArrayList mHistory = new ArrayList();
......
private final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume) {
final int NH = mHistory.size();
int addPos = -1;
if (!newTask) {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int i = NH-1; i >= 0; i--) {
ActivityRecord p = (ActivityRecord)mHistory.get(i);
if (p.finishing) {
continue;
}
if (p.task == r.task) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
addPos = i+1;
if (!startIt) {
mHistory.add(addPos, r);
......
mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
......
return;
}
break;
}
if (p.fullscreen) {
startIt = false;
}
}
}
// Place a new activity at top of stack, so it is next to interact
// with the user.
if (addPos < 0) {
addPos = NH;
}
......
// Slot the activity into the history stack and proceed
mHistory.add(addPos, r);
......
if (NH > 0) {
......
mService.mWindowManager.addAppToken(
addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
.....
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
}
......
if (doResume) {
resumeTopActivityLocked(null);
}
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/am/ActivityStack.java中。
參數r是一個ActivityRecord對象,用來描述的是要啟動的Activity組件,參數newTask是一個布爾變量,用來描述要啟動的Activity組件是否是在新任務中啟動的,參數doResume也是一個布爾變量,用來描述是否需要馬上將Activity組件啟動起來。
ActivityStack類的成員變量mService指向的是系統的ActivityManagerService,另外一個成員變量mHistory是一個數組列表,用來描述系統的Activity組件堆棧。
當參數newTask的值等于false時,就說明參數r所描述的Activity組件是在已有的一個任務中啟動的,因此,這時候ActivityStack類的成員函數startActivityLocked就會從上到下遍歷保存成員變量mHistory,找到一個已有的Activity組件,它與參數r所描述的Activity組件是屬于同一個任務的,即它們的成員變量task的值相等。找到這樣的一個Activity組件之后,如果位于它上面的其它Activity組件的窗口至少有一個全屏的,即變量startIt的值等于true,那么ActivityStack類的成員函數startActivityLocked就只是將參數r所描述的Activity組件加入到成員變量mHistory所描述的一個Activity組件堆棧中,以及調用成員變量mService所描述的ActivityManagerService服務的成員變量mWindowManager所描述的WindowManagerService服務的成員函數addAppToken來為它創建一個AppWindowToken對象,然后就返回了,即不會執行下面的代碼來啟動參數r所描述的Activity組件。這相當于是延遲到參數r所描述的Activity組件可見時,才將它啟動起來。
當參數newTask的值等于true時,就說明參數r所描述的Activity組件是在一個任務中啟動的,這時候ActivityStack類的成員函數startActivityLocked就會首先將它添加到成員變量mHistory所描述的一個Activity組件堆棧,接著再判斷它是否是系統中第一個啟動的Activity組件。如果是系統中第一個啟動的Activity組件,那么ActivityStack類的成員函數startActivityLocked就只是簡單地調用WindowManagerService服務的成員函數addAppToken來為它創建一個AppWindowToken對象就完事了。如果不是系統系統中第一個啟動的Activity組件,那么ActivityStack類的成員函數startActivityLocked除了會調用WindowManagerService服務的成員函數addAppToken來為它創建一個AppWindowToken對象之外,還會為它創建一些啟動動畫等,我們忽略這些代碼。
從上面的分析就可以看出,無論如何,ActivityStack類的成員函數startActivityLocked都會調用WindowManagerService服務的成員函數addAppToken為正在啟動的Activity組件創建一個AppWindowToken對象。創建完成這個AppWindowToken對象之后,如果參數doResume的值等于true,那么ActivityStack類的成員函數startActivityLocked就會繼續調用另外一個成員函數resumeTopActivityLocked來繼續執行啟動參數r所描述的一個Activity組件,這一步可以參考前面Android應用程序啟動過程源代碼分析一文的Step 10。
接下來,我們就繼續分析WindowManagerService類的成員函數addAppToken的實現,以便可以了解WindowManagerService服務是如何為一個Activity組件創建一個AppWindowToken對象的。
**Step 2. WindowManagerService.addAppToken**
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
/**
* Mapping from a token IBinder to a WindowToken object.
*/
final HashMap<IBinder, WindowToken> mTokenMap =
new HashMap<IBinder, WindowToken>();
/**
* The same tokens as mTokenMap, stored in a list for efficient iteration
* over them.
*/
final ArrayList<WindowToken> mTokenList = new ArrayList<WindowToken>();
......
/**
* Z-ordered (bottom-most first) list of all application tokens, for
* controlling the ordering of windows in different applications. This
* contains WindowToken objects.
*/
final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
......
public void addAppToken(int addPos, IApplicationToken token,
int groupId, int requestedOrientation, boolean fullscreen) {
......
long inputDispatchingTimeoutNanos;
try {
inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
} catch (RemoteException ex) {
......
inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
}
synchronized(mWindowMap) {
AppWindowToken wtoken = findAppWindowToken(token.asBinder());
if (wtoken != null) {
......
return;
}
wtoken = new AppWindowToken(token);
wtoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
wtoken.groupId = groupId;
wtoken.appFullscreen = fullscreen;
wtoken.requestedOrientation = requestedOrientation;
mAppTokens.add(addPos, wtoken);
......
mTokenMap.put(token.asBinder(), wtoken);
mTokenList.add(wtoken);
// Application tokens start out hidden.
wtoken.hidden = true;
wtoken.hiddenRequested = true;
//dump();
}
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService類有三個成員變量mTokenMap、mTokenList和mAppTokens,它們都是用來描述系統中的窗口的。
成員變量mTokenMap指向的是一個HashMap,它里面保存的是一系列的WindowToken對象,每一個WindowToken對象都是用來描述一個窗口的,并且是以描述這些窗口的一個Binder對象的IBinder接口為鍵值的。例如,對于Activity組件類型的窗口來說,它們分別是以用來描述它們的一個ActivityRecord對象的IBinder接口保存在成員變量mTokenMap所指向的一個HashMap中的。
成員變量mTokenList指向的是一個ArrayList,它里面保存的也是一系列WindowToken對象,這些WindowToken對象與保存在成員變量mTokenMap所指向的一個HashMap中的WindowToken對象是一樣的。成員變量mTokenMap和成員變量mTokenList的區別就在于,前者在給定一個IBinder接口的情況下,可以迅速指出是否存在一個對應的窗口,而后者可以迅速遍歷系統中的窗口。
成員變量mAppTokens指向的也是一個ArrayList,不過它里面保存的是一系列AppWindowToken對象,每一個AppWindowToken對象都是用來描述一個Activity組件的窗口的,而這些AppWindowToken對象是以它們描述的窗口的Z軸坐標由小到大保存在這個ArrayList中的,這樣我們就可以通過這個ArrayList來從上到下或者從下到上地遍歷系統中的所有Activity組件窗口。由于這些AppWindowToken對象所描述的Activity組件窗口也是一個窗口,并且AppWindowToken類是從WindowToken繼承下來的,因此,這些AppWindowToken對象還會同時被保存在成員變量mTokenMap所指向的一個HashMap和成員變量mTokenList所指向的一個ArrayList中。
理解了WindowManagerService類的成員變量mTokenMap、mTokenList和mAppTokens的作用之后,WindowManagerService類的成員函數addAppToken的實現就容易理解了。由于參數token描述的是一個Activity組件窗口,因此,函數就會為它創建一個AppWindowToken對象,并且將這個AppWindowToken對象分別保存在 WindowManagerService類的三個成員變量mTokenMap、mTokenList和mAppTokens中。不過在創建對象,首先會檢查與參數token所對應的AppWindowToken對象已經存在。如果已經存在,就什么也不做就返回了。注意,參數addPos用來指定參數token描述的是一個Activity組件在系統Activity組件堆棧中的位置,這個位置同時也指定了為該Activity組件在成員變量成員變量mAppTokens所指向的一個ArrayList中的位置。由于保存在系統Activity組件堆棧的Activity組件本來就是按照它們的Z軸坐標從小到大的順序來排列的,因此,保存在成員變量mAppTokens所指向的一個ArrayList中的AppWindowToken對象也是按照它們的Z軸坐標從小到大的順序來排列的。
函數在為參數token所描述一個Activity組件窗口創建了一個AppWindowToken對象之后,還會初始化它的一系列成員變量,這些成員變量的含義如下所示:
1. inputDispatchingTimeoutNanos,表示Activity組件窗口收到了一個IO輸入事件之后,如果沒有在規定的時間內處理完成該事件,那么系統就認為超時。這個超時值可以由Activity組件本身來指定,即可以通過調用一個對應的ActivityRecord對象的成員函數getKeyDispatchingTimeout來獲得。假如Activity組件沒有指定的話,那么就會使用默認值DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS,即5000 * 1000000納秒。
2. groupId,表示Activity組件所屬的任務的ID。從前面Android應用程序啟動過程源代碼分析一文可以知道,每一個Activity組件都是屬于某一個任務的,而每一個任務都用來描述一組相關的Activity組件的,這些Activity組件用來完成用戶的某一個操作。
3. appFullscreen,表示Activity組件的窗口是否是全屏的。如果一個Activity組件的窗口是全屏的,那么它就會將位于它下面的所有窗口都擋住,這樣就可以在渲染系統UI時進行優化,即不用渲染位于全屏窗口以下的其它窗口。
4. requestedOrientation,表示Activity組件所請求的方向。這個方向可以是橫的(LANDSCAPE),也可以是豎的(PORTRAIT)。
5. hidden,表示Activity組件是否是處于不可見狀態。
6. hiddenRequested,與hidden差不多,也是表示Activity組件是否是處于不可見狀態。兩者的區別在于,在設置目標Activity組件的可見狀態時,如果系統等待執行Activity組件切換操作,那么目標Activity組件的可見狀態不會馬上被設置,即它的hidden值不會馬上被設置,而只是設置它的hiddenRequested值,表示它的可見性狀態正在等待被設置。等到系統執行完成Activity組件切換操作之后,兩者的值就會一致了。
接下來,我們繼續分析一個AppWindowToken對象的創建過程,它AppWindowToken類的構造函數的實現。
**Step 3. new AppWindowToken**
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
class WindowToken {
// The actual token.
final IBinder token;
// The type of window this token is for, as per WindowManager.LayoutParams.
final int windowType;
// Set if this token was explicitly added by a client, so should
// not be removed when all windows are removed.
final boolean explicit;
......
// If this is an AppWindowToken, this is non-null.
AppWindowToken appWindowToken;
......
WindowToken(IBinder _token, int type, boolean _explicit) {
token = _token;
windowType = type;
explicit = _explicit;
}
......
}
class AppWindowToken extends WindowToken {
// Non-null only for application tokens.
final IApplicationToken appToken;
......
AppWindowToken(IApplicationToken _token) {
super(_token.asBinder(),
WindowManager.LayoutParams.TYPE_APPLICATION, true);
appWindowToken = this;
appToken = _token;
}
......
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
AppWindowToken類的構造函數首先調用父類WindowToken的構造函數來執行父類的初始化工作,然后從父類WindowToken繼承下來的成員變量appWindowToken以及自己的成員變量appToken的值。參數_token指向的是一個ActivityRecord對象的IBinder接口,因此,AppWindowToken類的成員變量appToken描述的就是一個ActivityRecord對象。
WindowToken類的構造函數用來初始化token、windowType和explicit這三個成員變量。在我們這個場景中,成員變量token指向的也是一個ActivityRecord對象的IBinder接口,用來標志一個Activity組件的窗口,成員變量windowType用來描述窗口的類型,它的值等于WindowManager.LayoutParams.TYPE_APPLICATION,表示這是一個Activity組件窗口,成員變量explicit用來表示窗口是否是由應用程序進程請求添加的。
注意,當一個WindowToken對象的成員變量appWindowToken的值不等于null時,就表示它實際描述的是Activity組件窗口,并且這個成員變量指向的就是與該Activity組件所關聯的一個AppWindowToken對象。
至此,我們就分析完成一個AppWindowToken對象的創建過程了,通過這個過程我們就可以知道,每一個Activity組件,在ActivityManagerService服務內部都有一個對應的ActivityRecord對象,并且在WindowManagerService服務內部關聯有一個AppWindowToken對象。
#### **二. Session對象的創建過程**
應用程序進程在啟動第一個Activity組件的時候,就會請求與WindowManagerService服務建立一個連接,以便可以配合WindowManagerService服務來管理系統中的所有窗口。具體來說,就是應用程序進程在為它里面啟動的第一個Activity組件的視圖對象創建一個關聯的ViewRoot對象的時候,就會向WindowManagerService服務請求返回一個類型為Session的Binder本地對象,這樣應用程序進程就可以獲得一個類型為Session的Binder代理對象,以后就可以通過這個Binder代理對象來和WindowManagerService服務進行通信了。
從前面Android應用程序窗口(Activity)的視圖對象(View)的創建過程分析一文可以知道,應用程序進程在為它里面啟動的Activity組件的視圖對象創建關聯ViewRoot對象是通過調用WindowManagerImpl類的成員函數addView來實現的,因此,接下來我們就從WindowManagerImpl類的成員函數addView開始分析應用程序進程與WindowManagerService服務的連接過程,即一個Session對象的創建過程,如圖6所示:
:-: 
圖6 Session對象的創建過程
這個過程可以分為5個步驟,接下來我們就詳細分析每一個步驟。
**Step 1. WindowManagerImpl.addView**
~~~
public class WindowManagerImpl implements WindowManager {
......
private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
{
......
ViewRoot root;
......
synchronized (this) {
......
root = new ViewRoot(view.getContext());
......
}
// do this last because it fires off messages to start doing things
root.setView(view, wparams, panelParentView);
}
......
}
~~~
這個函數定義在文件frameworks/base/core/java/android/view/WindowManagerImpl.java中。
這里的參數view即為正在啟動的Activity組件的視圖對象,WindowManagerImpl類的成員函數addView的目標就是為它創建一個ViewRoot對象。這里我們只關注這個ViewRoot對象的創建過程,即ViewRoot類的構造函數的實現,WindowManagerImpl類的成員函數addView的詳細實現可以參考前面Android應用程序窗口(Activity)的視圖對象(View)的創建過程分析一文的Step 12。
**Step 2. new ViewRoot**
~~~
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
public ViewRoot(Context context) {
super();
......
// Initialize the statics when this class is first instantiated. This is
// done here instead of in the static block because Zygote does not
// allow the spawning of threads.
getWindowSession(context.getMainLooper());
......
}
......
}
~~~
這個函數定義在文件frameworks/base/core/java/android/view/ViewRoot.java文件中。
ViewRoot類的構造函數是通過調用靜態成員函數getWindowSession來請求WindowManagerService服務為應用程序進程創建一個返回一個類型為Session的Binder本地對象的,因此,接下來我們就繼續分析ViewRoot類的靜態成員函數getWindowSession的實現。
**Step 3. ViewRoot.getWindowSession**
~~~
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
static IWindowSession sWindowSession;
static final Object mStaticInit = new Object();
static boolean mInitialized = false;
......
public static IWindowSession getWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(imm.getClient(), imm.getInputContext());
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
......
}
~~~
這個函數定義在文件frameworks/base/core/java/android/view/ViewRoot.java文件中。
ViewRoot類的靜態成員函數getWindowSession首先獲得獲得應用程序所使用的輸入法管理器,接著再獲得系統中的WindowManagerService服務的一個Binder代理對象。有了這個Binder代理對象之后,就可以調用它的成員函數openSession來請求WindowManagerService服務返回一個類型為Session的Binder本地對象。這個Binder本地對象返回來之后,就變成了一個類型為Session的Binder代理代象,即一個實現了IWindowSession接口的Binder代理代象,并且保存在ViewRoot類的靜態成員變量sWindowSession中。在請求WindowManagerService服務返回一個類型為Session的Binder本地對象的時候,應用程序進程傳遞給WindowManagerService服務的參數有兩個,一個是實現IInputMethodClient接口的輸入法客戶端對象,另外一個是實現了IInputContext接口的一個輸入法上下文對象,它們分別是通過調用前面所獲得的一個輸入法管理器的成員函數getClient和getInputContext來獲得的。
從這里就可以看出,只有當ViewRoot類的靜態成員函數getWindowSession第一次被調用的時候,應用程序進程才會請求WindowManagerService服務返回一個類型為Session的Binder本地對象。又由于ViewRoot類的靜態成員函數getWindowSession第一次被調用的時候,正好是處于應用程序進程中的第一個Activity組件啟動的過程中,因此,應用程序進程是在啟動第一個Activity組件的時候,才會請求與WindowManagerService服務建立連接。一旦連接建立起來之后,ViewRoot類的靜態成員變量mInitialized的值就會等于true,并且另外一個靜態成員變量sWindowSession的值不等于null。同時,ViewRoot類的靜態成員函數getWindowSession是線程安全的,這樣就可以避免多個線程同時調用它來重復請求WindowManagerService服務為當前應用程序進程創建連接。
接下來,我們就繼續分析求WindowManagerService類的成員函數openSession的實現,以便可以了解一個Session對象的創建過程。
**Step 4. indowManagerService.openSession**
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
public IWindowSession openSession(IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(client, inputContext);
return session;
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowManagerService類的成員函數openSession的實現很簡單,它以應用程序進程傳遞過來的一個輸入法客戶端對象和一個輸入法上下文對象來參數,來創建一個類型為Session的Binder本地對象,并且將這個類型為Session的Binder本地對象返回給應用程序進程。
接下來我們就繼續分析Session類的構造函數的實現,以便可以了解一個Session對象的創建過程。
**Step 5. new Session**
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
final boolean mHaveInputMethods;
......
IInputMethodManager mInputMethodManager;
......
private final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
final IInputMethodClient mClient;
final IInputContext mInputContext;
......
public Session(IInputMethodClient client, IInputContext inputContext) {
mClient = client;
mInputContext = inputContext;
......
synchronized (mWindowMap) {
if (mInputMethodManager == null && mHaveInputMethods) {
IBinder b = ServiceManager.getService(
Context.INPUT_METHOD_SERVICE);
mInputMethodManager = IInputMethodManager.Stub.asInterface(b);
}
}
long ident = Binder.clearCallingIdentity();
try {
// Note: it is safe to call in to the input method manager
// here because we are not holding our lock.
if (mInputMethodManager != null) {
mInputMethodManager.addClient(client, inputContext,
mUid, mPid);
} else {
client.setUsingInputMethod(false);
}
client.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
......
} finally {
Binder.restoreCallingIdentity(ident);
}
}
......
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
Session類有兩個成員變量mClient和mInputContext,分別用來保存在從應用程序進程傳遞過來的一個輸入法客戶端對象和一個輸入法上下文對象,它們是在Session類的構造函數中初始化的。
Session類的構造函數還會檢查WindowManagerService服務是否需要獲得系統中的輸入法管理器服務,即檢查WindowManagerService類的成員變量mHaveInputMethods的值是否等于true。如果這個值等于true,并且WindowManagerService服務還沒有獲得系統中的輸入法管理器服務,即WindowManagerService類的成員變量mInputMethodManager的值等于null,那么Session類的構造函數就會首先獲得這個輸入法管理器服務,并且保存在WindowManagerService類的成員變量mInputMethodManager中。
獲得了系統中的輸入法管理器服務之后,Session類的構造函數就可以調用它的成員函數addClient來為正在請求與WindowManagerService服務建立連接的應用程序進程增加它所使用的輸入法客戶端對象和輸入法上下文對象了。
至此,我們就分析完成一個Session對象的創建過程了,通過這個過程我們就可以知道,每一個應用程序進程在WindowManagerService服務內部都有一個類型為Session的Binder本地對象,用來它與WindowManagerService服務之間的連接,而有了這個連接之后,WindowManagerService服務就可以請求應用進程配合管理系統中的應用程序窗口了。
#### **三. WindowState對象的創建過程**
在Android系統中,WindowManagerService服務負責統一管理系統中的所有窗口,因此,當運行在應用程序進程這一側的Activity組件在啟動完成之后,需要與WindowManagerService服務建立一個連接,以便WindowManagerService服務可以管理它的窗口。具體來說,就是應用程序進程將一個Activitty組件的視圖對象設置到與它所關聯的一個ViewRoot對象的內部的時候,就會將一個實現了IWindow接口的Binder本地對象傳遞WindowManagerService服務。這個實現了IWindow接口的Binder本地對象唯一地標識了一個Activity組件,WindowManagerService服務接收到了這個Binder本地對象之后,就會將它保存在一個新創建的WindowState對象的內部,這樣WindowManagerService服務以后就可以通過它來和Activity組件通信,以便可以要求Activity組件配合來管理系系統中的所有窗口。
從前面Android應用程序窗口(Activity)的視圖對象(View)的創建過程分析一文可以知道,應用程序進程將一個Activity組件的視圖對象設置到與它所關聯的一個ViewRoot對象的內部是通過調用ViewRoot類的成員函數setView來實現的,因此,接下來我們就從ViewRoot類的成員函數setView開始分析Activity組件與WindowManagerService服務的連接過程,即一個WindowState對象的創建過程,如圖7所示:
:-: 
圖7 WindowState對象的創建過程
這個過程可以分為7個步驟,接下來我們就詳細分析每一個步驟。
**Step 1. ViewRoot.setView**
~~~
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
static IWindowSession sWindowSession;
......
final W mWindow;
View mView;
......
public ViewRoot(Context context) {
super();
......
mWindow = new W(this, context);
......
}
......
public void setView(View view, WindowManager.LayoutParams attrs,
View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
......
try {
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
} catch (RemoteException e) {
......
} finally {
......
}
......
}
......
}
}
......
}
~~~
這個函數定義在文件frameworks/base/core/java/android/view/ViewRoot.java文件中。
這里的參數view即為正在啟動的Activity組件的視圖對象,ViewRoot類的成員函數setView會將它保存成員變量mView中,這樣就可以將一個Activity組件的視圖對象和一個ViewRoot對象關聯起來。ViewRoot類的成員函數setView接下來還會調用靜態成員變量sWindowSession所描述的一個實現了IWindowSession接口的Binder代理對象的成員函數add來請求WindowManagerService服務為正在啟動的Activity組件創建一個WindowState對象。接下來我們就主要關注WindowState對象的創建過程,ViewRoot類的成員函數setView的詳細實現可以參考前面Android應用程序窗口(Activity)的視圖對象(View)的創建過程分析一文的Step 13。
注意,ViewRoot類的成員函數setView在請求WindowManagerService服務為正在啟動的Activity組件創建一個WindowState對象的時候,會傳遞一個類型為W的Binder本地對象給WindowManagerService服務。這個類型為W的Binder本地對象實現了IWindow接口,保存在ViewRoot類的成員變量mWindow中,它是在ViewRoot類的構造函數中創建的,以后WindowManagerService服務就會通過它來和Activity組件通信。
從前面第二部的內容可以知道,ViewRoot類的靜態成員變量sWindowSession所指向的一個Binder代理對象引用的是運行在WindowManagerService服務這一側的一個Session對象,因此,接下來我們就繼續分析Session類的成員函數add的實現,以便可以了解一個WindowState對象的創建過程。
**Step 2. Session.add**
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
private final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
......
public int add(IWindow window, WindowManager.LayoutParams attrs,
int viewVisibility, Rect outContentInsets, InputChannel outInputChannel) {
return addWindow(this, window, attrs, viewVisibility, outContentInsets,
outInputChannel);
}
......
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
Session類的成員函數add的實現很簡單,它只是調用了外部類WindowManagerService的成員函數addWindow來進一步為正在啟動的Activity組件創建一個WindowState對象。
**Step 3. WindowManagerService.addWindow**
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中,它的實現比較長,我們分段來閱讀:
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
public int addWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets, InputChannel outInputChannel) {
......
WindowState attachedWindow = null;
WindowState win = null;
synchronized(mWindowMap) {
......
if (mWindowMap.containsKey(client.asBinder())) {
......
return WindowManagerImpl.ADD_DUPLICATE_ADD;
}
~~~
這段代碼首先在WindowManagerService類的成員變量mWindowMap所描述的一個HashMap中檢查是否存在一個與參數client所對應的WindowState對象,如果已經存在,那么就說明WindowManagerService服務已經為它創建過一個WindowState對象了,因此,這里就不會繼續往前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_DUPLICATE_ADD。
我們繼續往前看代碼:
~~~
if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
attachedWindow = windowForClientLocked(null, attrs.token, false);
if (attachedWindow == null) {
......
return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
}
if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
&& attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
......
return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
}
}
~~~
參數attrs指向的是一個WindowManager.LayoutParams對象,用來描述正在啟動的Activity組件的UI布局,當它的成員變量type的值大于等于FIRST_SUB_WINDOW并且小于等于LAST_SUB_WINDOW的時候,就說明現在要增加的是一個子窗口。在這種情況下,就必須要指定一個父窗口,而這個父窗口是通過數attrs指向的是一個WindowManager.LayoutParams對象的成員變量token來指定的,因此,這段代碼就會調用WindowManagerService類的另外一個成員函數windowForClientLocked來獲得用來描述這個父窗口的一個WindowState對象,并且保存在變量attachedWindow。
如果得到變量attachedWindow的值等于null,那么就說明父窗口不存在,這是不允許的,因此,函數就不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN。另一方面,如果變量attachedWindow的值不等于null,但是它的成員變量mAttrs所指向的一個WindowManager.LayoutParams對象的成員變量type的值也是大于等于FIRST_SUB_WINDOW并且小于等于LAST_SUB_WINDOW,那么也說明找到的父窗口也是一個子窗口,這種情況也是不允許的,因此,函數就不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN。
我們繼續往前看代碼:
~~~
boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);
if (token == null) {
if (attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW) {
......
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
if (attrs.type == TYPE_INPUT_METHOD) {
......
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
if (attrs.type == TYPE_WALLPAPER) {
......
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
token = new WindowToken(attrs.token, -1, false);
addToken = true;
} else if (attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW) {
AppWindowToken atoken = token.appWindowToken;
if (atoken == null) {
......
return WindowManagerImpl.ADD_NOT_APP_TOKEN;
} else if (atoken.removed) {
......
return WindowManagerImpl.ADD_APP_EXITING;
}
if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
// No need for this guy!
......
return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
}
} else if (attrs.type == TYPE_INPUT_METHOD) {
if (token.windowType != TYPE_INPUT_METHOD) {
......
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
} else if (attrs.type == TYPE_WALLPAPER) {
if (token.windowType != TYPE_WALLPAPER) {
......
return WindowManagerImpl.ADD_BAD_APP_TOKEN;
}
}
~~~
這段代碼首先在WindowManagerService類的成員變量mTokenMap所描述的一個HashMap中檢查WindowManagerService服務是否已經為正在增加的窗口創建過一個WindowToken對象了。
如果還沒有創建過WindowToken對,即變量token的值等于null,那么這段代碼就會進一步檢查正在增加的窗口的類型。如果正在增加的窗口是屬于應用程序窗口(FIRST_APPLICATION_WINDOW~LAST_APPLICATION_WINDOW,即Activity組件窗口),或者輸入法窗口(TYPE_INPUT_METHOD),或者壁紙窗口(TYPE_WALLPAPER),那么這三種情況都是不允許的,因此,函數就不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_BAD_APP_TOKEN。例如,對于應用程序窗口來說,與它所對應的Activity組件是在之前就已經由ActivityManagerService服務請求WindowManagerService服務創建過一個AppWindowToken對象了的(AppWindowToken對象也是一個WindowToken對象,因為AppWindowToken類繼承了WindowToken類),這個過程可以參考前面第一部分的內容。如果不是上述三種情況,那么這段代碼就會為正在增加的窗口創建一個WindowToken對象,并且保存在變量token中。
如果已經創建過WindowToken對象,即變量token的值不等于null,那么就說明正在增加的窗口或者是應用程序窗口,或者是輸入法窗口,或者是壁紙窗口。下面我們就為三種情況來討論。
如果是應用程序窗口,從前面第一部分的內容可以知道,WindowToken對象token的成員變量appWindowToken的值必須不能等于null,并且指向的是一個AppWindowToken對象。因此,當WindowToken對象token的成員變量appWindowToken的值等于null的時候,函數就不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_NOT_APP_TOKEN。另一方面,雖然WindowToken對象token的成員變量appWindowToken的值不等于null,但是它所指向的一個AppWindowToken對象的成員變量removed的值等于true時,那么就表示對應的Activity組件已經被移除,在這種情況下,函數也不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_APP_EXITING。還有一種特殊的應用程序窗口,它的類型為TYPE_APPLICATION_STARTING。這種類型的窗口稱為起始窗口,它是在一個Activity組件的窗口顯示出來之前就顯示的。因此,如果當前正在增加的是一個超始窗口,并且它所附屬的應用程序窗口,即變量atoken所描述的應用程序窗口,已經顯示出來了,即變量atoken所指向的一個AppWindowToken對象的成員變量firstWindowDrawn的值等于true,那么函數也不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_STARTING_NOT_NEEDED。
如果是輸入法窗口,但是參數attrs所描述的一個WindowManager.LayoutParams對象的成員變量windowType的值不等于TYPE_INPUT_METHOD,那么指定的窗口類型就是不匹配的。在這種情況下,函數就不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_BAD_APP_TOKEN。
如果是壁紙窗口,但是參數attrs所描述的一個WindowManager.LayoutParams對象的成員變量windowType的值不等于TYPE_WALLPAPER,那么指定的窗口類型就是不匹配的。在這種情況下,函數也不會繼續向前執行,而是直接返回一個錯誤碼WindowManagerImpl.ADD_BAD_APP_TOKEN。
我們繼續往前看代碼:
~~~
win = new WindowState(session, client, token,
attachedWindow, attrs, viewVisibility);
......
mPolicy.adjustWindowParamsLw(win.mAttrs);
res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerImpl.ADD_OKAY) {
return res;
}
~~~
通過上面的合法性檢查之后,這里就可以為正在增加的窗口創建一個WindowState對象了。
WindowManagerService類的成員變量mPolicy指向的是一個實現了WindowManagerPolicy接口的窗口管理策略器。在Phone平臺中,這個窗口管理策略器是由com.android.internal.policy.impl.PhoneWindowManager來實現的,它負責對系統中的窗口實現制定一些規則。這里主要是調用窗口管理策略器的成員函數adjustWindowParamsLw來調整當前正在增加的窗口的布局參數,以及調用成員函數prepareAddWindowLw來檢查當前應用程序進程請求增加的窗口是否是合法的。如果不是合法的,即變量res的值不等于WindowManagerImpl.ADD_OKAY,那么函數就不會繼續向前執行,而直接返回錯誤碼res。
WindowState對象的創建過程我們在接下來的Step 4中再分析,現在我們繼續向前看代碼:
~~~
if (outInputChannel != null) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.mInputChannel = inputChannels[0];
inputChannels[1].transferToBinderOutParameter(outInputChannel);
mInputManager.registerInputChannel(win.mInputChannel);
}
~~~
這段代碼是用創建IO輸入事件連接通道的,以便正在增加的窗口可以接收到系統所發生的鍵盤和觸摸屏事件,可以參考前面Android應用程序鍵盤(Keyboard)消息處理機制分析一文,這里不再詳述。
我們繼續向前看代碼:
~~~
if (addToken) {
mTokenMap.put(attrs.token, token);
mTokenList.add(token);
}
win.attach();
mWindowMap.put(client.asBinder(), win);
if (attrs.type == TYPE_APPLICATION_STARTING &&
token.appWindowToken != null) {
token.appWindowToken.startingWindow = win;
}
~~~
這段代碼首先檢查變量addToken的值是否等于true。如果等于true的話,那么就說明變量token所指向的一個WindowToken對象是在前面新創建的。在這種情況下,就需要將這個新創建的WindowToken對象分別添加到WindowManagerService類的成員變量mTokeMap和mTokenList分別描述的一個HashMap和一個ArrayList中去。
這段代碼接下來再調用前面所創建的一個WindowState對象win的成員函數attach來為當前正在增加的窗口創建一個用來連接到SurfaceFlinger服務的SurfaceSession對象。有了這個SurfaceSession對象之后,當前正在增加的窗口就可以和SurfaceFlinger服務通信了。在接下來的Step 5中,我們再詳細分析WindowState類的成員函數attach的實現。
這段代碼最后還做了兩件事情。第一件事情是將前面所創建的一個WindowState對象win添加到WindowManagerService類的成員變量mWindowMap所描述的一個HashMap中,這是以參數所描述的一個類型為W的Binder代理對象的IBinder接口來鍵值來保存的。第二件事情是檢查當前正在增加的是否是一個起始窗口,如果是的話,那么就會將前面所創建的一個WindowState對象win設置到用來描述它所屬的Activity組件的一個AppWindowToken對象的成員變量startingWindow中去,這樣系統就可以在顯示這個Activity組件的窗口之前,先顯示該起始窗口。
我們繼續向前看代碼:
~~~
boolean imMayMove = true;
if (attrs.type == TYPE_INPUT_METHOD) {
mInputMethodWindow = win;
addInputMethodWindowToListLocked(win);
imMayMove = false;
} else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) {
mInputMethodDialogs.add(win);
addWindowToListInOrderLocked(win, true);
adjustInputMethodDialogsLocked();
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
if (attrs.type == TYPE_WALLPAPER) {
......
adjustWallpaperWindowsLocked();
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
adjustWallpaperWindowsLocked();
}
}
~~~
WindowManagerService類有一個成員變量mWindows,它是一個類型為WindowState的ArrayList,保存在它里面的WindowState對象所描述的窗口是按照它們的Z軸坐標從小到大的順序來排列的。現在我們需要考慮將用來描述當前正在增加的窗口的WindowState對象win添加到這個ArrayList的合適位置中去。我們分三種情況考慮。
如果當前正在增加的窗口是一個輸入法窗口,那么WindowManagerService服務就需要按照Z軸坐標從大到小的順序來檢查當前是哪一個窗口是需要輸入法窗口的。找到了這個位于最上面的需要輸入法窗口的窗口之后,就可以將輸入法窗口放置在它的上面了,即可以將WindowState對象win添加到WindowManagerService類的成員變量mWindows所描述的一個ArrayList的合適位置了。這兩個操作是通過調用WindowManagerService類的成員函數addInputMethodWindowToListLocked來實現的。同時,WindowManagerService類的成員變量mInputMethodWindow指向的是系統當前正在使用的輸入法窗口,因此,在這種情況下,我們還需要將WindowState對象win保存在它里面。
如果當前正在添加的窗口是一個輸入法對話框,那么WindowManagerService服務就需要做兩件事情。第一件事情是將WindowState對象win添加到WindowManagerService類的成員變量mWindows所描述的一個ArrayList中去,這是通過調用WindowManagerService類的成員函數addWindowToListInOrderLocked來實現的。第二件事情是調用WindowManagerService類的成員函數adjustInputMethodDialogsLocked來調整正在增加的輸入法對話框在WindowManagerService類的成員變量mWindows所描述的一個ArrayList中的位置,使得它位于輸入法窗口的上面。
在上述兩種情況下,系統的輸入法窗口和輸入法對話框的位置都是得到合適的調整的了,因此,這段代碼就會將變量imMayMove的值設置為false,表示后面不需要再調整輸入法窗口和輸入法對話框的位置了。
如果當前正在添加的窗口是一個應用程序窗口或者壁紙窗口,那么WindowManagerService服務都需要將WindowState對象win添加到WindowManagerService類的成員變量mWindows所描述的一個ArrayList中去。添加完成之后,如果發現當前添加的窗口是一個壁紙窗口或者當前添加的是一個需要顯示壁紙的應用程序窗口,那么WindowManagerService服務還需要進一步調整系統中已經添加了的壁紙窗口的Z軸位置,使得它們位于最上面的需要顯示壁紙的窗口的下面,這是通過調用WindowManagerService類的成員函數adjustWallpaperWindowsLocked來實現的。
我們繼續向前看代碼:
~~~
win.mEnterAnimationPending = true;
mPolicy.getContentInsetHintLw(attrs, outContentInsets);
if (mInTouchMode) {
res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
}
if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
}
~~~
這段代碼做了四件事情。
第一件事情是將前面所創建的一個WindowState對象win的成員變量mEnterAnimationPending的值設置為true,表示當前正在增加的窗口需要顯示一個進入動畫。
第二件事情是調用WindowManagerService類的成員變量mPolicy所描述的一個窗口管理策略器的成員函數getContentInsetHintLw來獲得當前正在增加的窗口的UI內容邊襯大小,即當前正在增加的窗口可以在屏幕中所獲得的用來顯示UI內容的區域的大小,這通常是要排除屏幕邊框和狀態欄等所占據的屏幕區域。
第三件事情是檢查WindowManagerService類的成員變量mInTouchMode的值是否等于true。如果等于true的話,那么就說明系統運行在觸摸屏模式中,這時候這段代碼就會將返回值res的WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE位設置為1。
第四件事情是檢查當前正在增加的窗口是否是處于可見的狀態。從第二個if語句可以看出,由于WindowState對象win的值在這里不可以等于null,因此,這里只有兩種情況下,前正在增加的窗口是處于可見狀態的。第一種情況是WindowState對象的成員變量mAppToken的值等于null,這表明當前正在增加的窗口不是一個應用程序窗口,即不是一個Activity組件窗口,那么它就有可能是一個子窗口。由于子窗口通常是在其父窗口處于可見的狀態下才會創建的,因此,這個子窗口就需要馬上顯示出來的,即需要將它的狀態設置為可見的。第二種情況是WindowState對象的成員變量mAppToken的值不等于null,這表明當前正在增加的窗口是一個應用程序窗口。在這種情況下,WindowState對象的成員變量mAppToken指向的就是一個AppWindowToken對象。當這個AppWindowToken對象的成員變量clientHidden的值等于false的時候,就表明它所描述的一個Activity組件是處于可見狀態的,因此,這時候就需要將該Activity組件的窗口(即當前正在增加的窗口)的狀態設置為可見的。在當前正在增加的窗口是處于可見狀態的情況下,這段代碼就會將返回值res的WindowManagerImpl.ADD_FLAG_APP_VISIBLE位設置為1。
我們繼續向前看最后一段代碼:
~~~
boolean focusChanged = false;
if (win.canReceiveKeys()) {
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS);
if (focusChanged) {
imMayMove = false;
}
}
if (imMayMove) {
moveInputMethodWindowsIfNeededLocked(false);
}
assignLayersLocked();
......
if (focusChanged) {
finishUpdateFocusedWindowAfterAssignLayersLocked();
}
......
}
...
return res;
}
......
~~~
最后一段代碼做了以下五件事情。
第一件事情是檢查當前正在增加的窗口是否是能夠接收IO輸入事件的,即鍵盤輸入事件或者觸摸屏輸入事件。如果可以的話,那么就需要調用WindowManagerService類的成員函數updateFocusedWindowLocked來調整系統當前獲得輸入焦點的窗口,因為當前正在增加的窗口可能會成為新的可以獲得輸入焦點的窗口。如果WindowManagerService類的成員函數updateFocusedWindowLocked的返回值等于true,那么就表明系統當前獲得輸入焦點的窗口發生了變化。在這種情況下,WindowManagerService類的成員函數updateFocusedWindowLocked也會順便調整輸入法窗口的位置,使得它位于系統當前獲得輸入焦點的窗口的上面,因此,這時候這段代碼也會將變量imMayMove的值設置為false,表示接下來不用調整輸入法窗口的位置了。
第二件事情是檢查變量imMayMove的值是否等于true。如果等于true的話,那么就說明當前正在增加的窗口可能已經影響到系統的輸入法窗口的Z軸位置了,因此,這段代碼就需要調用WindowManagerService類的成員函數moveInputMethodWindowsIfNeededLocked來重新調整調整輸入法窗口的Z軸位置,使得它可以位于最上面的那個需要輸入法窗口的窗口的上面。
第三件事情是調用WindowManagerService類的成員函數assignLayersLocked來調整系統中所有窗口的Z軸位置,這也是因為當前正在增加的窗口可能已經影響到系統中所有窗口的Z軸位置了。例如,假如當前增加的是一個正在啟動的Activity組件的窗口,那么這個窗口的Z軸位置就應該是最大的,以便可以在最上面顯示。又如,假如當前增加的是一個子窗口,那么這個子窗口就應該位于它的父窗口的上面。這些都要求重新調整系統中所有窗口的Z軸位置,以便每一個窗口都可以在一個正確的位置上來顯示。
第四件事情檢查變量focusChanged的值是否等于true。如果等于true的話,那么就說明系統中獲得輸入焦點的窗口已經發生了變化。在這種情況下,這段代碼就會調用WindowManagerService類的成員函數finishUpdateFocusedWindowAfterAssignLayersLocked來通知系統IO輸入管理器,新的獲得焦點的窗口是哪一個,以便系統IO輸入管理器接下來可以將鍵盤輸入事件或者觸摸屏輸入事件分發給新的獲得焦點的窗口來處理。WindowManagerService類的成員函數finishUpdateFocusedWindowAfterAssignLayersLocked的實現可以參考前面Android應用程序鍵盤(Keyboard)消息處理機制分析一文,這里不再詳述。
第五件事情是變量res的值返回給應用程序進程,以便它可以知道請求WindowManagerService服務增加一個窗口的執行情況。
至此,WindowManagerService類的成員函數addWindow的實現就分析完成了,接下來我們就繼續分析WindowState類的構造函數和成員函數attach的實現,以便可以了解一個WindowSate對象及其相關聯的一個SurfaceSession對象的創建過程。
**Step 4. new WindowState**
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中,它的實現比較長,我們分段來閱讀:
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
private final class WindowState implements WindowManagerPolicy.WindowState {
......
WindowState(Session s, IWindow c, WindowToken token,
WindowState attachedWindow, WindowManager.LayoutParams a,
int viewVisibility) {
mSession = s;
mClient = c;
mToken = token;
mAttrs.copyFrom(a);
mViewVisibility = viewVisibility;
DeathRecipient deathRecipient = new DeathRecipient();
mAlpha = a.alpha;
~~~
這段代碼初始化WindowState類的以下六個成員變量:
* mSession:指向一個類型為Session的Binder本地對象,使用參數s來初始化,表示當前所創建的WindowState對象是屬于哪一個應用程序進程的。
* mClient:指向一個實現了IWindow接口的Binder代理對象,它引用了運行在應用程序進程這一側的一個類型為W的Binder本地對象,使用參數c來初始化,通過它可以與運行在應用程序進程這一側的Activity組件進行通信。
* mToken:指向一個WindowToken對象,使用參數token來初始化,通過它就可以知道唯一地標識一個窗口。
* mAttrs:指向一個WindowManager.LayoutParams對象,使用參數a來初始化,通過它就可以知道當前當前所創建的WindowState對象所描述的窗口的布局參數。
* mViewVisibility:這是一個整型變量,使用參數viewVisibility來初始化,表示當前所創建的WindowState對象所描述的窗口視圖的可見性。
* mAlpha:這是一個浮點數,使用參數a所描述的一WindowManager.LayoutParams對象的成員變量alpha來初始化,表示當前所創建的WindowState對象所描述的窗口的Alpha通道。
此外,這段代碼還創建了一個類型為DeathRecipient的死亡通知接收者deathRecipient,它是用來監控參數c所引用的一個類型為W的Binder本地對象的生命周期的。當這個Binder本地對象死亡的時候,就意味著當前所創建的WindowState對象所描述的窗口所在的應用程序進程已經退出了。接下來的這段代碼就是用來注冊死亡通知接收者deathRecipient的,如下所示:
~~~
try {
c.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
mDeathRecipient = null;
mAttachedWindow = null;
mLayoutAttached = false;
mIsImWindow = false;
mIsWallpaper = false;
mIsFloatingLayer = false;
mBaseLayer = 0;
mSubLayer = 0;
return;
}
mDeathRecipient = deathRecipient;
~~~
注冊完成之后,前面所創建的死亡通知接收者deathRecipient就會保存在WindowState類的成員變量mDeathRecipientk 。
我們繼續向前看代碼:
~~~
if ((mAttrs.type >= FIRST_SUB_WINDOW &&
mAttrs.type <= LAST_SUB_WINDOW)) {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.windowTypeToLayerLw(
attachedWindow.mAttrs.type) * TYPE_LAYER_MULTIPLIER
+ TYPE_LAYER_OFFSET;
mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
mAttachedWindow = attachedWindow;
mAttachedWindow.mChildWindows.add(this);
mLayoutAttached = mAttrs.type !=
WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
mIsImWindow = attachedWindow.mAttrs.type == TYPE_INPUT_METHOD
|| attachedWindow.mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = attachedWindow.mAttrs.type == TYPE_WALLPAPER;
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
} else {
// The multiplier here is to reserve space for multiple
// windows in the same type layer.
mBaseLayer = mPolicy.windowTypeToLayerLw(a.type)
* TYPE_LAYER_MULTIPLIER
+ TYPE_LAYER_OFFSET;
mSubLayer = 0;
mAttachedWindow = null;
mLayoutAttached = false;
mIsImWindow = mAttrs.type == TYPE_INPUT_METHOD
|| mAttrs.type == TYPE_INPUT_METHOD_DIALOG;
mIsWallpaper = mAttrs.type == TYPE_WALLPAPER;
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
}
~~~
這段代碼初始化WindowState類的以下七個成員變量:
* mBaseLayer:這是一個整型變量,用來描述一個窗口的基礎Z軸位置值,這個值是與窗口類型相關的。對于子窗口來說,它的值由父窗口的基礎Z軸位置值乘以常量TYPE_LAYER_MULTIPLIER再加固定偏移量TYPE_LAYER_OFFSET得到;對于非子窗口來說,它的值就是由窗口的類型來決定的。一個窗口的基礎Z軸位置值是通過調用WindowManagerService類的成員變量mPolicy所描述的一個窗口管理策略器的成員函數windowTypeToLayerLw來獲得的,而窗口管理策略器的成員函數windowTypeToLayerLw主要是根據窗口的類型來決定它的基礎Z軸位置值的。
* mSubLayer:這是一個整型變量,用來描述一個子窗口相對其父窗口的Z軸偏移值。對于非子窗口來說,這個值固定為0;對于子窗口來說,這個值是由WindowManagerService類的成員變量mPolicy所描述的一個窗口管理策略器的成員函數subWindowTypeToLayerLw來獲得的,而窗口管理策略器的成員函數subWindowTypeToLayerLw主要是根據子窗口的類型來決定它相對其父窗口的Z軸偏移值的。
* mAttachedWindow:指向一個WindowState對象,用來描述一個子窗口的父窗口。對于非子窗口來說,這個值固定為null;對于子窗口來說, 這個值使用參數attachedWindow來初始化。如果當前所創建的WindowState對象所描述的窗口是一個子窗口,那么這個子窗口還會被添加用來描述它的父窗口的一WindowState對象的成員變量mChildWindows所描述的一個子窗口列表中去。
* mLayoutAttached:這是一個布爾變量,用來描述一個子窗口的視圖是否是嵌入在父窗口的視圖里面的。對于非子窗口來說,這個值固定為false;對于子窗口來說,這個值只有子窗口的類型是非對話框時,它的值才會等于true,否則都等于false。
* mIsImWindow:這是一個布爾變量,表示當前所創建的WindowState對象所描述的窗口是否是一個輸入法窗口或者一個輸入法對話框。
* mIsWallpaper :這是一個布爾變量,表示當前所創建的WindowState對象所描述的窗口是否是一個壁紙窗口。
* mIsFloatingLayer :這是一個布爾變量,表示當前所創建的WindowState對象所描述的窗口是否是一個浮動窗口。當一個窗口是一個輸入法窗口、輸入法對話框口或者壁紙窗口時,它才是一個浮動窗口。
我們繼續向前看代碼:
~~~
WindowState appWin = this;
while (appWin.mAttachedWindow != null) {
appWin = mAttachedWindow;
}
WindowToken appToken = appWin.mToken;
while (appToken.appWindowToken == null) {
WindowToken parent = mTokenMap.get(appToken.token);
if (parent == null || appToken == parent) {
break;
}
appToken = parent;
}
mRootToken = appToken;
mAppToken = appToken.appWindowToken;
~~~
這段代碼主要用來初始化成員變量mRootToken和mAppToken。
* 成員變量mRootToken的類型為WindowToken,用來描述當前所創建的WindowState對象所描述的窗口的根窗口。如果當前所創建的WindowState對象所描述的窗口是一個子窗口,那么就先找到它的父窗口,然后再找到它的父窗口所屬的應用程序窗口,即Activity組件窗口,這時候找到的Activity組件窗口就是一個根窗口。如果當前所創建的WindowState對象所描述的窗口是一個子窗口,但是它不屬于任何一個應用程序窗口的,那么它的父窗口就是一個根窗口。如果當前所創建的WindowState對象所描述的窗口不是一個子窗口,并且它也不屬于一個應用程序窗口的,那么它本身就是一個根窗口。
* 成員變量mAppToken的類型為AppWindowToken,只有當成員變量mRootToken所描述的一個根窗口是一個應用程序窗口時,它的值才不等于null。
我們繼續向前看最后一段代碼:
~~~
mSurface = null;
mRequestedWidth = 0;
mRequestedHeight = 0;
mLastRequestedWidth = 0;
mLastRequestedHeight = 0;
mXOffset = 0;
mYOffset = 0;
mLayer = 0;
mAnimLayer = 0;
mLastLayer = 0;
}
......
}
......
}
~~~
這段代碼將以下十個成員變量的值設置為null或者0:
* mSurface:指向一個mSurface對象,用來描述窗口的繪圖表面。
* mRequestedWidth:這是一個整型變量,用來描述應用程序進程所請求的窗口寬度。
* mRequestedHeight:這是一個整型變量,用來描述應用程序進程所請求的窗口高度。
* mLastRequestedWidth:這是一個整型變量,用來描述應用程序進程上一次所請求的窗口寬度。
* mLastRequestedHeight:這是一個整型變量,用來描述應用程序進程上一次所請求的窗口高度。
* mXOffset:這是一個整型變量,用來描述壁紙窗口相對屏幕在X軸上的偏移量,對其它類型的窗口為說,這個值等于0。
* mYOffset:這是一個整型變量,用來描述壁紙窗口相對屏幕在Y軸上的偏移量,對其它類型的窗口為說,這個值等于0。
* mLayer:這是一個整型變量,用來描述窗口的Z軸位置值。
* mAnimLayer:這是一個整型變量,用來描述窗口的Z軸位置值,它的值可能等于mLayer的值,但是在以下四種情況中不相等。當一個窗口關聯有一個目標窗口的時候,那么它的值就等于mLayer的值加上目標窗口指定的一個動畫層調整值;當一個窗口的根窗口是一個應用程序窗口時,那么它的值就等于mLayer的值加上根窗口指定的一個動畫層調整值;當一個窗口是一個輸入法窗口時,那么它的值就等于mLayer的值加上系統設置的輸入法動畫層調整值;當一個窗口是壁紙窗口時,那么它的值就等于mLayer的值加上系統設置的壁紙動畫層調整值。
* mLastLayer:這是一個整型變量,用描述窗口上一次所使用的mAnimLayer的值。
至此,我們就分析完成WindowState的構造函數的實現了,返回到前面的Step 3中,即WindowManagerService類的成員函數addWindow中,接下來就會繼續調用前面所創建的一個WindowState對象的成員函數attach來創建一個關聯的SurfaceSession對象,以便可以用來和SurfaceFlinger服務通信。
**Step 5. WindowState.attach**
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
private final class WindowState implements WindowManagerPolicy.WindowState {
final Session mSession;
......
void attach() {
......
mSession.windowAddedLocked();
}
......
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
WindowState類的成員變量mSession指向的是一個Session對象,這個Session對象就是用來連接應用程序進程和WindowManagerService服務,WindowState類的成員函數attach調用它的成員函數windowAddedLocked來檢查是否需要為當前正在請求增加窗口的應用程序進程創建一個SurfaceSession對象。
接下來,我們繼續分析Session類的成員函數windowAddedLocked的實現。
**Step 6. Session.windowAddedLocked**
~~~
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
......
/**
* All currently active sessions with clients.
*/
final HashSet<Session> mSessions = new HashSet<Session>();
......
private final class Session extends IWindowSession.Stub
implements IBinder.DeathRecipient {
......
SurfaceSession mSurfaceSession;
int mNumWindow = 0;
......
void windowAddedLocked() {
if (mSurfaceSession == null) {
......
mSurfaceSession = new SurfaceSession();
......
mSessions.add(this);
}
mNumWindow++;
}
......
}
......
}
~~~
這個函數定義在文件frameworks/base/services/java/com/android/server/WindowManagerService.java中。
Session類的成員變量mSurfaceSession指向的是一個SurfaceSession對象,這個SurfaceSession對象是WindowManagerService服務用來與SurfaceSession服務建立連接的。Session類的成員函數windowAddedLocked首先檢查這個成員變量的值是否等于null。如果等于null的話,那么就說明WindowManagerService服務尚未為當前正在請求增加窗口的應用程序進程創建一個用來連接SurfaceSession服務的SurfaceSession對象,因此,Session類的成員函數windowAddedLocked就會創建一個SurfaceSession對象,并且保存在成員變量mSurfaceSession中,并且將正在處理的Session對象添加WindowManagerService類的成員變量mSession所描述的一個HashSet中去,表示WindowManagerService服務又多了一個激活的應用程序進程連接。
Session類的另外一個成員變量mNumWindow是一個整型變量,用來描述當前正在處理的Session對象內部包含有多少個窗口,即運行在引用了當前正在處理的Session對象的應用程序進程的內部的窗口的數量。每當運行在應用程序進程中的窗口銷毀時,該應用程序進程就會通知WindowManagerService服務移除用來描述該窗口狀態的一個WindowState對象,并且通知它所引用的Session對象減少其成員變量mNumWindow的值。當一個Session對象的成員變量mNumWindow的值減少為0時,就說明該Session對象所描述的應用程序進程連接已經不需要了,因此,該Session對象就可以殺掉其成員變量mSurfaceSession所描述的一個SurfaceSession對象,以便可以斷開和SurfaceSession服務的連接。
接下來,我們就繼續分析SurfaceSession類的構造函數的實現,以便可以了解一個SurfaceSession對象是如何與SurfaceSession服務建立連接的。
**Step 7. new SurfaceSession**
~~~
public class SurfaceSession {
/** Create a new connection with the surface flinger. */
public SurfaceSession() {
init();
}
......
private native void init();
......
private int mClient;
}
~~~
這個函數定義在文件frameworks/base/core/java/android/view/SurfaceSession.java中。
SurfaceSession類的構造函數的實現很簡單,它只是調用了另外一個成員函數init來執行一些初始化操作,其實就是用來初始化SurfaceSession類的成員變量mClient。
SurfaceSession類的成員函數init是一個JNI方法,它是由C++層的函數SurfaceSession_init來實現的,如下所示:
~~~
static void SurfaceSession_init(JNIEnv* env, jobject clazz)
{
sp<SurfaceComposerClient> client = new SurfaceComposerClient;
client->incStrong(clazz);
env->SetIntField(clazz, sso.client, (int)client.get());
}
~~~
這個函數定義在文件frameworks/base/core/jni/android_view_Surface.cpp中。
在分析函數SurfaceSession_init的實現之前,我們首先看看全局變量sso的定義,如下所示:
~~~
struct sso_t {
jfieldID client;
};
static sso_t sso;
~~~
它是一個類型為sso_t的結構體變量,它的成員變量client描述的是SurfaceSession類的成員變量mClient在SurfaceSession類中的偏移量:
~~~
void nativeClassInit(JNIEnv* env, jclass clazz)
{
......
jclass surfaceSession = env->FindClass("android/view/SurfaceSession");
sso.client = env->GetFieldID(surfaceSession, "mClient", "I");
......
}
~~~
回到函數SurfaceSession_init中,它首先創建一個SurfaceComposerClient對象client,接著再增加這個SurfaceComposerClient對象的強引用計數,因為再接下來會將這個SurfaceComposerClient對象的地址值保存在參數clazz所描述的一個SurfaceSession對象的成員變量mClient中,這相當于是參數clazz所描述的一個SurfaceSession對象引用了剛才所創建的SurfaceComposerClient對象client。
在前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃這一系列的文章中,我們已經分析過SurfaceComposerClient類的作用了,這主要就是用來在應用程序進程和SurfaceFlinger服務之間建立連接的,以便應用程序進程可以為運行在它里面的應用程序窗口請求SurfaceComposerClient創建繪制表面(Surface)的操作等。
這樣,每一個Java層的SurfaceSession對象在C++層就都有一個對應的SurfaceComposerClient對象,因此,Java層的應用程序就可以通過SurfaceSession類來和SurfaceFlinger服務建立連接。
至此,我們就分析完成一個WindowState對象的創建過程了,通過這個過程我們就可以知道,每一個Activity組件窗口在WindowManagerService服務內部都有一個對應的WindowState對象,用來描述它的窗口狀態。
至此,我們也分析完成Android應用程序窗口與WindowManagerService服務的連接過程了。從這個連接過程以及前面Android應用程序窗口(Activity)的窗口對象(Window)的創建過程分析和Android應用程序窗口(Activity)的視圖對象(View)的創建過程分析這兩篇文章,我們就可以知道,為了實現一個Activity組件的UI,無論是應用程序進程,還是WindowManagerService,都做了大量的工作,例如,應用程序進程為它創建一個窗口(Window)對象、一個視圖(View)對象、一個ViewRoot對象、一個W對象,WindowManagerService服務為它創建一個AppWindowToken對象和一個WindowState對象。此外,WindowManagerService服務還為一個Activity組件所運行在的應用程序進程創建了一個Session對象。理解這些對象的實現以及作用對我們了解Android應用程序窗口的實現框架以及WindowManagerService服務的實現原理都是非常重要的。
雖然到目前為止,我們已經為Android應用程序窗口創建了很多對象,但是我們仍然還有一個最重要的對象還沒有創建,那就是Android應用程序窗口的繪圖表面,即用來渲染UI的Surface還沒有創建。從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃這一系列的文章可以知道,這個Surface是要請求SurfaceFlinger服務來創建的,因此,在接下來的一篇文章中,我們就將繼續分析Android應用程序窗口的繪圖表面(Surface)的創建過程,敬請關注!
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析