Android的UI顯示原理之Surface的建立

susion發表於2019-01-15

本文是Android檢視層原始碼分析系列第二篇文章,通過上一篇文章深入剖析Window組成已經瞭解到WindowManager.addView(contentView)最終會交給WindowManagerService處理,WindowManagerService會建立這個contentView相關的UI載體Surface,本文的目的就是理清Surface的建立過程,以及它與SurfaceFlinger的關係。

文章比較長,但希望你可以堅持看完,相信會有一定收穫的

本文是基於Google Android Repo中的較新的原始碼分析的。Android UI渲染這一塊變化還是比較大的,邏輯可能和網上大部分文章有一些出入。

在本文正式開始之前,我們先來了解一下與SurfaceFlinger相關的基礎知識:

  • 與SurfaceFlinger相關的基礎知識

SurfaceFlinger可以說是Android UI渲染體系的核心,在Android系統啟動時會啟動SurfaceFlinger服務,它的主要作用就是被Android應用程式呼叫,把繪製(測量,佈局,繪製)後的視窗(Surface)渲染到手機螢幕上。所以整個 UI重新整理過程可能像下面這張圖:

Android的UI顯示原理之Surface的建立

當然實際上的UI渲染原理可沒有像上圖那樣這麼簡單。為了接下來在原始碼追蹤的過程中不迷路,我們帶著下面幾個問題來開始分析:

  1. WindowManagerService是如何管理Window的?
  2. Surface是如何建立的?
  3. SurfaceFlinger是如何管理多個應用的UI渲染的?
  4. SurfaceFlinger中UI渲染的基本單元是什麼?

ok,接下來就開始Android UI顯示原理之Surface的建立的主要流程分析。由於整個體系的原始碼流程很複雜,因此在追蹤原始碼時我只貼了一些整個流程分析中的主要節點,並且加了一些註釋。

在上一篇文章中我們知道,ViewRootImpl管理著整個view tree。 對於ViewRootImpl.setView(),我們可以簡單的把它當做一個UI渲染操作的入口,因此我們就從這個方法開始看:

WindowManagerService對於Window的管理

ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    ...
    //mWindowSession是一個aidl,ViewRootImpl利用它來和WindowManagerService互動
    //mWindow是一個aidl,WindowManagerService可以利用這個物件與服務端互動
    //mAttachInfo可以理解為是一個data bean,可以跨程式傳遞
    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
            getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
            mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
    ...
}
複製程式碼

ViewRootImpl.setView()方法會向WindowManagerService請求新增一個Window,mWindowSession.addToDisplay()跨程式最終呼叫到了WindowManagerService.addWindow():

WindowManagerService.java

public int addWindow(Session session, IWindow client...) {
    ...
    //WindowState用來描述一個Window
    final WindowState win = new WindowState(this, session, client, token, parentWindow,
                appOp[0], seq, attrs, viewVisibility, session.mUid,
                session.mCanAddInternalSystemWindow);
    ...
    win.attach();  //會建立一個SurfaceSession

    mWindowMap.put(client.asBinder(), win); //mWindowMap是WindowManagerService用來儲存當前所有Window新的的集合
    ...
    win.mToken.addWindow(win); //一個token下會有多個win state。 其實token與PhoneWindow是一一對應的。
    ...
}
複製程式碼

WindowStateWindowManagerService用來描述應用程式的一個Window的物件。上面註釋我標註了win.attach(),這個方法可以說是WindowSurfaceFlinger連結的起點,它最終會呼叫到Session.windowAddedLocked():

Session.java

void windowAddedLocked(String packageName) {
    ...
    if (mSurfaceSession == null) { 
        ...
        mSurfaceSession = new SurfaceSession();
        ...
    }
}

//SurfaceSession類的構造方法
public final class SurfaceSession {
    private long mNativeClient; // SurfaceComposerClient*

