android surfaceflinger研究—-Surface機制

  前一篇文章介紹瞭android的顯示系統,這篇文章中,我們把視角往上層移動一下,研究一下framework是如何與surfaceflinger進行業務交互的。如何創建surface,如何顯示窗口等等,所有的這一切都是通過系統服務WindowManagerService與surfaceflinger來進行的。
 
    android中的Surface機制這一塊代碼寫的比較難理解,光叫Surface的類就有3個,因此本篇文章從兩部分來分析,首先,想要理解Surface機制,還是需要首先理清各個類之間的關系。其次,在理解瞭整個Surface機制的類關系之後,到時我們再結合前一篇文章中對顯示系統的介紹,研究一下一個Surface是如何和顯示系統建立起聯系來的,這個聯系主要是指Surface的顯示buffer的存儲管理。在下篇文章中,再分析SurfaceFlinger是如何將已經存儲瞭窗口圖形數據的Surface Buffer顯示到顯示系統中。。
 
1. Surface機制的靜態關系
    將這一部分叫做Surface機制,是有別於SurfaceFlinger而言的,android的圖形系統中,作為C/S模型兩端的WMS和SurfaceFlinger是圖形系統業務的核心,但是不把WMS和SurfaceFlinger中間的這層聯系搞清楚的話,是很難理解整個圖形系統的,在本文中我將兩者之間的這個聯系關系稱之為Surface機制,它的主要任務就是創建一個Surface,ViewRoot在這個Surface上描繪當前的窗口,SurfaceFlinger將這個Surface flinger(扔)給顯示系統將其呈現在硬件設備上。其實這裡這個Surface在不同的模塊中是以不同的形態存在的,唯一不變的就是其對應的顯示Buffer。
 
 
   
 
 
 
1.1 ViewRoot和WMS共享Surface
    我們知道每個Activity都會有一個ViewRoot作為Activity Window與WMS交互的接口,ViewRoot會繪制整個Activity的窗口View到Surface上,因此我們在ViewRoot中就有瞭創建Surface的需求。看一下代碼中的Surface的定義:
relayoutWindow()@ViewRoot.java
 
[java]
<span style="font-size:13px;">    private final Surface mSurface = new Surface();</span> 
Surface()@Surface.java
[java]
<span style="font-size:13px;">    public Surface() { 
        if (DEBUG_RELEASE) { 
            mCreationStack = new Exception(); 
        } 
        mCanvas = new CompatibleCanvas(); 
    }</span> 
    由上面可以看出在ViewRoot中定義的Surface隻是一個空殼,那麼真正的Surface是在哪裡被初始化的呢?大管傢WMS中!當ViewRoot請求WMS relayout時,會將ViewSurface中的Surface交給WMS初始化。在WMS中,對應每個WindowState對象,在relayout窗口時,同樣會創建一個Surface,wms中的這個Surface會真正的初始化,然後再將這個WMS Surface復制給ViewRoot中的Surface。這麼實現的目的就是保證ViewRoot和WMS共享同一個Surface。ViewRoot對Surface進行繪制,WMS對這個Surface進行初始化及管理。很和諧!
relayoutWindow()@ViewRoot.java
 
