本章主要內(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
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。
一般來說,應(yīng)用程序的外表是通過Activity來展示的。那么,Activity是如何完成界面繪制工作的呢?根據(jù)前面所講的知識,應(yīng)用程序的顯示和Surface有關(guān),那么具體到Activity上,它和Surface又是什么關(guān)系呢?
本節(jié)就來討論這些問題。首先從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)鍵點,下面對其分別介紹。
第一個關(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。
上面已創(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ù)后面的征程。
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究竟是什么?
如果能有這樣的疑問,就說明我們非常細心了。下面試來解決這兩個問題。
據(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。
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類型,請看它的定義。
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)在就來揭示其真面目。
先看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來完成。
了解了上述知識后,重新回到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編程中常用的模式之一。
?
看完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)鍵點。
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類。
這里冒出來一個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ù)。
來分析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ù)傳入。
上面總結(jié)了ViewRoot和WMS的交互流程,其中一共有兩個跨進程的調(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)有的知識點,否則可能會頭暈。
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中。
為什么需要這兩個特殊的類呢?簡單介紹一下: