1. 程式人生 > >Android深入淺出之Surface[1]

Android深入淺出之Surface[1]

Android深入淺出之Surface

目的

本節的目的就是為了講清楚Android中的Surface系統,大家耳熟能詳的SurfaceFlinger到底是個什麼東西,它的工作流程又是怎樣的。當然,鑑於SurfaceFlinger的複雜性,我們依然將採用情景分析的辦法,找到合適的切入點。

一個Activity是怎麼在螢幕上顯示出來的呢?我將首先把這個說清楚。

接著我們把其中的關鍵呼叫抽象在Native層,以這些函式呼叫為切入點來研究SurfaceFlinger。好了,開始我們的征途吧。

Activity是如何顯示的

最初的想法就是,Activity獲得一塊視訊記憶體,然後在上面繪圖,最後交給裝置去顯示。這個道理是沒錯,但是

AndroidSurfaceFlinger是在System Server程序中建立的,Activity一般另有執行緒,這之間是如何...如何掛上關係的呢?我可以先提前告訴大家,這個過程還比較複雜。呵呵。

好吧,我們從Activity最初的啟動開始。程式碼在

framework/base/core/java/android/app/ActivityThread.java中,這裡有個函式叫handleLaunchActivity

[---->ActivityThread:: handleLaunchActivity()]