[java]
<span style="font-size:13px;">        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);</span> 
relayoutWindow()@WindowManagerService.java
[java]
<span style="font-size:13px;">                    Surface surface = win.createSurfaceLocked(); 
                    if (surface != null) { 
                        outSurface.copyFrom(surface); 
                        win.mReportDestroySurface = false; 
                        win.mSurfacePendingDestroy = false; 
                        if (SHOW_TRANSACTIONS) Slog.i(TAG, 
                                "  OUT SURFACE " + outSurface + ": copied"); 
                    } else {</span> 
1.2 SurfaceSession
    SurfaceSession可以認為是創建Surface過程中,WMS和SurfaceFlinger之間的會話層,通過這個SurfaceSession實現瞭Surface的創建。
 
   
 
    SurfaceSession是JAVA層的概念,@SurfaceSession.java。它對應的native實體是一個SurfaceComposerClient對象。
 
    SurfaceComposerClient通過ComposerService類來獲得SurfaceFlinger的IBinder接口,但是光獲得SurfaceFlinger的IBinder接口是不夠的,要想請求SurfaceFlinger創建一個Surface,還需要向SurfaceFlinger獲得一個IBinder接口ISurfaceComposerClient,通過這個ISurfaceComposerClient來請求SurfaceFlinger創建一個Surface,為什麼這麼繞呢,為什麼不直接讓SurfaceFlinger創建Surface呢?
 
    站在SurfaceFlinger的角度來考慮,對於SurfaceFlinger來說,可能有多個Client來請求SurfaceFlinger的業務,每個Client可能會請求SurfaceFlinger創建多個Surface,那麼SurfaceFlinger本地需要提供一套機制來保存每個client請求創建的Surface,SurfaceFlinger通過為每個client創建一個Client對象實現這個機制,並將這個Client的IBinder接口ISurfaceComposerClient返給SurfaceComposerClient對象。SurfaceComposerClient對象在通過ISurfaceComposerClient去請求創建Surface。
 
@SurfaceFlinger.h
 
[cpp]
class Client : public BnSurfaceComposerClient 
 
@SurfaceComposerClient.cpp
[cpp]
void SurfaceComposerClient::onFirstRef() 

    sp<ISurfaceComposer> sm(getComposerService()); 
    if (sm != 0) { 
        sp<ISurfaceComposerClient> conn = sm->createConnection(); 
        if (conn != 0) { 
            mClient = conn; 
            Composer::addClient(this); 
            mPrebuiltLayerState = new layer_state_t; 
            mStatus = NO_ERROR; 
        } 
    } 

   下圖描述瞭整個SurfaceSession的內部結構與工作流程。
 
其中藍色箭頭是SurfaceComposerClient通過ComposerService獲得SurfaceFlinger的IBinder接口ISurfaceComposer過程;
 
紅色箭頭表示SurfaceComposerClient通過IPC請求SurfaceFlinger創建Client的過程,並獲得Client的IBinder接口ISurfaceComposerClient;
 
綠色箭頭表示SurfaceComposerClient通過IPC請求Client創建Surface。
 
 
 
1.3 Surface的形態
    上一節我們分析瞭SurfaceSession的靜態結構,得知Surface的創建過程是通過SurfaceSession這個中間會話層去請求SurfaceFlinger去創建的,並且這篇文章中,我們說瞭半天Surface瞭,那麼究竟我們要創建的Surface究竟是什麼樣的一個東西呢,它的具體形態是什麼呢?這一小節我們就來分析以下Surface的形態。
 
1.3.1client端Surface的形態
    首先,我們看一下Surface在WMS中定義的代碼
 
createSurfaceLocked()@WindowManagerService.java
 
 
[java]
mSurface = new Surface( 
        mSession.mSurfaceSession, mSession.mPid, 
        mAttrs.getTitle().toString(), 
        0, w, h, mAttrs.format, flags); 
我們可以看到,它將SurfaceSession對象當作參數傳遞給瞭Surface的構造函數。往下看Surface的構造函數。
@Surface.java
 
 
[java]
public Surface(SurfaceSession s, 
        int pid, int display, int w, int h, int format, int flags) 
    throws OutOfResourcesException { 
    if (DEBUG_RELEASE) { 
        mCreationStack = new Exception(); 
    } 
    mCanvas = new CompatibleCanvas(); 
    init(s,pid,null,display,w,h,format,flags); 

    這個構造函數,不同於我們在ViewRoot中看到的Surface的構造函數,這個構造函數並不是一個空殼,它做瞭本地實體的初始化工作,因此這個Surface才是一個真正的Suface。
Native 函數init回調到SurfaceComposerClient的createSurface()函數,往下的過程在上一節的圖中描述的很清楚,流程就不介紹瞭,同時我們先不管SurfaceFlinger為SurfaceComposerClient創建的Surface到底是一個什麼東西,我們先看看SurfaceComposerClient為WMS創建的是一個什麼東西?
 
 
 
@SurfaceComposerClient.cpp
 
 
[cpp]
sp<SurfaceControl> SurfaceComposerClient::createSurface( 
        int pid, 
        const String8& name, 
        DisplayID display, 
        uint32_t w, 
        uint32_t h, 
        PixelFormat format, 
        uint32_t flags) 

    sp<SurfaceControl> result; 
    if (mStatus == NO_ERROR) { 
        ISurfaceComposerClient::surface_data_t data; 
        sp<ISurface> surface = mClient->createSurface(&data, pid, name, 
                display, w, h, format, flags); 
        if (surface != 0) { 
            result = new SurfaceControl(this, surface, data, w, h, format, flags); 
        } 
    } 
    return result; 

    從上面的代碼我們可以看出,SurfaceComposerClient為WMS返回的是一個SurfaceControl對象,這個SurfaceControl對象包含瞭surfaceFlinger為SurfaceComposerClient創建的surface,這個surfaceFlinge創建的Surface在Client端的形態為ISurface。這個過程下面分析SurfaceFlinger端的Surface形態時會看到。
 
    SurfaceControl類中還有一個非常重要的成員,它的類型也叫做Surface,定義在frameworks/base/libs/surfaceflinger/Surface.h。這個Surface提供瞭顯示Buffer的管理。在文章的後面再介紹。
 
@frameworks/base/libs/surfaceflinger_client/Surface.cpp
 
 
[cpp]
sp<Surface> SurfaceControl::getSurface() const 

    Mutex::Autolock _l(mLock); 
    if (mSurfaceData == 0) { 
        mSurfaceData = new Surface(const_cast<SurfaceControl*>(this)); 
    } 
    return mSurfaceData; 

1.3.2 SurfaceFlinger端Surface形態
SurfaceFlinger::createSurface@SurfaceFlinger.cpp 
 
[cpp]
sp<Layer> normalLayer; 
switch (flags & eFXSurfaceMask) { 
    case eFXSurfaceNormal: 
        if (UNLIKELY(flags & ePushBuffers)) { 
            layer = createPushBuffersSurface(client, d, w, h, flags); 
        } else { 
            normalLayer = createNormalSurface(client, d, w, h, flags, format); 
            layer = normalLayer; 
        } 
        break; 
    case eFXSurfaceBlur: 
        layer = createBlurSurface(client, d, w, h, flags); 
        break; 
    case eFXSurfaceDim: 
        layer = createDimSurface(client, d, w, h, flags); 
        break; 

 
if (layer != 0) { 
    layer->initStates(w, h, flags); 
    layer->setName(name); 
    ssize_t token = addClientLayer(client, layer); 
 
    surfaceHandle = layer->getSurface(); 
    if (surfaceHandle != 0) {  
        params->token = token; 
        params->identity = surfaceHandle->getIdentity(); 
        params->width = w; 
        params->height = h; 
        params->format = format; 
        if (normalLayer != 0) { 
            Mutex::Autolock _l(mStateLock); 
            mLayerMap.add(surfaceHandle->asBinder(), normalLayer); 
        } 
    } 
    當client請求SurfaceFlinger創建Surface時,SurfaceFlinger首先根據WMS提供的窗口的屬性來一個命名為Layer概念的對象,然後再根據Layer創建它的子類對象LayerBaseClient::Surface。此時第三個名為Surface類出現瞭,下一節我們來介紹一下這個Layer的概念。
 
   
 
1.4 Layer      
   
 
1.4.1 Layer的分類
    目前,android中有4中Layer類型,如上圖所示。 
 
    1. Layer, 普通的Layer,它為每個Client端請求的Surface創建顯示Buffer。
 
    2. LayerBuffer,這種Layer它並不會創建顯示Buffer,它隻是使用已有的Buffer作為顯示Buffer,如Camera的preview;
 
    3. LayerBlur,這種Layer也不會創建顯示Buffer,它隻是將通過這個Layer將原來FrameBuffer上的數據進行模糊處理;
 
    4. LayerDim,這種Layer也不會創建顯示Buffer,它隻是將通過這個Layer將原來FrameBuffer上的數據進行暗淡處理;
 
 
 
     從這中Layer看出,我們分析的重點就是第一種Layer,下面我們著重分析一下普通的Layer。Layer的具體業務我們在下一篇文章中分析
 
1.4.2 Layer的管理
    上文我們在分析SurfaceSession的時候,也分析過,一個Client可能會創建多個Surface,也就是要創建多個Layer,那麼SurfaceFlinger端如何管理這個寫個Layer呢?SurfaceFlinger維護瞭2個Vector來管理Layer。
 
    第一種方式,我們知道SurfaceFlinger會為每個SurfaceSession創建一個Client對象,這第一種方式就是將所有為某一個SurfacSession創建的Layer保存在它對應的Client對象中。
 
SurfaceFlinger::createSurface()@SurfaceFlinger.cpp
 
 
[cpp]
ssize_t token = addClientLayer(client, layer); 
 
    第二種方式,將所有的創建的普通的Layer保存起來,以便Client Surface在請求實現Buffer時能夠辨識Client Surface對應的Layer。
SurfaceFlinger::createSurface()@SurfaceFlinger.cpp
 
 
[cpp]
mLayerMap.add(surfaceHandle->asBinder(), normalLayer); 
 
2. Surface 顯示Buffer的存儲管理
    在前文介紹Client端的Surface形態的內容時,我們提到SurfaceControl中還會維護一個名為Surface對象,它定義在frameworks/base/libs/surfaceflinger/Surface.h中,它負責向LayerBaseClient::Surface請求顯示Buffer,同時將顯示Buffer交給JAVA Surface的Canvas去繪制窗口,我們稱這個Surface為Client Surface。
 
2.1 窗口繪制
    我們先從ViewRoot中分析一下,它是如何顯示窗口View的,如何用到Client Surface請求的顯示Buffer的。
draw()@ViewRoot.java
 
 
[java]
Canvas canvas; 
            try { 
                int left = dirty.left; 
                int top = dirty.top; 
                int right = dirty.right; 
                int bottom = dirty.bottom; 
                canvas = surface.lockCanvas(dirty); 
 
                if (left != dirty.left || top != dirty.top || right != dirty.right || 
                        bottom != dirty.bottom) { 
                    mAttachInfo.mIgnoreDirtyState = true; 
                } 
 
                // TODO: Do this in native 
                canvas.setDensity(mDensity); 
    上面的代碼顯示,JAVA Surface 會lock canvas。而Client Surface的創建就在這個過程中,即下面代碼中的第一行getSurface().我們先不管Client Surface的創建,先看看Canvas是如何與Client Surface的顯示Buffer關聯的。
 
[cpp]
static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect) 

    const sp<Surface>& surface(getSurface(env, clazz)); 
    if (!Surface::isValid(surface)) 
        return 0; 
 
 
    SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas); 
    SkBitmap bitmap; 
    ssize_t bpr = info.s * bytesPerPixel(info.format); 
    bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr); 
    if (info.format == PIXEL_FORMAT_RGBX_8888) { 
        bitmap.setIsOpaque(true); 
    } 
    if (info.w > 0 && info.h > 0) { 
        bitmap.setPixels(info.bits); 
    } else { 
        // be safe with an empty bitmap. 
        bitmap.setPixels(NULL); 
    } 
    nativeCanvas->setBitmapDevice(bitmap); 
     
    SkRegion clipReg; 
    if (dirtyRegion.isRect()) { // very common case 
        const Rect b(dirtyRegion.getBounds()); 
        clipReg.setRect(b.left, b.top, b.right, b.bottom); 
    } else { 
        size_t count; 
        Rect const* r = dirtyRegion.getArray(&count); 
        while (count) { 
            clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op); 
            r++, count–; 
        } 
    } 
 
    nativeCanvas->clipRegion(clipReg); 
     
    int saveCount = nativeCanvas->save(); 
    env->SetIntField(clazz, so.saveCount, saveCount); 
 
    if (dirtyRect) { 
        const Rect& bounds(dirtyRegion.getBounds()); 
        env->SetIntField(dirtyRect, ro.l, bounds.left); 
        env->SetIntField(dirtyRect, ro.t, bounds.top); 
        env->SetIntField(dirtyRect, ro.r, bounds.right); 
        env->SetIntField(dirtyRect, ro.b, bounds.bottom); 
    } 
     
    return canvas; 

 
    上面的代碼,我們可以看出,Canvas的Bitmap設備的設置瞭Client Surface的顯示Buffer為其Bitmap pixel存儲空間。
 
[cpp]
bitmap.setPixels(info.bits); 
    這樣Canvas的繪制空間就有瞭。下一步就該繪制窗口瞭。
 
draw()@ViewRoot.java
 
[cpp]
try { 
    canvas.translate(0, -yoff); 
    if (mTranslator != null) { 
        mTranslator.translateCanvas(canvas); 
    } 
    canvas.setScreenDensity(scalingRequired 
            ? DisplayMetrics.DENSITY_DEVICE : 0); 
    mView.draw(canvas); 

其中ViewRoot中的mView為整個窗口的DecorView。
 
 
2.2 Client Surface的初始化
    Client Surface的創建是從ViewRoot首次Lock canvas時進行的,這麼做的目的可能也是為瞭節約空間,減少不必要的開支。
 
    Client Surface的初始化和顯示Buffer的管理過程比較復雜,下圖給出瞭這一部分的一個靜態結構圖,有些東西從圖上表現不出來,下面我簡單的介紹一下。
 
 
 
 
2.2.1 SharedClient
    SharedClient是這一部分實現的關鍵所在,它並不是一個每個Client Surface創建時都會被創建的,整個系統中隻有一個SharedClient對象,並且它是在共享內存上創建的,下面代碼中可以看出,UserClient在初始化時,提供瞭一個MemoryHeapBase來供SharedClient創建,MemoryHeapBase是創建的共享內存。
@SurfaceFlinger.cpp
 
 
[cpp]
UserClient::UserClient(const sp<SurfaceFlinger>& flinger) 
    : ctrlblk(0), mBitmap(0), mFlinger(flinger) 

    const int pgsize = getpagesize(); 
    const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1)); 
 
    mCblkHeap = new MemoryHeapBase(cblksize, 0, 
            "SurfaceFlinger Client control-block"); 
 
    ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase()); 
    if (ctrlblk) { // construct the shared structure in-place. 
        new(ctrlblk) SharedClient; 
    } 

 
    SharedClient對象的主要目的其實很簡單,就是為系統提供瞭SharedBufferStack::NUM_LAYERS_MAX(GB上為31)個SharedBufferStack。也就是目前系統同時支持31個Client Surface的創建。關於SharedBufferStack下面再做介紹。
   為什麼需要將SharedClient設計為共享內存呢?每個Client Surface需要的SharedBufferStack寄存在SharedClient中,而對於每個SharedBufferStack,一方面,Client Surface需要對它進行一些區域尺寸等的設置;另一方面,在render時,Layer需要獲得當前Client Surfce對應的SharedBufferStack中獲得區域尺寸等設置信息。
 