    public SurfaceSession() {
        mNativeClient = nativeCreate(); 
    }
複製程式碼

這裡呼叫了native方法nativeCreate(),這個方法其實是返回了一個SurfaceComposerClient指標。那這個物件是怎麼建立的呢?

SurfaceComposerClient的建立

android_view_SurfaceSession.cpp

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    SurfaceComposerClient* client = new SurfaceComposerClient(); //建構函式其實並沒有做什麼
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(client);
}
複製程式碼

即構造了一個SurfaceComposerClient物件。並返回它的指標。這個物件一個應用程式就有一個,它是應用程式與SurfaceFlinger溝通的橋樑,為什麼這麼說呢?在SurfaceComposerClient指標第一次使用時會呼叫下面這個方法:

//這個方法在第一次使用SurfaceComposerClient的指標的時候會呼叫
void SurfaceComposerClient::onFirstRef() {
    ....
    sp<ISurfaceComposerClient> conn;
    //sf 就是SurfaceFlinger
    conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
            sf->createConnection();
    ...
}
複製程式碼

即通過SurfaceFlinger(它本身具有跨程式通訊的能力)建立了一個ISurfaceComposerClient物件:

SurfaceFlinger.cpp

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    return initClient(new Client(this)); //initClient這個方法其實並沒有做什麼,
}
複製程式碼

即構造了一個Client物件,Client實現了ISurfaceComposerClient介面。是一個可以跨程式通訊的aidl物件。即SurfaceComposerClient可以通過它來和SurfaceFlinger通訊。除此之外它還可以建立Surface,並且維護一個應用程式的所有Layer(下文會分析到它是什麼)它是一個十分重要的物件,我們先來看一下它的組成,它所涉及的其他東西在下文分析中都會講到:

Client.h

class Client : public BnSurfaceComposerClient
{
public:
    ...
    void attachLayer(const sp<IBinder>& handle, const sp<Layer>& layer);
    void detachLayer(const Layer* layer);
    ...
private:
    // ISurfaceComposerClient interface。   gbp很重要,它維護這一個應用程式的渲染 Buffer佇列
    virtual status_t createSurface(...sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp);

    virtual status_t destroySurface(const sp<IBinder>& handle); 

    //跨程式通訊方法
    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
    ...

    // constant
    sp<SurfaceFlinger> mFlinger;

    // protected by mLock
    DefaultKeyedVector< wp<IBinder>, wp<Layer> > mLayers; // 一個應用程式的所有Layer
    ...
};
複製程式碼

經過上面這一頓原始碼分析,我們大概知道了ViewRootImpl.setView()所引發的主要操作:

  1. WindowManagerService建立了一個WindowState。用來表示客戶端的一個Window
  2. WindowManagerService建立了一個SurfaceSession,SurfaceSession會與SurfaceFlinger構建連結,建立了一個SurfaceComposerClient物件,一個應用程式只具有一個這個物件。
  3. SurfaceComposerClient建立了一個Client, 這個物件十分重要,它維護這應用程式的渲染核心資料,並負責與SurfaceFlinger通訊。

如下圖:

Android的UI顯示原理之Surface的建立

經過上面的步驟,應用程式的ViewRootImpl已經被WindowManagerService識別,並且應用程式已經與SurfaceFlinger建立連線。即建立了SurfaceComposerClientClient物件

文章開始就已經說了SurfaceWindow(ViewRootImpl)的UI載體,那Surface是在哪裡建立的呢?

Surface的建立

其實一個ViewRootImpl就對應一個Surface。這點可以通過ViewRootImpl的原始碼看出:

ViewRootImpl.java

public final Surface mSurface = new Surface();
複製程式碼

ViewRootImpl在構造的時候就new 了一個 Surface。但其實這個新new的Surface並沒有什麼邏輯,它的建構函式是空的。那麼Surface到底是在哪裡建立的呢?

觸發Surface的建立操作

