鍍金池/ 教程/ Android/ 第8章 ?深入理解Surface系統(tǒng)
第4章 ?深入理解 Zygote
第10章 深入理解MediaScanner
第3章 ?深入理解init
第8章 ?深入理解Surface系統(tǒng)
第5章 深入理解常見類
第7章 ?深入理解Audio系統(tǒng)
第一章 ?閱讀前的準(zhǔn)備工作
<span>第6章 深入理解Binder</span>
第9章 ?深入理解Vold和Rild
第2章? 深入理解JNI

第8章 ?深入理解Surface系統(tǒng)

本章主要內(nèi)容

·? 詳細分析一個Activity的顯示過程。

·? 詳細分析Surface。

·? 詳細分析SurfaceFlinger。

本章涉及的源代碼文件名及位置:

·?ActivityThread.java

framework/base/core/java/android/app/ActivityThread.java

·? Activity.java

framework/base/core/java/android/app/Activity.java

·? Instrumentation.java

framework/base/core/java/android/app/Instrumentation.java

·? PolicyManager.java

frameworks/policies/base/phone/com/android/internal/policy/impl/PolicyManager.java

·? Policy.java

frameworks/policies/base/phone/com/android/internal/policy/impl/Policy.java

·? PhoneWindow.java

frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindow.java

·? Window.java

framework/base/core/java/android/view/Window.java

·? WindowManagerImpl

framework/ base/core/java/android/view/WindowManagerImpl.java

·? ViewRoot.java

framework/base/core/java/android/view/ViewRoot.java

·? Surface.java

framework/base/core/java/android/view/Surface.java

·? WindowManagerService.java

framework/base/services/java/com/android/server/WindowManagerService.java

·? IWindowSession.aidl

framework/base/core/java/android/view/IWindowSession.aidl

·? IWindow.aidl

framework/base/core/java/android/view/IWindow.aidl

·? SurfaceSession.java

framework/base/core/java/android/view/SurfaceSession.java

·? android_view_Surface.cpp

framework/base/core/jni/android_view_Surface.cpp

·? framebuffer_service.c

system/core/adb/framebuffer_service.c

·? SurfaceComposerClient.cpp

framework/base/libs/surfaceflinger_client/SurfaceComposerClient.cpp

·? SurfaceFlinger.cpp

framework/base/libs/surfaceflinger/SurfaceFlinger.cpp

·? ISurfaceComposer.h

framework/base/include/surfaceflinger/ISurfaceComposer.h

·? Layer.h

framework/base/include/surfaceflinger/Layer.h

·? Layer.cpp

framework/base/libs/surfaceflinger/Layer.cpp

·? LayerBase.cpp

framework/base/libs/surfaceflinger/LayerBase.cpp

·? Surface.cpp

framework/base/libs/surfaceflinger_client/Surface.cpp

·? SharedBufferStack.cpp

framework/base/libs/surfaceflinger_client/SharedBufferStack.cpp

·? GraphicBuffer.h

framework/base/include/ui/GraphicBuffer.h

·? GraphicBuffer.cpp

framework/base/libs/ui/GraphicBuffer.cpp

·? GraphicBufferAllocator.h

framework/base/include/ui/GraphicBufferAllocator.h

·? GraphicBufferAllocator.cpp

framework/base/libs/ui/GraphicBufferAllocator.cpp

·? GraphicBufferMapper.cpp

framework/base/libs/ui/GraphicBufferMapper.cpp

·? Android_natives.h

framework/base/include/ui/egl/Android_natives.h

·? android_native_buffer.h

framework/base/include/ui/android_native_buffer.h

·? native_handle.h

system/core/include/cutils/native_handle.h

·? gralloc.h

hardware/libhardware/include/hardware/gralloc.h

·? ISurface.cpp

framework/base/libs/surfaceflinger_client/ISurface.cpp

·? DisplayHardware.cpp

framework/base/libs/surfaceflinger/DisplayHardware.cpp

8.1 ?概述

Surface是繼Audio系統(tǒng)后要破解第二個復(fù)雜的系統(tǒng)。它的難度和復(fù)雜度遠遠超過了Audio?;谶@種情況,本章將集中精力打通Surface系統(tǒng)的“任督二脈”,這任督二脈分別是:

·? 任脈:應(yīng)用程序和Surface的關(guān)系。

·? 督脈:Surface和SurfaceFlinger之間的關(guān)系。

當(dāng)這二脈打通后,我們就可以自行修煉更高層次的功夫了。圖8-1顯示了這二脈的關(guān)系:

http://wiki.jikexueyuan.com/project/deep-android-v1/images/chapter8/image001.png" alt="image" />

圖8-1 ?Surface系統(tǒng)的任督二脈

其中,左圖是任脈,右圖是督脈。

·? 先看左圖??梢园l(fā)現(xiàn),不論是使用Skia繪制二維圖像,還是用OpenGL繪制三維圖像,最終Application都要和Surface交互。Surface就像是UI的畫布,而App則像是在Surface上作畫。所以要想打通任脈,就須破解App和Surface之間的關(guān)系。

·? 再看右圖。Surface和SurfaceFlinger的關(guān)系,很像Audio系統(tǒng)中AudioTrack和AudioFlinger的關(guān)系。Surface向SurfaceFlinger提供數(shù)據(jù),而SurfaceFlinger則混合數(shù)據(jù)。所謂打通督脈的關(guān)鍵,就是破解Surface和SurfaceFlinger之間的關(guān)系。

目標(biāo)已清楚,讓我們開始“運功”破解代碼吧!

說明:為書寫方便起見,后文將SurfaceFlinger簡寫為SF。

8.2 ?一個Activity的顯示

一般來說,應(yīng)用程序的外表是通過Activity來展示的。那么,Activity是如何完成界面繪制工作的呢?根據(jù)前面所講的知識,應(yīng)用程序的顯示和Surface有關(guān),那么具體到Activity上,它和Surface又是什么關(guān)系呢?

本節(jié)就來討論這些問題。首先從Activity的創(chuàng)建說起。

8.2.1 ?Activity的創(chuàng)建

我們已經(jīng)知道了Activity的生命周期,如onCreate、onDestroy等,但大家是否考慮過這樣一個問題:

·? 如果沒有創(chuàng)建Activity,那么onCreate和onDestroy就沒有任何意義,可這個Activity究竟是在哪里創(chuàng)建的?。

第4章中的“Zygote分裂”一節(jié)已講過,Zygote在響應(yīng)請求后會fork一個子進程,這個子進程是App對應(yīng)的進程,它的入口函數(shù)是ActivityThread類的main函數(shù)。ActivityThread類中有一個handleLaunchActivity函數(shù),它就是創(chuàng)建Activity的地方。一起來看這個函數(shù),代碼如下所示:

[-->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;

??????????//②調(diào)用handleResumeActivity

???????????handleResumeActivity(r.token, false, r.isForward);

?? }

??????......

}

handleLaunchActivity函數(shù)中列出了兩個關(guān)鍵點,下面對其分別介紹。

1. 創(chuàng)建Activity

第一個關(guān)鍵函數(shù)performLaunchActivity返回一個Activity,這個Activity就是App中的那個Activity(僅考慮App中只有一個Activity的情況),它是怎么創(chuàng)建的呢?其代碼如下所示:

[-->ActivityThread.java]

