我們已經知道了Activity的生命周期,如onCreate、onDestroy等,但大家是否考慮過這樣一個問題:
- 如果沒有創建Activity,那么onCreate和onDestroy就沒有任何意義,可這個Activity究竟是在哪里創建的?。
第4章中的“Zygote分裂”一節已講過,Zygote在響應請求后會fork一個子進程,這個子進程是App對應的進程,它的入口函數是ActivityThread類的main函數。ActivityThread類中有一個handleLaunchActivity函數,它就是創建Activity的地方。一起來看這個函數,代碼如下所示:
**ActivityThread.java**
~~~
private final voidhandleLaunchActivity(ActivityRecord r, Intent customIntent) {
//①performLaunchActivity返回一個Activity
Activitya = performLaunchActivity(r, customIntent);
if(a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
//②調用handleResumeActivity
handleResumeActivity(r.token, false, r.isForward);
}
......
}
~~~
handleLaunchActivity函數中列出了兩個關鍵點,下面對其分別介紹。
1. 創建Activity
第一個關鍵函數performLaunchActivity返回一個Activity,這個Activity就是App中的那個Activity(僅考慮App中只有一個Activity的情況),它是怎么創建的呢?其代碼如下所示:
handleLaunchActivity函數中列出了兩個關鍵點,下面對其分別介紹。
**ActivityThread.java**
~~~
private final ActivityperformLaunchActivity(ActivityRecord r,
Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
......//完成一些準備工作
//Activity定義在Activity.java中
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
/*
mInstrumentation為Instrumentation類型,源文件為Instrumentation.java。
它在newActivity函數中根據Activity的類名通過Java反射機制來創建對應的Activity,
這個函數比較復雜,待會我們再分析它。
*/
activity = mInstrumentation.newActivity(
cl,component.getClassName(), r.intent);
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
}catch (Exception e) {
......
}
try {
Application app =
r.packageInfo.makeApplication(false,mInstrumentation);
if (activity != null) {
//在Activity中getContext函數返回的就是這個ContextImpl類型的對象
ContextImpl appContext = new ContextImpl();
......
//下面這個函數會調用Activity的onCreate函數
mInstrumentation.callActivityOnCreate(activity, r.state);
......
return activity;
}
~~~
好了,performLaunchActivity函數的作用明白了吧?
- 根據類名以Java反射的方法創建一個Activity。
- 調用Activity的onCreate函數,開始SDK中大書特書Activity的生命周期。
那么,在onCreate函數中,我們一般會做什么呢?在這個函數中,和UI相關的重要工作就是調用setContentView來設置UI的外觀。接下去,需要看handleLaunchActivity中第二個關鍵函數handleResumeActivity。
2. 分析handleResumeActivity
上面已創建好了一個Activity,再來看handleResumeActivity。它的代碼如下所示:
**ActivityThread.java**
~~~
final void handleResumeActivity(IBinder token,boolean clearHide,
boolean isForward) {
boolean willBeVisible = !a.mStartedActivity;
if (r.window == null && !a.mFinished&& willBeVisible) {
r.window= r.activity.getWindow();
//①獲得一個View對象
Viewdecor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//②獲得ViewManager對象
ViewManagerwm = a.getWindowManager();
......
//③把剛才的decor對象加入到ViewManager中
wm.addView(decor,l);
}
......//其他處理
}
~~~
上面有三個關鍵點。這些關鍵點似乎已經和UI部分(如View、Window)有聯系了。那么這些聯系是在什么時候建立的呢?在分析上面代碼中的三個關鍵點之前,請大家想想在前面的過程中,哪些地方會和UI掛上鉤呢?
- 答案就在onCreate函數中,Activity一般都在這個函數中通過setContentView設置UI界面。
看來,必須先分析setContentView,才能繼續后面的征程。
3. 分析setContentView
setContentView有好幾個同名函數,現在只看其中的一個就可以了。代碼如下所示:
**Activity.java**
~~~
public void setContentView(View view) {
//getWindow返回的是什么呢?一起來看看。
getWindow().setContentView(view);
}
public Window getWindow() {
returnmWindow; //返回一個類型為Window的mWindow,它是什么?
}
~~~
上面出現了兩個和UI有關系的類:View和Window[①]。來看SDK文檔是怎么描述這兩個類的。這里先給出原文描述,然后進行對應翻譯:
- Window:abstract base class for a top-levelwindow look and behavior policy. An instance of this class should be used asthe top-level view added to the window manager. It provides standard UIpolicies such as a background, title area, default key processing, etc.
中文的意思是:Window是一個抽象基類,用于控制頂層窗口的外觀和行為。做為頂層窗口它有什么特殊的職能呢?即繪制背景和標題欄、默認的按鍵處理等。
這里面有一句比較關鍵的話:它將做為一個頂層的view加入到Window Manager中。
- View:This class represents the basicbuilding block for user interface components. A View occupies a rectangulararea on the screen and is responsible for drawing and event handling.
View的概念就比較簡單了,它是一個基本的UI單元,占據屏幕的一塊矩形區域,可用于繪制,并能處理事件。
從上面的View和Window的描述,再加上setContentView的代碼,我們能想象一下這三者的關系,如圖8-2所示:
:-: 
圖8-2 Window/View的假想關系圖
根據上面的介紹,大家可能會產生兩個疑問:
- Window是一個抽象類,它實際的對象到底是什么類型?
- Window Manager究竟是什么?
如果能有這樣的疑問,就說明我們非常細心了。下面試來解決這兩個問題。
(1)Activity的Window
據上文講解可知,Window是一個抽象類。它實際的對象到底屬于什么類型?先回到Activity創建的地方去看看。下面正是創建Activity時的代碼,可當時沒有深入地分析。
~~~
activity = mInstrumentation.newActivity(
cl,component.getClassName(), r.intent);
~~~
代碼中調用了Instrumentation的newActivity,再去那里看看。
**Instrumentation.java**
~~~
public Activity newActivity(Class<?>clazz, Context context,
IBinder token, Application application, Intent intent,
ActivityInfo info, CharSequencetitle, Activity parent,
String id,Object lastNonConfigurationInstance)
throws InstantiationException, IllegalAccessException{
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
//關鍵函數attach!!
activity.attach(context, aThread, this, token, application, intent,
info, title,parent, id, lastNonConfigurationInstance,
new Configuration());
return activity;
}
~~~
看到關鍵函數attach了吧?Window的真相馬上就要揭曉了,讓我們用咆哮體②來表達內心的激動之情吧!!!!
**Activity.java**
~~~
final void attach(Context context,ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
......
//利用PolicyManager來創建Window對象
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
......
//創建WindowManager對象
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
if(mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
//保存這個WindowManager對象
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
~~~
此刻又有一點失望吧?這里冒出了個PolicyManager類,Window是由它的makeNewWindow函數所創建,因此還必須再去看看這個PolicyManager。
(2)水面下的冰山——PolicyManager
PolicyManager定義于PolicyManager.java文件,該文件在一個非常獨立的目錄下,現將其單獨列出來:
- frameworks/policies/base/phone/com/android/internal/policy/impl
* * * * *
**注意**,上面路徑中的灰色目錄phone是針對智能手機這種小屏幕的;另外還有一個平級的目錄叫mid,是針對Mid設備的。mid目錄的代碼比較少,可能目前還沒有開發完畢。
* * * * *
下面來看這個PolicyManager,它比較簡單。
**PolicyManager.java**
~~~
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static{
//
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
//創建Policy對象
sPolicy = (IPolicy)policyClass.newInstance();
}catch (ClassNotFoundException ex) {
......
}
private PolicyManager() {}
//通過Policy對象的makeNewWindow創建一個Window
publicstatic Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
......
}
~~~
這里有一個單例的sPolicy對象,它是Policy類型,請看它的定義。
(3)真正的Window
Policy類型的定義代碼如下所示:
**Policy.java**
~~~
public class Policy implements IPolicy {
private static final String TAG = "PhonePolicy";
private static final String[] preload_classes = {
"com.android.internal.policy.impl.PhoneLayoutInflater",
"com.android.internal.policy.impl.PhoneWindow",
"com.android.internal.policy.impl.PhoneWindow$1",
"com.android.internal.policy.impl.PhoneWindow$ContextMenuCallback",
"com.android.internal.policy.impl.PhoneWindow$DecorView",
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
};
static{
//加載所有的類
for (String s : preload_classes) {
try {
Class.forName(s);
} catch (ClassNotFoundException ex) {
......
}
}
}
public PhoneWindow makeNewWindow(Contextcontext) {
//makeNewWindow返回的是PhoneWindow對象
return new PhoneWindow(context);
}
......
}
~~~
至此,終于知道了代碼:
~~~
mWindow = PolicyManager.makeNewWindow(this);
~~~
返回的Window,原來是一個PhoneWindow對象。它的定義在PhoneWindow.java中。
mWindow的真實身份搞清楚了,還剩下個WindowManager。現在就來揭示其真面目。
(4)真正的WindowManager
先看WindowManager創建的代碼,如下所示:
**Activity.java**
~~~
......//創建mWindow對象
//調用mWindow的setWindowManager函數
mWindow.setWindowManager(null, mToken,mComponent.flattenToString());
.....
~~~
上面的函數設置了PhoneWindow的WindowManager,不過第一個參數是null,這是什么意思?在回答此問題之前,先來看PhoneWindow的定義,它是從Window類派生。
**PhoneWindow.java::PhoneWindow定義**
~~~
public class PhoneWindow extends Windowimplements MenuBuilder.Callback
~~~
前面調用的setWindowManager函數,其實是由PhoneWindow的父類Window類來實現的,來看其代碼,如下所示:
**Window.java**
~~~
public void setWindowManager(WindowManagerwm,IBinder appToken, String appName) { //注意,傳入的wm值為null
mAppToken = appToken;
mAppName = appName;
if(wm == null) {
//如果wm為空的話,則創建WindowManagerImpl對象
wm = WindowManagerImpl.getDefault();
}
//mWindowManager是一個LocalWindowManager
mWindowManager = new LocalWindowManager(wm);
}
~~~
LocalWindowManager是在Window中定義的內部類,請看它的構造函數,其定義如下所示:
**Window.java::LocalWindowManager定義**
~~~
private class LocalWindowManager implementsWindowManager {
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;//還好,只是簡單地保存了傳入的wm參數
mDefaultDisplay = mContext.getResources().getDefaultDisplay(
mWindowManager.getDefaultDisplay());
}
......
~~~
如上面代碼所示,LocalWindowManager將保存一個WindowManager類型的對象,這個對象的實際類型是WindowManagerImpl。而WindowManagerImpl又是什么呢?來看它的代碼,如下所示:
**WindowManagerImpl.java**
~~~
public class WindowManagerImpl implementsWindowManager {
......
public static WindowManagerImpl getDefault()
{
return mWindowManager; //返回的就是WindowManagerImpl對象
}
private static WindowManagerImpl mWindowManager= new WindowManagerImpl();
}
~~~
看到這里,是否有點頭暈眼花?很多朋友讀我的一篇與此內容相關的博文后,普遍也有如此反應。對此,試配制了一劑治暈藥方,如圖8-3所示:
:-: 
圖8-3 Window和WindowManger的家族圖譜
根據上圖,可得出以下結論:
- Activity的mWindow成員變量其真實類型是PhoneWindow,而mWindowManager成員變量的真實類型是LocalWindowManager。
- LocalWindowManager和WindowManagerImpl都實現了WindowManager接口。這里采用的是Proxy模式,表明LocalWindowManager將把它的工作委托WindowManagerImpl來完成。
(5)setContentView的總結
了解了上述知識后,重新回到setContentView函數。這次希望能分析得更深入些。
**Activity.java**
~~~
public void setContentView(View view) {
getWindow().setContentView(view);//getWindow返回的是PhoneWindow
}
~~~
一起來看PhoneWindow的setContentView函數,代碼如下所示:
**PhoneWindow**
~~~
public void setContentView(View view) {
//調用另一個setContentView
setContentView(view,
new ViewGroup.LayoutParams(MATCH_PARENT,MATCH_PARENT));
}
public void setContentView(View view,ViewGroup.LayoutParams params) {
//mContentParent為ViewGroup類型,它的初值為null
if(mContentParent == null) {
installDecor();
}else {
mContentParent.removeAllViews();
}
//把view加入到ViewGroup中
mContentParent.addView(view, params);
......
}
~~~
mContentParent是一個ViewGroup類型,它從View中派生,所以也是一個UI單元。從它名字中“Group”所表達的意思分析,它還可以包含其他的View元素。這又是什么意思呢?
- 也就是說,在繪制一個ViewGroup時,它不僅需要把自己的樣子畫出來,還需要把它包含的View元素的樣子也畫出來。讀者可將它想象成一個容器,容器中的元素就是View。
這里采用的是23種設計模式中的Composite模式,它是UI編程中常用的模式之一。
再來看installDecor函數,其代碼如下所示:
**PhoneWindow.java**
~~~
private void installDecor() {
if (mDecor == null) {
//創建mDecor,它為DecorView類型,從FrameLayout派生
mDecor= generateDecor();
......
}
if(mContentParent == null) {
//得到這個mContentParent
mContentParent = generateLayout(mDecor);
//創建標題欄
mTitleView= (TextView)findViewById(com.android.internal.R.id.title);
......
}
~~~
generateLayout函數的輸入參數為mDecor,輸出為mContentParent,代碼如下所示:
**PhoneWindow**
~~~
protected ViewGroup generateLayout(DecorViewdecor){
......
intlayoutResource;
intfeatures = getLocalFeatures();
if((features & ((1 << FEATURE_LEFT_ICON) |(1 <<FEATURE_RIGHT_ICON))) != 0) {
if(mIsFloating) {
//根據情況取得對應標題欄的資源id
layoutResource = com.android.internal.R.layout.dialog_title_icons;
}
......
}
mDecor.startChanging();
View in =mLayoutInflater.inflate(layoutResource, null);
//加入標題欄
decor.addView(in,new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
/*
ID_ANDROID_CONTENT的值為”com.android.internal.R.id.content”
這個contentParent由findViewById返回,實際上就是mDecorView的一部分。
*/
ViewGroupcontentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
......
mDecor.finishChanging();
returncontentParent;
}
~~~
下面看findViewById是如何實現的。它定義在Window.java中,代碼如下所示:
**Window.java**
~~~
public View findViewById(int id) {
//getDecorView將返回mDecorView,所以contentParent確實是DecorView的一部分
returngetDecorView().findViewById(id);
}
~~~
大家還記得圖8-2嗎?介紹完上面的知識后,根據圖8-2,可繪制更細致的圖8-4:
:-: 
圖8-4 一個Activity中的UI組件
可從上圖中看出,在Activity的onCreate函數中,通過setContentView設置的View,其實只是DecorView的子View。DecorView還處理了標題欄顯示等一系列的工作。
注意,這里使用了設計模式中的Decorator(裝飾)模式,它也是UI編程中常用的模式之一。
4. 重回handleResumeActivity
看完setContentView的分析后,不知大家是否還記得這樣一個問題:為什么要分析這個setContentView函數?在繼續前行之前,先來回顧一下被setContentView打斷的流程。
當時,我們正在分析handleResumeActivity,代碼如下所示:
**ActivityThread.java**
~~~
final void handleResumeActivity(IBinder token,boolean clearHide,
boolean isForward) {
booleanwillBeVisible = !a.mStartedActivity;
......
if (r.window == null && !a.mFinished&& willBeVisible) {
r.window= r.activity.getWindow();
//①獲得一個View對象。現在知道這個view就是DecorView
Viewdecor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//②獲得ViewManager對象,這個wm就是LocalWindowManager
ViewManagerwm = a.getWindowManager();
WindowManager.LayoutParamsl = r.window.getAttributes();
a.mDecor= decor;
l.type =WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
if(a.mVisibleFromClient) {
a.mWindowAdded= true;
//③把剛才的decor對象加入到ViewManager中
wm.addView(decor,l);
}
......//其他處理
}
~~~
在上面的代碼中,由于出現了多個之前不熟悉的東西,如View、ViewManager等,而這些東西的來源又和setContentView有關,所以我們才轉而去分析setContentView了。想起來了吧?
由于代碼比較長,跳轉關系也很多,在分析代碼時,請讀者把握流程,在大腦中建立一個代碼分析的堆棧。
下面就從addView的分析開始。如前面所介紹的,它的調用方法是:
~~~
wm.addView(decor, l);//wm類型實際是LocalWindowManager
~~~
來看這個addView函數,它的代碼如下所示:
**Window.javaLocalWindowManager**
~~~
public final void addView(View view,ViewGroup.LayoutParams params) {
WindowManager.LayoutParams wp =(WindowManager.LayoutParams)params;
CharSequence curTitle = wp.getTitle();
...... //做一些操作,可以不管它
//還記得前面提到過的Proxy模式嗎?mWindowManager對象實際上是WindowManagerImpl類型
mWindowManager.addView(view, params);
}
~~~
看來,要搞清楚這個addView函數還是比較麻煩的,因為現在必須到WindowManagerImpl中去看看。它的代碼如下所示:
**WindowManagerImpl.java**
~~~
private void addView(View view,ViewGroup.LayoutParams params, boolean nest)
{
ViewRootroot; //ViewRoot,幕后的主角終于登場了!
synchronized(this) {
//①創建ViewRoot
root =new ViewRoot(view.getContext());
root.mAddNesting = 1;
view.setLayoutParams(wparams);
if(mViews == null) {
index = 1;
mViews = new View[1];
mRoots= new ViewRoot[1];
mParams = new WindowManager.LayoutParams[1];
} else{
......
}
index--;
mViews[index]= view;
mRoots[index]= root;//保存這個root
mParams[index]= wparams;
//②setView,其中view是剛才我們介紹的DecorView
root.setView(view,wparams, panelParentView);//
}
~~~
“ViewRoot,ViewRoot ....”,主角終于出場了!即使沒介紹它的真實身份,不禁也想歡呼幾聲。可為避免高興得過早,還是應該先冷靜地分析一下它。這里,列出了ViewRoot的兩個重要關鍵點。
(1)ViewRoot是什么?
ViewRoot是什么?看起來好像和View有些許關系,至少名字非常像。事實上,它的確和View有關系,因為它實現了ViewParent接口。SDK的文檔中有關于ViewParent的介紹。但它和Android基本繪圖單元中的View卻不太一樣,比如:ViewParent不處理繪畫,因為它沒有onDraw函數。
如上所述,ViewParent和繪畫沒有關系,那么,它的作用是什么?先來看它的代碼,如下所示:
**ViewRoot.java::ViewRoot定義**
~~~
public final class ViewRoot extends Handlerimplements ViewParent,
View.AttachInfo.Callbacks //從Handler類派生
{
private final Surface mSurface = new Surface();//這里創建了一個Surface對象
final W mWindow; //這個是什么?
View mView;
}
~~~
上面這段代碼傳達出了一些重要信息:
- ViewRoot繼承了Handler類,看來它能處理消息。ViewRoot果真重寫了handleMessage函數。稍侯再來看它。
- ViewRoot有一個成員變量叫mSurface,它是Surface類型。
- ViewRoot還有一個W類型的mWindow和一個View類型的mView變量。
其中,W是ViewRoot定義的一個靜態內部類:
~~~
static class W extends IWindow.Stub
~~~
這個類將參與Binder的通信,以后對此再做講解,先來介紹Surface類。
(2)神筆馬良乎?
這里冒出來一個Surface類。它是什么?在回答此問題之前,先來考慮這樣一個問題:
- 前文介紹的View、DecorView等都是UI單元,這些UI單元的繪畫工作都在onDraw函數中完成。如果把onDraw想象成畫圖過程,那么畫布是什么?
Android肯定不是“馬良”,它也沒有那支可以在任何物體上作畫的“神筆”,所以我們需要一塊實實在在的畫布,這塊畫布就是Surface。SDK文檔對Surface類的說明是:Handle on to a raw buffer thatis being managed by the screen compositor。這句話的意思是:
- 有一塊Raw buffer,至于是內存還是顯存,不必管它。
- Surface操作這塊Raw buffer。
- Screen compositor(其實就是SurfaceFlinger)管理這塊Raw buffer。
Surface和SF、ViewRoot有什么關系呢?相信,聰明的你此時已經明白些了,這里用圖8-5描繪一下心中的想法:
:-: 
圖8-5 馬良的神筆工作原理
結合之前所講的知識,圖8-5清晰地傳達了如下幾條信息:
- ViewRoot有一個成員變量mSurface,它是Surface類型,它和一塊Raw Buffer有關聯。
- ViewRoot是一個ViewParent,它的子View的繪畫操作,是在畫布Surface上展開的。
- Surface和SurfaceFlinger有交互,這非常類似AudioTrack和AudioFlinger之間的交互。
既然本章題目為“深入理解Surface系統”,那么就需要重點關注Surface和SurfaceFlinger間的關系。建立這個關系需ViewRoot的參與,所以應先來分析ViewRoot的創建和它的setView函數。
(3)ViewRoot的創建和對setView的分析
來分析ViewRoot的構造。關于它所包含內容,代碼如下所示:
**ViewRoot.java**
~~~
public ViewRoot(Context context) {
super();
....
// getWindowSession?我們進去看看
getWindowSession(context.getMainLooper());
......//ViewRoot的mWindow是一個W類型,注意它不是Window類型,而是IWindow類型
mWindow= new W(this, context);
}
~~~
getWindowsession函數,將建立Activity的ViewRoot和WindowManagerService的關系。代碼如下所示:
**ViewRoot.java**
~~~
ublic static IWindowSessiongetWindowSession(Looper mainLooper) {
synchronized (mStaticInit) {
if(!mInitialized) {
try {
InputMethodManagerimm =
InputMethodManager.getInstance(mainLooper);
//下面這個函數先得到WindowManagerService的Binder代理,然后調用它的openSession
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(imm.getClient(), imm.getInputContext());
mInitialized = true;
} catch (RemoteException e) {
}
}
return sWindowSession;
}
}
~~~
WindowSession?WindowManagerService?第一次看到這些東西時,我快瘋了。復雜,太復雜,無比復雜!要攻克這些難題,應先來回顧一下與Zygote相關的知識:
- WindowManagerService(以后簡稱WMS)由System_Server進程啟動,SurfaceFlinger服務也在這個進程中。
看來,Activity的顯示還不單純是它自己的事,還需要和WMS建立聯系才行。繼續看。先看setView的處理。這個函數很復雜,
注意其中關鍵的幾句。
openSession的操作是一個使用Binder通信的跨進程調用,暫且記住這個函數,在精簡流程之后再來分析。
代碼如下所示:
**ViewRoot.java**
~~~
public void setView(View view, WindowManager.LayoutParamsattrs,
View panelParentView){//第一個參數view是DecorView
......
mView= view;//保存這個view
synchronized (this) {
requestLayout(); //待會先看看這個。
try {
//調用IWindowSession的add函數,第一個參數是mWindow
res =sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets);
}
......
}
~~~
ViewRoot的setView函數做了三件事:
- 保存傳入的view參數為mView,這個mView指向PhoneWindow的DecorView。
- 調用requestLayout。
- 調用IWindowSession的add函數,這是一個跨進程的Binder通信,第一個參數是mWindow,它是W類型,從IWindow.stub派生。
先來看這個requestLayout函數,它非常簡單,就是往handler中發送了一個消息。注意,ViewRoot是從Handler派生的,所以這個消息最后會由ViewRoot自己處理,代碼如下所示:
**ViewRoot.java**
~~~
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
public void scheduleTraversals() {
if(!mTraversalScheduled) {
mTraversalScheduled = true;
sendEmptyMessage(DO_TRAVERSAL); //發送DO_TRAVERSAL消息
}
}
~~~
好,requestLayout分析完畢。
從上面的代碼中可發現,ViewRoot和遠端進程SystemServer的WMS有交互,先來總結一下它和WMS的交互流程:
- ViewRoot調用openSession,得到一個IWindowSession對象。
- 調用WindowSession對象的add函數,把一個W類型的mWindow對象做為參數傳入。
5. ViewRoot和WMS的關系
上面總結了ViewRoot和WMS的交互流程,其中一共有兩個跨進程的調用。一起去看。
(1)調用流程分析
WMS的代碼在WindowManagerService.java中:
**WindowManagerService.java**
~~~
public IWindowSessionopenSession(IInputMethodClient client,
IInputContextinputContext) {
......
return new Session(client, inputContext);
}
~~~
Session是WMS定義的內部類。它支持Binder通信,并且屬于Bn端,即響應請求的服務端。
再來看它的add函數。代碼如下所示:
**WindowManagerService.java::Session**
~~~
public int add(IWindow window,WindowManager.LayoutParams attrs,
int viewVisibility, Rect outContentInsets) {
//調用外部類對象的addWindow,也就是WMS的addWindow
returnaddWindow(this, window, attrs, viewVisibility,
outContentInsets);
}
~~~
**WindowManagerService.java**
~~~
public int addWindow(Session session, IWindowclient,
WindowManager.LayoutParams attrs, int viewVisibility,
Rect outContentInsets) {
......
//創建一個WindowState
win = new WindowState(session, client, token,
attachedWindow, attrs,viewVisibility);
......
//調用attach函數
win.attach();
......
return res;
}
~~~
WindowState類也是在WMS中定義的內部類,直接看它的attach函數,代碼如下所示:
**WMS.java::WindowState**
~~~
void attach() {
//mSession就是Session對象,調用它的windowAddedLocked函數
mSession.windowAddedLocked();
}
~~~
**WMS.java::Session**
~~~
void windowAddedLocked() {
if(mSurfaceSession == null) {
......
//創建一個SurfaceSession對象
mSurfaceSession= new SurfaceSession();
......
}
mNumWindow++;
}
~~~
這里出現了另外一個重要的對象SurfaceSession。在講解它之前,急需理清一下現有的知識點,否則可能會頭暈。
(2)ViewRoot和WMS的關系梳理
ViewRoot和WMS之間的關系,可用圖8-6來表示:
:-:
圖8-6 ViewRoot和WMS的關系
總結一下圖8-6中的知識點:
- ViewRoot通過IWindowSession和WMS進程進行跨進程通信。IWindowSession定義在IWindowSession.aidl文件中。這個文件在編譯時由aidl工具處理,最后會生成類似于Native Binder中Bn端和Bp端的代碼,后文會介紹它。
- ViewRoot內部有一個W類型的對象,它也是一個基于Binder通信的類,W是IWindow的Bn端,用于響應請求。IWindow定義在另一個aidl文件IWindow.aidl中。
為什么需要這兩個特殊的類呢?簡單介紹一下:
首先,來看IWindowSession.aidl對自己的描述:
- System private per-application interface to the window manager:也就是說每個App進程都會和WMS建立一個IWindowSession會話。這個會話被App進程用于和WMS通信。后面會介紹它的requestLayout函數。
再看對IWindow.adil的描述:
- API back to a client window that the Window Manager uses to informit of interesting things happening:這句話的大意是IWindow是WMS用來做事件通知的。每當發生一些事情時,WMS就會把這些事告訴某個IWindow。可以把IWindow想象成一個回調函數。
IWindow的描述表達了什么意思呢?不妨看看它的內容,代碼如下所示:
**IWindow.aidl定義**
~~~
void dispatchKey(in KeyEvent event);
void dispatchPointer(in MotionEvent event, longeventTime,
boolean callWhenDone);
void dispatchTrackball(in MotionEvent event,long eventTime,
boolean callWhenDone);
~~~
明白了?這里的事件指的就是按鍵、觸屏等事件。那么,一個按鍵事件是如何被分發的呢?下面是它大致的流程:
- WMS所在的SystemServer進程接收到按鍵事件。
- WMS找到UI位于屏幕頂端的進程所對應的IWindow對象,這是一個Bp端對象。
- 調用這個IWindow對象的dispatchKey。IWindow對象的Bn端位于ViewRoot中,ViewRoot再根據內部View的位置信息找到真正處理這個事件的View,最后調用dispatchKey函數完成按鍵的處理。
其實這些按鍵事件的分發機制可以拿Windows的UI編程來做類比,在Windows中應用程序的按鍵處理流程是:
- 每一個按鍵事件都會轉化成一個消息,這個消息將由系統加入到對應進程的消息隊列中。該進程的消息在派發處理時,會根據消息的句柄找到對應的Window(窗口),繼而該消息就由這個Window處理了。
* * * * *
**注意**:上面的描述實際上大大簡化了真實的處理流程,讀者可在了解大體知識后進行更深入的研究。
* * * * *
上面介紹的是ViewRoot和WMS的交互,但是我們最關心的Surface還沒有正式介紹,在此之前,還是先介紹Activity的流程。
- 前言
- 第1章 閱讀前的準備工作
- 1.1 系統架構
- 1.1.1 Android系統架構
- 1.1.2 本書的架構
- 1.2 搭建開發環境
- 1.2.1 下載源碼
- 1.2.2 編譯源碼
- 1.3 工具介紹
- 1.3.1 Source Insight介紹
- 1.3.2 Busybox的使用
- 1.4 本章小結
- 第2章 深入理解JNI
- 2.1 JNI概述
- 2.2 學習JNI的實例:MediaScanner
- 2.3 Java層的MediaScanner分析
- 2.3.1 加載JNI庫
- 2.3.2 Java的native函數和總結
- 2.4 JNI層MediaScanner的分析
- 2.4.1 注冊JNI函數
- 2.4.2 數據類型轉換
- 2.4.3 JNIEnv介紹
- 2.4.4 通過JNIEnv操作jobject
- 2.4.5 jstring介紹
- 2.4.6 JNI類型簽名介紹
- 2.4.7 垃圾回收
- 2.4.8 JNI中的異常處理
- 2.5 本章小結
- 第3章 深入理解init
- 3.1 概述
- 3.2 init分析
- 3.2.1 解析配置文件
- 3.2.2 解析service
- 3.2.3 init控制service
- 3.2.4 屬性服務
- 3.3 本章小結
- 第4章 深入理解zygote
- 4.1 概述
- 4.2 zygote分析
- 4.2.1 AppRuntime分析
- 4.2.2 Welcome to Java World
- 4.2.3 關于zygote的總結
- 4.3 SystemServer分析
- 4.3.1 SystemServer的誕生
- 4.3.2 SystemServer的重要使命
- 4.3.3 關于 SystemServer的總結
- 4.4 zygote的分裂
- 4.4.1 ActivityManagerService發送請求
- 4.4.2 有求必應之響應請求
- 4.4.3 關于zygote分裂的總結
- 4.5 拓展思考
- 4.5.1 虛擬機heapsize的限制
- 4.5.2 開機速度優化
- 4.5.3 Watchdog分析
- 4.6 本章小結
- 第5章 深入理解常見類
- 5.1 概述
- 5.2 以“三板斧”揭秘RefBase、sp和wp
- 5.2.1 第一板斧--初識影子對象
- 5.2.2 第二板斧--由弱生強
- 5.2.3 第三板斧--破解生死魔咒
- 5.2.4 輕量級的引用計數控制類LightRefBase
- 5.2.5 題外話-三板斧的來歷
- 5.3 Thread類及常用同步類分析
- 5.3.1 一個變量引發的思考
- 5.3.2 常用同步類
- 5.4 Looper和Handler類分析
- 5.4.1 Looper類分析
- 5.4.2 Handler分析
- 5.4.3 Looper和Handler的同步關系
- 5.4.4 HandlerThread介紹
- 5.5 本章小結
- 第6章 深入理解Binder
- 6.1 概述
- 6.2 庖丁解MediaServer
- 6.2.1 MediaServer的入口函數
- 6.2.2 獨一無二的ProcessState
- 6.2.3 時空穿越魔術-defaultServiceManager
- 6.2.4 注冊MediaPlayerService
- 6.2.5 秋風掃落葉-StartThread Pool和join Thread Pool分析
- 6.2.6 你徹底明白了嗎
- 6.3 服務總管ServiceManager
- 6.3.1 ServiceManager的原理
- 6.3.2 服務的注冊
- 6.3.3 ServiceManager存在的意義
- 6.4 MediaPlayerService和它的Client
- 6.4.1 查詢ServiceManager
- 6.4.2 子承父業
- 6.5 拓展思考
- 6.5.1 Binder和線程的關系
- 6.5.2 有人情味的訃告
- 6.5.3 匿名Service
- 6.6 學以致用
- 6.6.1 純Native的Service
- 6.6.2 扶得起的“阿斗”(aidl)
- 6.7 本章小結
- 第7章 深入理解Audio系統
- 7.1 概述
- 7.2 AudioTrack的破解
- 7.2.1 用例介紹
- 7.2.2 AudioTrack(Java空間)分析
- 7.2.3 AudioTrack(Native空間)分析
- 7.2.4 關于AudioTrack的總結
- 7.3 AudioFlinger的破解
- 7.3.1 AudioFlinger的誕生
- 7.3.2 通過流程分析AudioFlinger
- 7.3.3 audio_track_cblk_t分析
- 7.3.4 關于AudioFlinger的總結
- 7.4 AudioPolicyService的破解
- 7.4.1 AudioPolicyService的創建
- 7.4.2 重回AudioTrack
- 7.4.3 聲音路由切換實例分析
- 7.4.4 關于AudioPolicy的總結
- 7.5 拓展思考
- 7.5.1 DuplicatingThread破解
- 7.5.2 題外話
- 7.6 本章小結
- 第8章 深入理解Surface系統
- 8.1 概述
- 8.2 一個Activity的顯示
- 8.2.1 Activity的創建
- 8.2.2 Activity的UI繪制
- 8.2.3 關于Activity的總結
- 8.3 初識Surface
- 8.3.1 和Surface有關的流程總結
- 8.3.2 Surface之乾坤大挪移
- 8.3.3 乾坤大挪移的JNI層分析
- 8.3.4 Surface和畫圖
- 8.3.5 初識Surface小結
- 8.4 深入分析Surface
- 8.4.1 與Surface相關的基礎知識介紹
- 8.4.2 SurfaceComposerClient分析
- 8.4.3 SurfaceControl分析
- 8.4.4 writeToParcel和Surface對象的創建
- 8.4.5 lockCanvas和unlockCanvasAndPost分析
- 8.4.6 GraphicBuffer介紹
- 8.4.7 深入分析Surface的總結
- 8.5 SurfaceFlinger分析
- 8.5.1 SurfaceFlinger的誕生
- 8.5.2 SF工作線程分析
- 8.5.3 Transaction分析
- 8.5.4 關于SurfaceFlinger的總結
- 8.6 拓展思考
- 8.6.1 Surface系統的CB對象分析
- 8.6.2 ViewRoot的你問我答
- 8.6.3 LayerBuffer分析
- 8.7 本章小結
- 第9章 深入理解Vold和Rild
- 9.1 概述
- 9.2 Vold的原理與機制分析
- 9.2.1 Netlink和Uevent介紹
- 9.2.2 初識Vold
- 9.2.3 NetlinkManager模塊分析
- 9.2.4 VolumeManager模塊分析
- 9.2.5 CommandListener模塊分析
- 9.2.6 Vold實例分析
- 9.2.7 關于Vold的總結
- 9.3 Rild的原理與機制分析
- 9.3.1 初識Rild
- 9.3.2 RIL_startEventLoop分析
- 9.3.3 RIL_Init分析
- 9.3.4 RIL_register分析
- 9.3.5 關于Rild main函數的總結
- 9.3.6 Rild實例分析
- 9.3.7 關于Rild的總結
- 9.4 拓展思考
- 9.4.1 嵌入式系統的存儲知識介紹
- 9.4.2 Rild和Phone的改進探討
- 9.5 本章小結
- 第10章 深入理解MediaScanner
- 10.1 概述
- 10.2 android.process.media分析
- 10.2.1 MSR模塊分析
- 10.2.2 MSS模塊分析
- 10.2.3 android.process.media媒體掃描工作的流程總結
- 10.3 MediaScanner分析
- 10.3.1 Java層分析
- 10.3.2 JNI層分析
- 10.3.3 PVMediaScanner分析
- 10.3.4 關于MediaScanner的總結
- 10.4 拓展思考
- 10.4.1 MediaScannerConnection介紹
- 10.4.2 我問你答
- 10.5 本章小結