我們還是回到ViewRootImpl.setView()來看一下:

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    ...
    requestLayout(); //susion 請求layout。先新增到待渲染佇列中  
    ...
    res = mWindowSession.addToDisplay(mWindow, ...); //WindowManagerService會建立mWindow對應的WindowState
    ...
}
複製程式碼

即在向WindowManagerService請求建立WindowState之前,呼叫了requestLayout(),這個方法會引起ViewRootImpl所管理的整個view tree的重新渲染。它最終會呼叫到scheduleTraversals():

void scheduleTraversals() {
    ...
    mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    ...
}
複製程式碼

對於Choreographer本文不做詳細的分析,可以去參考 Android Choreographer 原始碼分析的分析來了解這個類。

scheduleTraversals()會通過Choreographer來post一個mTraversalRunnableChoreographer接收顯示系統的時間脈衝(垂直同步訊號-VSync訊號,16ms發出一次),在下一個frame渲染時控制執行這個mTraversalRunnable

但是mTraversalRunnable的執行至少要在應用程式與SurfaceFlinger建立連線之後。這是因為渲染操作是由SurfaceFlinger負責排程了,如果應用程式還沒有與SurfaceFlinger建立連線,那SurfaceFlinger當然不會渲染這個應用程式。所以在執行完mWindowSession.addToDisplay(mWindow, ...)之後,才會執行mTraversalRunnable:

ViewRootImpl.java

final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}
複製程式碼

doTraversal()會呼叫到ViewRootImpl.performTraversals(),大部分同學可能知道這個方法是一個view treemeasure/layout/draw的控制方法:

private void performTraversals() {
    finalView host = mView; //mView是一個Window的根View,對於Activity來說就是DecorView
    ...
    relayoutWindow(params, viewVisibility, insetsPending);
    ...
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
    ...         
    performLayout(lp, mWidth, mHeight);
    ...
    performDraw();
    ...
}
複製程式碼

Surface的具體建立就由relayoutWindow(params, viewVisibility, insetsPending)這個方法來完成的。這個方法會通過IPC呼叫到WindowManagerService.relayoutWindow():

ViewRootImpl.java

private int relayoutWindow(WindowManager.LayoutParams params, ...) throws RemoteException {
    ...
    int relayoutResult = mWindowSession.relayout(mWindow,..., mSurface);
    ...
}
複製程式碼

上面我省略了mWindowSession.relayout()方法的很多引數,不過有一個十分重要的引數我沒有省略,就是mSurface。前面已經分析了它就是一個空的Surface物件。其實:

真正的Surface建立是由SurfaceControl完成的,應用程式ViewRootImplSurface只是一個指標,指向這個Surface

下面就來看一下SurfaceControl是如何建立Surface的:

mWindowSession.relayout()會呼叫到WindowManagerService.relayoutWindow():

WindowManagerService.java

 //這裡的outSurface其實就是ViewRootImpl中的那個Surface
public int relayoutWindow(Session session, IWindow client....Surface outSurface){ 
    ...
    result = createSurfaceControl(outSurface, result, win, winAnimator);  
    ...
}

private int createSurfaceControl(Surface outSurface, int result, WindowState win,WindowStateAnimator winAnimator) {
    ...
    surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
    ...
    surfaceController.getSurface(outSurface);
}
複製程式碼

winAnimator.createSurfaceLocked實際上是建立了一個SurfaceControl。即上面是先構造SurfaceControl,然後在構造Surface

SurfaceControl的建立

winAnimator.createSurfaceLocked其實是通過SurfaceControl的建構函式建立了一個SurfaceControl物件,這個物件的作用其實就是負責維護Surface,Surface其實也是由這個物件負責建立的,我們看一下這個物件的構造方法:

SurfaceControl.java

long mNativeObject; //成員指標變數,指向native建立的SurfaceControl

private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
            SurfaceControl parent, int windowType, int ownerUid){
    ...
    mNativeObject = nativeCreate(session, name, w, h, format, flags,
        parent != null ? parent.mNativeObject : 0, windowType, ownerUid);
    ...
}
複製程式碼