private final ActivityperformLaunchActivity(ActivityRecord r,

Intent customIntent) {

??? ????

???????ActivityInfo aInfo = r.activityInfo;

??????? ......//完成一些準(zhǔn)備工作

??????//Activity定義在Activity.java中

???????Activity activity = null;

???????try {

???????????java.lang.ClassLoader cl = r.packageInfo.getClassLoader();

???? /*

???? mInstrumentation為Instrumentation類型,源文件為Instrumentation.java。

???? 它在newActivity函數(shù)中根據(jù)Activity的類名通過Java反射機制來創(chuàng)建對應(yīng)的Activity,

???? 這個函數(shù)比較復(fù)雜,待會我們再分析它。

???? */

???????????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中g(shù)etContext函數(shù)返回的就是這個ContextImpl類型的對象

???????????????ContextImpl appContext = new ContextImpl();

???????????????......

??????????????//下面這個函數(shù)會調(diào)用Activity的onCreate函數(shù)

???????????????mInstrumentation.callActivityOnCreate(activity, r.state);

?????? ?????????......

???????return activity;

?}

好了,performLaunchActivity函數(shù)的作用明白了吧?

·? 根據(jù)類名以Java反射的方法創(chuàng)建一個Activity。

·? 調(diào)用Activity的onCreate函數(shù),開始SDK中大書特書Activity的生命周期。

那么,在onCreate函數(shù)中,我們一般會做什么呢?在這個函數(shù)中,和UI相關(guān)的重要工作就是調(diào)用setContentView來設(shè)置UI的外觀。接下去,需要看handleLaunchActivity中第二個關(guān)鍵函數(shù)handleResumeActivity。

2. 分析handleResumeActivity

上面已創(chuàng)建好了一個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);

?? }

?????????......//其他處理

}

上面有三個關(guān)鍵點。這些關(guān)鍵點似乎已經(jīng)和UI部分(如View、Window)有聯(lián)系了。那么這些聯(lián)系是在什么時候建立的呢?在分析上面代碼中的三個關(guān)鍵點之前,請大家想想在前面的過程中,哪些地方會和UI掛上鉤呢?

·? 答案就在onCreate函數(shù)中,Activity一般都在這個函數(shù)中通過setContentView設(shè)置UI界面。

看來,必須先分析setContentView,才能繼續(xù)后面的征程。

3. 分析setContentView

setContentView有好幾個同名函數(shù),現(xiàn)在只看其中的一個就可以了。代碼如下所示:

[-->Activity.java]

public void setContentView(View view) {

//getWindow返回的是什么呢?一起來看看。

?getWindow().setContentView(view);

}

?

public Window getWindow() {

? returnmWindow; //返回一個類型為Window的mWindow,它是什么?

}

上面出現(xiàn)了兩個和UI有關(guān)系的類:View和Window[①]。來看SDK文檔是怎么描述這兩個類的。這里先給出原文描述,然后進行對應(yīng)翻譯:

·? 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是一個抽象基類,用于控制頂層窗口的外觀和行為。做為頂層窗口它有什么特殊的職能呢?即繪制背景和標(biāo)題欄、默認(rèn)的按鍵處理等。

這里面有一句比較關(guān)鍵的話:它將做為一個頂層的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單元,占據(jù)屏幕的一塊矩形區(qū)域,可用于繪制,并能處理事件。

從上面的View和Window的描述,再加上setContentView的代碼,我們能想象一下這三者的關(guān)系,如圖8-2所示:

http://wiki.jikexueyuan.com/project/deep-android-v1/images/chapter8/image002.png" alt="image" />

圖8-2 ?Window/View的假想關(guān)系圖

根據(jù)上面的介紹,大家可能會產(chǎn)生兩個疑問:

·? Window是一個抽象類,它實際的對象到底是什么類型?

·? Window Manager究竟是什么?

如果能有這樣的疑問,就說明我們非常細心了。下面試來解決這兩個問題。

(1)Activity的Window

據(jù)上文講解可知,Window是一個抽象類。它實際的對象到底屬于什么類型?先回到Activity創(chuàng)建的地方去看看。下面正是創(chuàng)建Activity時的代碼,可當(dāng)時沒有深入地分析。

activity = mInstrumentation.newActivity(

??????????????????? cl,component.getClassName(), r.intent);

代碼中調(diào)用了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;

??????? //關(guān)鍵函數(shù)attach!!