class SharedClient@SharedBufferStack.h
 
[cpp]
SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ]; 
   
2.2.2 SharedBufferStack
    SharedBufferStack在這個模塊中所處的地位在上一小節中介紹瞭,下面主要介紹一下它的作用。
    1. 設置當前窗口要顯示的區域等信息;
class SharedBufferStack@SharedBufferStack.h
[cpp]
status_t setDirtyRegion(int buffer, const Region& reg); 
status_t setCrop(int buffer, const Rect& reg); 
status_t setTransform(int buffer, uint8_t transform); 
    2. android的圖形系統中提供瞭兩個顯示Buffer,從上圖中我們可以看出Client Surface有2個GraphicBuffer,2個Buffer其中一個顯示,稱之為Front Buffer,另外一個交給ViewRoot去繪制窗口,稱之為Back Buffer。等BackBuffer繪制完成,SurfaceFlinger在將兩者調換,這樣就大大提高瞭顯示的效率,具體過程下篇文章介紹。
    而SharedBufferStack第二個很重要的作用就是提供瞭一套機制來實現這個調換的過程,以保證提供給ViewRoot的Buffer符合當前Buffer輪轉的要求。通過SharedBufferClient::tail和
class SharedBufferStack@SharedBufferStack.h
[cpp]
volatile int32_t head;      // server's current front buffer 
volatile int32_t available; // number of dequeue-able buffers 
這幾個變量的值來確定Client Surface中GraphicBuffer的索引,其中SharedBufferClient::tail記錄的是BackBuffer的索引;SharedBufferStack::head記錄的是FrontBuffer的索引。
 
 
2.2.3 Client Surace GraphicBuffer的請求
    這裡將Client Surface的GraphicBuffer的創建過程以時序圖的形式展現出來。
 

 

 
 
    這裡需要註意的是,Client Surface的2個GraphicBuffer隻有在lock()時才會去創建,而不是在Client Surface被創建的時候創建的

作者 杜文濤

發佈留言