即呼叫了nativeCreate()並返回一個SurfaceControl指標:

android_view_SurfaceControl.cpp

static jlong nativeCreate(JNIEnv* env, ...) {
    //這個client其實就是前面建立的SurfaceComposerClinent
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj)); 
    sp<SurfaceControl> surface; //建立成功之後,這個指標會指向新建立的SurfaceControl
    status_t err = client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface, flags, parent, windowType, ownerUid);
    ...
    return reinterpret_cast<jlong>(surface.get()); //返回這個SurfaceControl的地址
}
複製程式碼

即呼叫到SurfaceComposerClient.createSurfaceChecked():

SurfaceComposerClient.cpp

//outSurface會指向新建立的SurfaceControl
status_t SurfaceComposerClient::createSurfaceChecked(...sp<SurfaceControl>* outSurface..) 
{
    sp<IGraphicBufferProducer> gbp; //這個物件很重要
    ...
    err = mClient->createSurface(name, w, h, format, flags, parentHandle, windowType, ownerUid, &handle, &gbp);
    if (err == NO_ERROR) {
        //SurfaceControl建立成功, 指標賦值
        *outSurface = new SurfaceControl(this, handle, gbp, true);
    }
    return err;
}
複製程式碼

上面這個方法實際上是呼叫Client.createSurface()來建立一個Surface。在建立時有一個很重要的引數sp<IGraphicBufferProducer> gbp,在下面原始碼分析中我們也要重點注意它。這是因為應用所渲染的每一幀,實際上都會新增到IGraphicBufferProducer中,來等待SurfaceFlinger的渲染。這個過程我們在下一篇文章中會分析,我們先繼續來看一下Surface是如何被Client建立的:

Client.cpp

status_t Client::createSurface(...)
{
    ...
    //gbp 直接透傳到了SurfaceFlinger
    return mFlinger->createLayer(name, this, w, h, format, flags, windowType, ownerUid, handle, gbp, &parent);
}
複製程式碼

??? 不是說好的要建立Surface呢?怎麼變成mFlinger->createLayer()? 額,我也不明白這個突然轉變,不過我們只要知道:

SurfaceSurfaceFlinger中對應的實體其實是Layer

我們繼續看一下mFlinger->createLayer()

SurfaceFlinger.cpp

status_t SurfaceFlinger::createLayer(const String8& name,const sp<Client>& client...)
{
    status_t result = NO_ERROR;
    sp<Layer> layer; //將要建立的layer
    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal:
            result = createBufferLayer(client,
                    uniqueName, w, h, flags, format,
                    handle, gbp, &layer); // 注意gbp,這時候還沒有構造呢!
            break;
            ... //Layer 分為好幾種,這裡不全部列出
    }
    ...
    result = addClientLayer(client, *handle, *gbp, layer, *parent);  //這個layer和client相關聯, 新增到Client的mLayers集合中。
    ...
    return result;
}
複製程式碼

SurfaceFlinger.createLayer()方法可以看出Layer分為好幾種。我們這裡只對普通的BufferLayer的建立做一下分析,看createBufferLayer():

status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client... sp<Layer>* outLayer)
{
    ...
    sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
    status_t err = layer->setBuffers(w, h, format, flags);  //設定layer的寬高
    if (err == NO_ERROR) {
        *handle = layer->getHandle(); //建立handle
        *gbp = layer->getProducer(); //建立 gbp IGraphicBufferProducer
        *outLayer = layer; //把新建的layer的指標拷貝給outLayer,這樣outLayer就指向了新建的BufferLayer
    }
    return err;
}
複製程式碼

前面我說過IGraphicBufferProducer(gbp)是一個很重要的物件,它涉及到SurfaceFlinger的渲染邏輯,下面我們就看一下這個物件的建立邏輯:

IGraphicBufferProducer(gbp)的建立

BufferLayer.cpp

sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
    return mProducer;
}
複製程式碼

mProducer其實是Layer的成員變數,它的建立時機是Layer第一次被使用時:

void BufferLayer::onFirstRef() {
    ...
    BufferQueue::createBufferQueue(&producer, &consumer, true); 
    mProducer = new MonitoredProducer(producer, mFlinger, this);
    ...
}
複製程式碼

所以mProducer的例項是MonitoredProducer,但其實它只是一個裝飾類,它實際功能都委託給構造它的引數producer:

BufferQueue.cpp

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
    ...
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); //注意這個consumer
    ...
    *outProducer = producer;
    *outConsumer = consumer;
}
複製程式碼

所以實際實現mProducer的工作的queueProducerBufferQueueProducer

所以構造一個SurfaceControl所做的工作就是建立了一個SurfaceControl,並讓SurfaceFlinger建立了一個對應的LayerLayer中有一個IGraphicBufferProducer,它的例項是BufferQueueProducer

可以用下面這個圖來描述SurfaceControl的建立過程:

Android的UI顯示原理之Surface的建立

從SurfaceControl中獲取Surface

我們回看WindowManagerService.createSurfaceControl(), 來看一下java層的Surface物件到底是個什麼:

WindowManagerService.java

private int createSurfaceControl(Surface outSurface, int result, WindowState win,WindowStateAnimator winAnimator) {
    ...
    surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
    ...
    surfaceController.getSurface(outSurface);
}
複製程式碼

上面我們已經瞭解了winAnimator.createSurfaceLocked的整個過程,我們看一下surfaceController.getSurface(outSurface), surfaceControllerWindowSurfaceController的例項:

//WindowSurfaceController.java
void getSurface(Surface outSurface) {
    outSurface.copyFrom(mSurfaceControl);
}

//Surface.java
public void copyFrom(SurfaceControl other) {
    ...
    long surfaceControlPtr = other.mNativeObject;
    ...
    long newNativeObject = nativeGetFromSurfaceControl(surfaceControlPtr);
    ...
    mNativeObject = ptr; // mNativeObject指向native建立的Surface
}
複製程式碼

Surface.copyFrom()方法呼叫nativeGetFromSurfaceControl()來獲取一個指標,這個指標是根據前面建立的SurfaceControl的指標來尋找的,即傳入的引數surfaceControlPtr:

android_view_Surface.cpp

static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj)); //把java指標轉化內native指標
    sp<Surface> surface(ctrl->getSurface()); //直接構造一個Surface,指向 ctrl->getSurface()
    if (surface != NULL) {
        surface->incStrong(&sRefBaseOwner); //強引用
    }
    return reinterpret_cast<jlong>(surface.get());
}
複製程式碼

這裡的ctrl指向前面建立的SurfaceControl,繼續追溯ctrl->getSurface():

SurfaceControl.cpp

sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        return generateSurfaceLocked();
    }
    return mSurfaceData;
}

sp<Surface> SurfaceControl::generateSurfaceLocked() const
{
    //這個mGraphicBufferProducer其實就是上面分析的BufferQueueProducer
    mSurfaceData = new Surface(mGraphicBufferProducer, false); 
    return mSurfaceData;
}
複製程式碼

即直接new了一個nativie的Surface返回給java層,java層的Surface指向的就是native層的Surface

所以Surface的實際建立可以用下圖表示:

Android的UI顯示原理之Surface的建立

經過上面這個圖,也可以理解SurfaceControl為什麼叫SurfaceControl了。

本文到這裡已經很長了,對於UI的渲染過程:即ViewRootImpl是如何渲染到Surface到下一篇文章再分析。

歡迎關注我的Android進階計劃看更多幹貨

歡迎關注我的微信公眾號:susion隨心

Android的UI顯示原理之Surface的建立

參考文章:

AndroidUI系列—淺談影象渲染機制

一篇文章看明白 Android 圖形系統 Surface 與 SurfaceFlinger 之間的關係

相關文章