???????activity.attach(context, aThread, this, token, application, intent,

info, title,parent, id, lastNonConfigurationInstance,

new Configuration());

???????return activity;

??? }

看到關(guān)鍵函數(shù)attach了吧?Window的真相馬上就要揭曉了,讓我們用咆哮體來表達內(nèi)心的激動之情吧?。。?!

[-->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來創(chuàng)建Window對象

???????mWindow = PolicyManager.makeNewWindow(this);

???????mWindow.setCallback(this);

??????? ......

??????? //創(chuàng)建WindowManager對象

???????mWindow.setWindowManager(null, mToken, mComponent.flattenToString());

??????? if(mParent != null) {

???????????mWindow.setContainer(mParent.getWindow());

??????? }

?????? //保存這個WindowManager對象

???????mWindowManager = mWindow.getWindowManager();

???????mCurrentConfig = config;

}

此刻又有一點失望吧?這里冒出了個PolicyManager類,Window是由它的makeNewWindow函數(shù)所創(chuàng)建,因此還必須再去看看這個PolicyManager。

(2)水面下的冰山——PolicyManager

PolicyManager定義于PolicyManager.java文件,該文件在一個非常獨立的目錄下,現(xiàn)將其單獨列出來:

·? frameworks/policies/base/phone/com/android/internal/policy/impl

注意,上面路徑中的灰色目錄phone是針對智能手機這種小屏幕的;另外還有一個平級的目錄叫mid,是針對Mid設(shè)備的。mid目錄的代碼比較少,可能目前還沒有開發(fā)完畢。

下面來看這個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);

???????????//創(chuàng)建Policy對象

???????????sPolicy = (IPolicy)policyClass.newInstance();

??????? }catch (ClassNotFoundException ex) {

????????????......

??? ???}

?

????private PolicyManager() {}

?

??? //通過Policy對象的makeNewWindow創(chuàng)建一個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。現(xiàn)在就來揭示其真面目。

(4)真正的WindowManager

先看WindowManager創(chuàng)建的代碼,如下所示:

[-->Activity.java]

??......//創(chuàng)建mWindow對象

?? //調(diào)用mWindow的setWindowManager函數(shù)

mWindow.setWindowManager(null, mToken,mComponent.flattenToString());

?? .....

上面的函數(shù)設(shè)置了PhoneWindow的WindowManager,不過第一個參數(shù)是null,這是什么意思?在回答此問題之前,先來看PhoneWindow的定義,它是從Window類派生。

[-->PhoneWindow.java::PhoneWindow定義]

public class PhoneWindow extends Windowimplements MenuBuilder.Callback

前面調(diào)用的setWindowManager函數(shù),其實是由PhoneWindow的父類Window類來實現(xiàn)的,來看其代碼,如下所示:

[-->Window.java]

public void setWindowManager(WindowManagerwm,IBinder appToken, String appName) {?????//注意,傳入的wm值為null

???????mAppToken = appToken;

???????mAppName = appName;

??????? if(wm == null) {

??????????//如果wm為空的話,則創(chuàng)建WindowManagerImpl對象

???????????wm = WindowManagerImpl.getDefault();

??????? }

?????? //mWindowManager是一個LocalWindowManager

???????mWindowManager = new LocalWindowManager(wm);

??? }

LocalWindowManager是在Window中定義的內(nèi)部類,請看它的構(gòu)造函數(shù),其定義如下所示:

[-->Window.java::LocalWindowManager定義]

private class LocalWindowManager implementsWindowManager {

???????LocalWindowManager(WindowManager wm) {

???????????mWindowManager = wm;//還好,只是簡單地保存了傳入的wm參數(shù)

???????????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();

}

看到這里,是否有點頭暈眼花?很多朋友讀我的一篇與此內(nèi)容相關(guān)的博文后,普遍也有如此反應(yīng)。對此,試配制了一劑治暈藥方,如圖8-3所示:

http://wiki.jikexueyuan.com/project/deep-android-v1/images/chapter8/image003.png" alt="image" />

圖8-3 ?Window和WindowManger的家族圖譜

根據(jù)上圖,可得出以下結(jié)論:

·? Activity的mWindow成員變量其真實類型是PhoneWindow,而mWindowManager成員變量的真實類型是LocalWindowManager。

·? LocalWindowManager和WindowManagerImpl都實現(xiàn)了WindowManager接口。這里采用的是Proxy模式,表明LocalWindowManager將把它的工作委托WindowManagerImpl來完成。

(5)setContentView的總結(jié)

了解了上述知識后,重新回到setContentView函數(shù)。這次希望能分析得更深入些。

[-->Activity.java]

public void setContentView(View view) {

???????getWindow().setContentView(view);//getWindow返回的是PhoneWindow

}

一起來看PhoneWindow的setContentView函數(shù),代碼如下所示:

[-->PhoneWindow]

public void setContentView(View view) {

?? //調(diào)用另一個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種設(shè)計模式中的Composite模式,它是UI編程中常用的模式之一。

再來看installDecor函數(shù),其代碼如下所示:

[-->PhoneWindow.java]

private void installDecor() {

?? ?if (mDecor == null) {

???? //創(chuàng)建mDecor,它為DecorView類型,從FrameLayout派生

???? mDecor= generateDecor();

? ??????????......

?? }

? if(mContentParent == null) {

???? //得到這個mContentParent

mContentParent = generateLayout(mDecor);

//創(chuàng)建標(biāo)題欄

??? mTitleView= (TextView)findViewById(com.android.internal.R.id.title);

......

}

generateLayout函數(shù)的輸入?yún)?shù)為mDecor,輸出為mContentParent,代碼如下所示:

[-->PhoneWindow]

protected ViewGroup generateLayout(DecorViewdecor){

? ......

? intlayoutResource;

? intfeatures = getLocalFeatures();

? if((features & ((1 << FEATURE_LEFT_ICON) |(1 <<FEATURE_RIGHT_ICON))) != 0) {

????? if(mIsFloating) {

????? //根據(jù)情況取得對應(yīng)標(biāo)題欄的資源id

?????layoutResource = ?com.android.internal.R.layout.dialog_title_icons;

???? }

???????......

}

?

? mDecor.startChanging();

?

?View in =mLayoutInflater.inflate(layoutResource, null);

?//加入標(biāo)題欄

?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是如何實現(xiàn)的。它定義在Window.java中,代碼如下所示:

[-->Window.java]

public View findViewById(int id) {

??//getDecorView將返回mDecorView,所以contentParent確實是DecorView的一部分

?? returngetDecorView().findViewById(id);

?}

大家還記得圖8-2嗎?介紹完上面的知識后,根據(jù)圖8-2,可繪制更細致的圖8-4:

http://wiki.jikexueyuan.com/project/deep-android-v1/images/chapter8/image004.png" alt="image" />

圖8-4 ?一個Activity中的UI組件

可從上圖中看出,在Activity的onCreate函數(shù)中,通過setContentView設(shè)置的View,其實只是DecorView的子View。DecorView還處理了標(biāo)題欄顯示等一系列的工作。

注意,這里使用了設(shè)計模式中的Decorator(裝飾)模式,它也是UI編程中常用的模式之一。

?

4. 重回handleResumeActivity

看完setContentView的分析后,不知大家是否還記得這樣一個問題:為什么要分析這個setContentView函數(shù)?在繼續(xù)前行之前,先來回顧一下被setContentView打斷的流程。

當(dāng)時,我們正在分析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對象?,F(xiàn)在知道這個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);

?? }

......//其他處理

}

在上面的代碼中,由于出現(xiàn)了多個之前不熟悉的東西,如View、ViewManager等,而這些東西的來源又和setContentView有關(guān),所以我們才轉(zhuǎn)而去分析setContentView了。想起來了吧?