private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {

Activity a = performLaunchActivity(r, customIntent);

if (a != null) {

r.createdConfig = new Configuration(mConfiguration);

Bundle oldState = r.state;

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

---->呼叫handleResumeActivity

}

handleLaunchActivity中會呼叫handleResumeActivity

[--->ActivityThread:: handleResumeActivity]

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 decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();

a.mDecor = decor;

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

if (a.mVisibleFromClient) {

a.mWindowAdded = true;

wm.addView(decor, l); //這個很關鍵。

}

上面addView那幾行非常關鍵,它關係到咱們在ActivitysetContentView後,整個Window到底都包含了些什麼。我先告訴大家。所有你建立的View之上,還有一個DecorView,這是一個FrameLayout,另外還有一個PhoneWindow。上面這些東西的程式碼在

framework/Policies/Base/Phone/com/android/Internal/policy/impl。這些隱藏的View的建立都是由你在AcitivtyonCreate中呼叫setContentView導致的。

[---->PhoneWindow:: addContentView]

public void addContentView(View view, ViewGroup.LayoutParams params) {

if (mContentParent == null) {//剛建立的時候mContentParent為空

installDecor();

}

mContentParent.addView(view, params);

final Callback cb = getCallback();

if (cb != null) {

cb.onContentChanged();

}

}

installDecor將建立mDecormContentParentmDecorDecorView型別,

mContentParentViewGroup型別

private void installDecor() {

if (mDecor == null) {

mDecor = generateDecor();

mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);

mDecor.setIsRootNamespace(true);

}

if (mContentParent == null) {

mContentParent = generateLayout(mDecor);

那麼,ViewManager wm = a.getWindowManager()又返回什麼呢?

PhoneWindowWindow中派生,Acitivity建立的時候會呼叫它的setWindowManager。而這個函式由Window類實現。

程式碼在framework/base/core/java/android/view/Window.java

public void setWindowManager(WindowManager wm,IBinder appToken, String appName) {

mAppToken = appToken;

mAppName = appName;

if (wm == null) {

wm = WindowManagerImpl.getDefault();

}

mWindowManager = new LocalWindowManager(wm);

}

你看見沒,分析JAVA程式碼這個東西真的很複雜。mWindowManager的實現是LocalWindowManager,但由通過Bridge模式把功能交給WindowManagerImpl去實現了。

真的很複雜!

好了,羅裡羅嗦的,我們回到wm.addView(decor, l)。最終會由WindowManagerImpl來完成

addView操作,我們直接看它的實現好了。

程式碼在framework/base/core/java/android/view/WindowManagerImpl.java

[---->addView]

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

{

ViewRoot root; //ViewRoot,我們的主人公終於登場!

synchronized (this) {

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;

mParams[index] = wparams;

}

root.setView(view, wparams, panelParentView);

}

ViewRoot是整個顯示系統中最為關鍵的東西,看起來這個東西好像和View有那麼點關係,其實它根本和ViewUI關係不大,它不過是一個Handler罷了,唯一有關係的就是它其中有一個變數為Surface型別。我們看看它的定義。ViewRoot程式碼在

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

public final class ViewRoot extends Handler implements ViewParent,

View.AttachInfo.Callbacks

{

private final Surface mSurface = new Surface();

}

它竟然從handler派生,而ViewParent不過定義了一些介面函式罷了。

看到Surface直覺上感到它和SurfaceFlinger有點關係。要不先去看看?

Surface程式碼在framework/base/core/java/android/view/Surface.java中,我們呼叫的是無參建構函式。

public Surface() {

mCanvas = new CompatibleCanvas(); //就是建立一個Canvas

}

如果你有興趣的話,看看Surface其他建構函式,最終都會呼叫native的實現,而這些native的實現將和SurfaceFlinger建立關係,但我們這裡ViewRoot中的mSurface顯然還沒有到這一步。那它到底是怎麼和SurfaceFlinger搞上的呢?這一切待會就會水落石出的。

另外,為什麼ViewRoot是主人公呢?因為ViewRoot建立了客戶端和SystemServer的關係。我們看看它的建構函式。

public ViewRoot(Context context) {

super();

....

getWindowSession(context.getMainLooper());

}

getWindowsession將建立和WindowManagerService的關係。

ublic static IWindowSession getWindowSession(Looper mainLooper) {

synchronized (mStaticInit) {

if (!mInitialized) {

try {

//sWindowSession是通過Binder機制建立的。終於讓我們看到點希望了

InputMethodManager imm = InputMethodManager.getInstance(mainLooper);

sWindowSession = IWindowManager.Stub.asInterface(

ServiceManager.getService("window"))

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

mInitialized = true;

} catch (RemoteException e) {

}

}

return sWindowSession;

}

}

上面跨Binder的程序呼叫另一端是WindowManagerService,程式碼在

framework/base/services/java/com/android/server/WindowManagerService.java中。我們先不說這個。

回過頭來看看ViewRoot接下來的呼叫。

[-->ViewRoot::setView()],這個函式很複雜,我們看其中關鍵幾句。

public void setView(View view, WindowManager.LayoutParams attrs,

View panelParentView) {

synchronized (this) {

requestLayout();

try {

res = sWindowSession.add(mWindow, mWindowAttributes,

getHostVisibility(), mAttachInfo.mContentInsets);

}

}

requestLayout實現很簡單,就是往handler中傳送了一個訊息。

public void requestLayout() {

checkThread();

mLayoutRequested = true;

scheduleTraversals(); //傳送DO_TRAVERSAL訊息

}

public void scheduleTraversals() {

if (!mTraversalScheduled) {

mTraversalScheduled = true;

sendEmptyMessage(DO_TRAVERSAL);

}

}

我們看看跨程序的那個呼叫。sWindowSession.add。它的最終實現在WindowManagerService中。

[--->WindowSession::add()]

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

int viewVisibility, Rect outContentInsets) {

return addWindow(this, window, attrs, viewVisibility, outContentInsets);

}

WindowSession是個內部類,會呼叫外部類的addWindow

這個函式巨複雜無比,但是我們的核心目標是找到建立顯示相關的部分。所以,最後精簡的話就簡單了。

[--->WindowManagerService:: addWindow]

public int addWindow(Session session, IWindow client,

WindowManager.LayoutParams attrs, int viewVisibility,

Rect outContentInsets) {

//建立一個WindowState,這個又是什麼玩意兒呢?

win = new WindowState(session, client, token,

attachedWindow, attrs, viewVisibility);

win.attach();

return res;

}

WindowState類中有一個和Surface相關的成員變數,叫SurfaceSession。它會在

attach函式中被建立。SurfaceSession嘛,就和SurfaceFlinger有關係了。我們待會看。

好,我們知道ViewRoot建立及呼叫add後,我們客戶端的View系統就和WindowManagerService建立了牢不可破的關係。

另外,我們知道ViewRoot是一個handler,而且剛才我們呼叫了requestLayout,所以接下來訊息迴圈下一個將呼叫的就是ViewRoothandleMessage

public void handleMessage(Message msg) {

switch (msg.what) {

case DO_TRAVERSAL:

performTraversals();

performTraversals更加複雜無比,經過我仔細挑選,目標鎖定為下面幾個函式。當然,後面我們還會回到performTraversals,不過我們現在更感興趣的是Surface是如何建立的。

private void performTraversals() {

// cache mView since it is used so much below...

final View host = mView;

boolean initialized = false;

boolean contentInsetsChanged = false;

boolean visibleInsetsChanged;

try {

//ViewRoot也有一個Surface成員變數,叫mSurface,這個就是代表SurfaceFlinger的客戶端

//ViewRoot在這個Surface上作畫,最後將由SurfaceFlinger來合成顯示。剛才說了mSurface還沒有什麼內容。

relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

[---->ViewRoot:: relayoutWindow()]

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,

boolean insetsPending) throws RemoteException {

//relayOut是跨程序呼叫,mSurface做為引數傳進去了,看來離真相越來越近了呀!

int relayoutResult = sWindowSession.relayout(

mWindow, params,

(int) (mView.mMeasuredWidth * appScale + 0.5f),

(int) (mView.mMeasuredHeight * appScale + 0.5f),

viewVisibility, insetsPending, mWinFrame,

mPendingContentInsets, mPendingVisibleInsets,

mPendingConfiguration, mSurface); mSurface做為引數傳進去了。

}

我們趕緊轉到WindowManagerService去看看吧。、

public int relayoutWindow(Session session, IWindow client,

WindowManager.LayoutParams attrs, int requestedWidth,

int requestedHeight, int viewVisibility, boolean insetsPending,

Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,

Configuration outConfig, Surface outSurface){

.....

try {

//看到這裡,我內心一陣狂喜,有戲,太有戲了!

//其中win是我們最初建立的WindowState

Surface surface = win.createSurfaceLocked();

if (surface != null) {

//先建立一個本地surface,然後把傳入的引數outSurface copyFrom一下

outSurface.copyFrom(surface);

win.mReportDestroySurface = false;

win.mSurfacePendingDestroy = false;

} else {

outSurface.release();

}

}

}

[--->WindowState::createSurfaceLocked]

Surface createSurfaceLocked() {

try {

mSurface = new Surface(

mSession.mSurfaceSession, mSession.mPid,

mAttrs.getTitle().toString(),

0, w, h, mAttrs.format, flags);

}

Surface.openTransaction();

這裡使用了Surface的另外一個建構函式。

public Surface(SurfaceSession s,

int pid, String name, int display, int w, int h, int format, int flags)

throws OutOfResourcesException {

mCanvas = new CompatibleCanvas();

init(s,pid,name,display,w,h,forma