由于代碼比較長,跳轉(zhuǎn)關(guān)系也很多,在分析代碼時,請讀者把握流程,在大腦中建立一個代碼分析的堆棧。

下面就從addView的分析開始。如前面所介紹的,它的調(diào)用方法是:

wm.addView(decor, l);//wm類型實際是LocalWindowManager

來看這個addView函數(shù),它的代碼如下所示:

[-->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函數(shù)還是比較麻煩的,因為現(xiàn)在必須到WindowManagerImpl中去看看。它的代碼如下所示:

[-->WindowManagerImpl.java]

private void addView(View view,ViewGroup.LayoutParams params, boolean nest)

{

? ViewRootroot; //ViewRoot,幕后的主角終于登場了!

? synchronized(this) {

? //①創(chuàng)建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 ....”,主角終于出場了!即使沒介紹它的真實身份,不禁也想歡呼幾聲??蔀楸苊飧吲d得過早,還是應(yīng)該先冷靜地分析一下它。這里,列出了ViewRoot的兩個重要關(guān)鍵點。

(1)ViewRoot是什么?

ViewRoot是什么?看起來好像和View有些許關(guān)系,至少名字非常像。事實上,它的確和View有關(guān)系,因為它實現(xiàn)了ViewParent接口。SDK的文檔中有關(guān)于ViewParent的介紹。但它和Android基本繪圖單元中的View卻不太一樣,比如:ViewParent不處理繪畫,因為它沒有onDraw函數(shù)。

如上所述,ViewParent和繪畫沒有關(guān)系,那么,它的作用是什么?先來看它的代碼,如下所示:

[-->ViewRoot.java::ViewRoot定義]

public final class ViewRoot extends Handlerimplements ViewParent,

???????View.AttachInfo.Callbacks //從Handler類派生

{

private final Surface mSurface = new Surface();//這里創(chuàng)建了一個Surface對象

final W mWindow;?//這個是什么?

View mView;

}

上面這段代碼傳達出了一些重要信息:

·? ViewRoot繼承了Handler類,看來它能處理消息。ViewRoot果真重寫了handleMessage函數(shù)。稍侯再來看它。

·? ViewRoot有一個成員變量叫mSurface,它是Surface類型。

·? ViewRoot還有一個W類型的mWindow和一個View類型的mView變量。

其中,W是ViewRoot定義的一個靜態(tài)內(nèi)部類:

static class W extends IWindow.Stub

這個類將參與Binder的通信,以后對此再做講解,先來介紹Surface類。

(2)神筆馬良乎?

這里冒出來一個Surface類。它是什么?在回答此問題之前,先來考慮這樣一個問題:

·? 前文介紹的View、DecorView等都是UI單元,這些UI單元的繪畫工作都在onDraw函數(shù)中完成。如果把onDraw想象成畫圖過程,那么畫布是什么?

Android肯定不是“馬良”,它也沒有那支可以在任何物體上作畫的“神筆”,所以我們需要一塊實實在在的畫布,這塊畫布就是Surface。SDK文檔對Surface類的說明是:Handle on to a raw buffer thatis being managed by the screen compositor。這句話的意思是:

·? 有一塊Raw buffer,至于是內(nèi)存還是顯存,不必管它。

·? Surface操作這塊Raw buffer。

·? Screen compositor(其實就是SurfaceFlinger)管理這塊Raw buffer。

Surface和SF、ViewRoot有什么關(guān)系呢?相信,聰明的你此時已經(jīng)明白些了,這里用圖8-5描繪一下心中的想法:

http://wiki.jikexueyuan.com/project/deep-android-v1/images/chapter8/image005.png" alt="image" />

圖8-5 ?馬良的神筆工作原理

結(jié)合之前所講的知識,圖8-5清晰地傳達了如下幾條信息:

·? ViewRoot有一個成員變量mSurface,它是Surface類型,它和一塊Raw Buffer有關(guān)聯(lián)。

·? ViewRoot是一個ViewParent,它的子View的繪畫操作,是在畫布Surface上展開的。

·? Surface和SurfaceFlinger有交互,這非常類似AudioTrack和AudioFlinger之間的交互。

既然本章題目為“深入理解Surface系統(tǒng)”,那么就需要重點關(guān)注Surface和SurfaceFlinger間的關(guān)系。建立這個關(guān)系需ViewRoot的參與,所以應(yīng)先來分析ViewRoot的創(chuàng)建和它的setView函數(shù)。

(3)ViewRoot的創(chuàng)建和對setView的分析

來分析ViewRoot的構(gòu)造。關(guān)于它所包含內(nèi)容,代碼如下所示:

[-->ViewRoot.java]

public ViewRoot(Context context) {

???????super();

??????....

?????? // getWindowSession?我們進去看看

??????getWindowSession(context.getMainLooper());

?????......//ViewRoot的mWindow是一個W類型,注意它不是Window類型,而是IWindow類型

?????? mWindow= new W(this, context);

}

getWindowsession函數(shù),將建立Activity的ViewRoot和WindowManagerService的關(guān)系。代碼如下所示:

[-->ViewRoot.java]

ublic static IWindowSessiongetWindowSession(Looper mainLooper) {

synchronized (mStaticInit) {

? if(!mInitialized) {

?? try {

????? InputMethodManagerimm =

???????? InputMethodManager.getInstance(mainLooper);

????? //下面這個函數(shù)先得到WindowManagerService的Binder代理,然后調(diào)用它的openSession

sWindowSession = IWindowManager.Stub.asInterface(

?????????????????? ServiceManager.getService("window"))

?????????????????.openSession(imm.getClient(), imm.getInputContext());

??????????????????? mInitialized = true;

???????????????} catch (RemoteException e) {

???????????????}

???????????}

???????????return sWindowSession;

??????? }

??? }

WindowSession?WindowManagerService?第一次看到這些東西時,我快瘋了。復(fù)雜,太復(fù)雜,無比復(fù)雜!要攻克這些難題,應(yīng)先來回顧一下與Zygote相關(guān)的知識:

·? WindowManagerService(以后簡稱WMS)由System_Server進程啟動,SurfaceFlinger服務(wù)也在這個進程中。

看來,Activity的顯示還不單純是它自己的事,還需要和WMS建立聯(lián)系才行。繼續(xù)看。先看setView的處理。這個函數(shù)很復(fù)雜,注意其中關(guān)鍵的幾句。

openSession的操作是一個使用Binder通信的跨進程調(diào)用,暫且記住這個函數(shù),在精簡流程之后再來分析。

代碼如下所示:

[-->ViewRoot.java]

public void setView(View view, WindowManager.LayoutParamsattrs,

????????????????????????View panelParentView){//第一個參數(shù)view是DecorView

??????......

?????? mView= view;//保存這個view

???????synchronized (this) {

???????????requestLayout(); //待會先看看這個。

???????????????try {

??????????????????? //調(diào)用IWindowSession的add函數(shù),第一個參數(shù)是mWindow

??????????????????? res =sWindowSession.add(mWindow, mWindowAttributes,

???????????????????????????getHostVisibility(), mAttachInfo.mContentInsets);

???????????????}

??? ??????......

}

ViewRoot的setView函數(shù)做了三件事:

·? 保存?zhèn)魅氲膙iew參數(shù)為mView,這個mView指向PhoneWindow的DecorView。

·? 調(diào)用requestLayout。

·? 調(diào)用IWindowSession的add函數(shù),這是一個跨進程的Binder通信,第一個參數(shù)是mWindow,它是W類型,從IWindow.stub派生。

先來看這個requestLayout函數(shù),它非常簡單,就是往handler中發(fā)送了一個消息。注意,ViewRoot是從Handler派生的,所以這個消息最后會由ViewRoot自己處理,代碼如下所示:

[-->ViewRoot.java]

public void requestLayout() {

???????checkThread();

???????mLayoutRequested = true;

???????scheduleTraversals();

}

public void scheduleTraversals() {

??????? if(!mTraversalScheduled) {

???????????mTraversalScheduled = true;

???????????sendEmptyMessage(DO_TRAVERSAL); //發(fā)送DO_TRAVERSAL消息

??????? }

}

好,requestLayout分析完畢。

從上面的代碼中可發(fā)現(xiàn),ViewRoot和遠端進程SystemServer的WMS有交互,先來總結(jié)一下它和WMS的交互流程:

·? ViewRoot調(diào)用openSession,得到一個IWindowSession對象。

·? 調(diào)用WindowSession對象的add函數(shù),把一個W類型的mWindow對象做為參數(shù)傳入。

5. ViewRoot和WMS的關(guān)系

上面總結(jié)了ViewRoot和WMS的交互流程,其中一共有兩個跨進程的調(diào)用。一起去看。

(1)調(diào)用流程分析

WMS的代碼在WindowManagerService.java中:

[-->WindowManagerService.java]

public IWindowSessionopenSession(IInputMethodClient client,

????????????????????????????????????????IInputContextinputContext) {

?????? ......

return new Session(client, inputContext);

}

Session是WMS定義的內(nèi)部類。它支持Binder通信,并且屬于Bn端,即響應(yīng)請求的服務(wù)端。

再來看它的add函數(shù)。代碼如下所示:

[-->WindowManagerService.java::Session]

public int add(IWindow window,WindowManager.LayoutParams attrs,

???????????????int viewVisibility, Rect outContentInsets) {

??? //調(diào)用外部類對象的addWindow,也就是WMS的addWindow

??? returnaddWindow(this, window, attrs, viewVisibility,

??????????????????????????????? outContentInsets);

}

[-->WindowManagerService.java]

public int addWindow(Session session, IWindowclient,

???????????WindowManager.LayoutParams attrs, int viewVisibility,

???????????Rect outContentInsets) {

???????????......

??????????//創(chuàng)建一個WindowState

??????????win = new WindowState(session, client, token,

??????????????????? attachedWindow, attrs,viewVisibility);

?????? ???......

?????????//調(diào)用attach函數(shù)

??????????win.attach();

??????????......

??????????return res;

}

WindowState類也是在WMS中定義的內(nèi)部類,直接看它的attach函數(shù),代碼如下所示:

[-->WMS.java::WindowState]

void attach() {

????? //mSession就是Session對象,調(diào)用它的windowAddedLocked函數(shù)

?????mSession.windowAddedLocked();

}

[-->WMS.java::Session]

void windowAddedLocked() {

? if(mSurfaceSession == null) {

??????? ......

?????? //創(chuàng)建一個SurfaceSession對象

?????? mSurfaceSession= new SurfaceSession();

?????? ......

???? }

???? ?mNumWindow++;

}

這里出現(xiàn)了另外一個重要的對象SurfaceSession。在講解它之前,急需理清一下現(xiàn)有的知識點,否則可能會頭暈。

(2)ViewRoot和WMS的關(guān)系梳理

ViewRoot和WMS之間的關(guān)系,可用圖8-6來表示:

http://wiki.jikexueyuan.com/project/deep-android-v1/images/chapter8/image006.png" alt="image" />

圖8-6 ?ViewRoot和WMS的關(guān)系

總結(jié)一下圖8-6中的知識點:

·? ViewRoot通過IWindowSession和WMS進程進行跨進程通信。IWindowSession定義在IWindowSession.aidl文件中。這個文件在編譯時由aidl工具處理,最后會生成類似于Native Binder中Bn端和Bp端的代碼,后文會介紹它。

·? ViewRoot內(nèi)部有一個W類型的對象,它也是一個基于Binder通信的類,W是IWindow的Bn端,用于響應(yīng)請求。IWindow定義在另一個aidl文件IWindow.aidl中。

為什么需要這兩個特殊的類呢?簡單介紹一下: