android surfaceflinger研究----Surface機制

轉自:http://blog.csdn.net/windskier/article/details/7041610

前一篇文章介紹了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] view plaincopy
  1. <span style="font-size:13px;">    private final Surface mSurface = new Surface();</span>  
Surface()@Surface.java

[java] view plaincopy
  1. <span style="font-size:13px;">    public Surface() {  
  2.         if (DEBUG_RELEASE) {  
  3.             mCreationStack = new Exception();  
  4.         }  
  5.         mCanvas = new CompatibleCanvas();  
  6.     }</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] view plaincopy
  1. <span style="font-size:13px;">        int relayoutResult = sWindowSession.relayout(  
  2.                 mWindow, params,  
  3.                 (int) (mView.mMeasuredWidth * appScale + 0.5f),  
  4.                 (int) (mView.mMeasuredHeight * appScale + 0.5f),  
  5.                 viewVisibility, insetsPending, mWinFrame,  
  6.                 mPendingContentInsets, mPendingVisibleInsets,  
  7.                 mPendingConfiguration, mSurface);</span>  
relayoutWindow()@WindowManagerService.java
[java] view plaincopy
  1. <span style="font-size:13px;">                    Surface surface = win.createSurfaceLocked();  
  2.                     if (surface != null) {  
  3.                         outSurface.copyFrom(surface);  
  4.                         win.mReportDestroySurface = false;  
  5.                         win.mSurfacePendingDestroy = false;  
  6.                         if (SHOW_TRANSACTIONS) Slog.i(TAG,  
  7.                                 "  OUT SURFACE " + outSurface + ": copied");  
  8.                     } 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

  1. class Client : public BnSurfaceComposerClient  

@SurfaceComposerClient.cpp
  1. void SurfaceComposerClient::onFirstRef()  
  2. {  
  3.     sp<ISurfaceComposer> sm(getComposerService());  
  4.     if (sm != 0) {  
  5.         sp<ISurfaceComposerClient> conn = sm->createConnection();  
  6.         if (conn != 0) {  
  7.             mClient = conn;  
  8.             Composer::addClient(this);  
  9.             mPrebuiltLayerState = new layer_state_t;  
  10.             mStatus = NO_ERROR;  
  11.         }  
  12.     }  
  13. }  

   下圖描述了整個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.1 client端Surface的形態

    首先,我們看一下Surface在WMS中定義的代碼

createSurfaceLocked()@WindowManagerService.java

[java] view plaincopy
  1. mSurface = new Surface(  
  2.         mSession.mSurfaceSession, mSession.mPid,  
  3.         mAttrs.getTitle().toString(),  
  4.         0, w, h, mAttrs.format, flags);  
我們可以看到,它將SurfaceSession對象當作參數傳遞給了Surface的構造函數。往下看Surface的構造函數。

@Surface.java

[java] view plaincopy
  1. public Surface(SurfaceSession s,  
  2.         int pid, int display, int w, int h, int format, int flags)  
  3.     throws OutOfResourcesException {  
  4.     if (DEBUG_RELEASE) {  
  5.         mCreationStack = new Exception();  
  6.     }  
  7.     mCanvas = new CompatibleCanvas();  
  8.     init(s,pid,null,display,w,h,format,flags);  
  9. }  
    這個構造函數,不同於我們在ViewRoot中看到的Surface的構造函數,這個構造函數並不是一個空殼,它做了本地實體的初始化工作,因此這個Surface纔是一個真正的Suface。

Native 函數init回調到SurfaceComposerClient的createSurface()函數,往下的過程在上一節的圖中描述的很清楚,流程就不介紹了,同時我們先不管SurfaceFlinger爲SurfaceComposerClient創建的Surface到底是一個什麼東西,我們先看看SurfaceComposerClient爲WMS創建的是一個什麼東西?


@SurfaceComposerClient.cpp

  1. sp<SurfaceControl> SurfaceComposerClient::createSurface(  
  2.         int pid,  
  3.         const String8& name,  
  4.         DisplayID display,  
  5.         uint32_t w,  
  6.         uint32_t h,  
  7.         PixelFormat format,  
  8.         uint32_t flags)  
  9. {  
  10.     sp<SurfaceControl> result;  
  11.     if (mStatus == NO_ERROR) {  
  12.         ISurfaceComposerClient::surface_data_t data;  
  13.         sp<ISurface> surface = mClient->createSurface(&data, pid, name,  
  14.                 display, w, h, format, flags);  
  15.         if (surface != 0) {  
  16.             result = new SurfaceControl(this, surface, data, w, h, format, flags);  
  17.         }  
  18.     }  
  19.     return result;  
  20. }  

    從上面的代碼我們可以看出,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

  1. sp<Surface> SurfaceControl::getSurface() const  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.     if (mSurfaceData == 0) {  
  5.         mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));  
  6.     }  
  7.     return mSurfaceData;  
  8. }  

1.3.2 SurfaceFlinger端Surface形態

SurfaceFlinger::[email protected]  

  1. sp<Layer> normalLayer;  
  2. switch (flags & eFXSurfaceMask) {  
  3.     case eFXSurfaceNormal:  
  4.         if (UNLIKELY(flags & ePushBuffers)) {  
  5.             layer = createPushBuffersSurface(client, d, w, h, flags);  
  6.         } else {  
  7.             normalLayer = createNormalSurface(client, d, w, h, flags, format);  
  8.             layer = normalLayer;  
  9.         }  
  10.         break;  
  11.     case eFXSurfaceBlur:  
  12.         layer = createBlurSurface(client, d, w, h, flags);  
  13.         break;  
  14.     case eFXSurfaceDim:  
  15.         layer = createDimSurface(client, d, w, h, flags);  
  16.         break;  
  17. }  
  18.   
  19. if (layer != 0) {  
  20.     layer->initStates(w, h, flags);  
  21.     layer->setName(name);  
  22.     ssize_t token = addClientLayer(client, layer);  
  23.   
  24.     surfaceHandle = layer->getSurface();  
  25.     if (surfaceHandle != 0) {   
  26.         params->token = token;  
  27.         params->identity = surfaceHandle->getIdentity();  
  28.         params->width = w;  
  29.         params->height = h;  
  30.         params->format = format;  
  31.         if (normalLayer != 0) {  
  32.             Mutex::Autolock _l(mStateLock);  
  33.             mLayerMap.add(surfaceHandle->asBinder(), normalLayer);  
  34.         }  
  35.     }  

    當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

  1. ssize_t token = addClientLayer(client, layer);  

    第二種方式,將所有的創建的普通的Layer保存起來,以便Client Surface在請求實現Buffer時能夠辨識Client Surface對應的Layer。

SurfaceFlinger::createSurface()@SurfaceFlinger.cpp

  1. 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] view plaincopy
  1. Canvas canvas;  
  2.             try {  
  3.                 int left = dirty.left;  
  4.                 int top = dirty.top;  
  5.                 int right = dirty.right;  
  6.                 int bottom = dirty.bottom;  
  7.                 canvas = surface.lockCanvas(dirty);  
  8.   
  9.                 if (left != dirty.left || top != dirty.top || right != dirty.right ||  
  10.                         bottom != dirty.bottom) {  
  11.                     mAttachInfo.mIgnoreDirtyState = true;  
  12.                 }  
  13.   
  14.                 // TODO: Do this in native  
  15.                 canvas.setDensity(mDensity);  
    上面的代碼顯示,JAVA Surface 會lock canvas。而Client Surface的創建就在這個過程中,即下面代碼中的第一行getSurface().我們先不管Client Surface的創建,先看看Canvas是如何與Client Surface的顯示Buffer關聯的。

  1. static jobject Surface_lockCanvas(JNIEnv* env, jobject clazz, jobject dirtyRect)  
  2. {  
  3.     const sp<Surface>& surface(getSurface(env, clazz));  
  4.     if (!Surface::isValid(surface))  
  5.         return 0;  
  6.   
  7.   
  8.     SkCanvas* nativeCanvas = (SkCanvas*)env->GetIntField(canvas, no.native_canvas);  
  9.     SkBitmap bitmap;  
  10.     ssize_t bpr = info.s * bytesPerPixel(info.format);  
  11.     bitmap.setConfig(convertPixelFormat(info.format), info.w, info.h, bpr);  
  12.     if (info.format == PIXEL_FORMAT_RGBX_8888) {  
  13.         bitmap.setIsOpaque(true);  
  14.     }  
  15.     if (info.w > 0 && info.h > 0) {  
  16.         bitmap.setPixels(info.bits);  
  17.     } else {  
  18.         // be safe with an empty bitmap.  
  19.         bitmap.setPixels(NULL);  
  20.     }  
  21.     nativeCanvas->setBitmapDevice(bitmap);  
  22.       
  23.     SkRegion clipReg;  
  24.     if (dirtyRegion.isRect()) { // very common case  
  25.         const Rect b(dirtyRegion.getBounds());  
  26.         clipReg.setRect(b.left, b.top, b.right, b.bottom);  
  27.     } else {  
  28.         size_t count;  
  29.         Rect const* r = dirtyRegion.getArray(&count);  
  30.         while (count) {  
  31.             clipReg.op(r->left, r->top, r->right, r->bottom, SkRegion::kUnion_Op);  
  32.             r++, count--;  
  33.         }  
  34.     }  
  35.   
  36.     nativeCanvas->clipRegion(clipReg);  
  37.       
  38.     int saveCount = nativeCanvas->save();  
  39.     env->SetIntField(clazz, so.saveCount, saveCount);  
  40.   
  41.     if (dirtyRect) {  
  42.         const Rect& bounds(dirtyRegion.getBounds());  
  43.         env->SetIntField(dirtyRect, ro.l, bounds.left);  
  44.         env->SetIntField(dirtyRect, ro.t, bounds.top);  
  45.         env->SetIntField(dirtyRect, ro.r, bounds.right);  
  46.         env->SetIntField(dirtyRect, ro.b, bounds.bottom);  
  47.     }  
  48.       
  49.     return canvas;  
  50. }  

    上面的代碼,我們可以看出,Canvas的Bitmap設備的設置了Client Surface的顯示Buffer爲其Bitmap pixel存儲空間。

  1. bitmap.setPixels(info.bits);  

    這樣Canvas的繪製空間就有了。下一步就該繪製窗口了。

draw()@ViewRoot.java

  1. try {  
  2.     canvas.translate(0, -yoff);  
  3.     if (mTranslator != null) {  
  4.         mTranslator.translateCanvas(canvas);  
  5.     }  
  6.     canvas.setScreenDensity(scalingRequired  
  7.             ? DisplayMetrics.DENSITY_DEVICE : 0);  
  8.     mView.draw(canvas);  
  9. }  
其中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

  1. UserClient::UserClient(const sp<SurfaceFlinger>& flinger)  
  2.     : ctrlblk(0), mBitmap(0), mFlinger(flinger)  
  3. {  
  4.     const int pgsize = getpagesize();  
  5.     const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));  
  6.   
  7.     mCblkHeap = new MemoryHeapBase(cblksize, 0,  
  8.             "SurfaceFlinger Client control-block");  
  9.   
  10.     ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());  
  11.     if (ctrlblk) { // construct the shared structure in-place.  
  12.         new(ctrlblk) SharedClient;  
  13.     }  
  14. }  

    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 [email protected]

  1. SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];  
    

2.2.2 SharedBufferStack

    SharedBufferStack在這個模塊中所處的地位在上一小節中介紹了,下面主要介紹一下它的作用。
    1. 設置當前窗口要顯示的區域等信息;
class SharedBufferStack@SharedBufferStack.h
  1. status_t setDirtyRegion(int buffer, const Region& reg);  
  2. status_t setCrop(int buffer, const Rect& reg);  
  3. 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
  1. volatile int32_t head;      // server's current front buffer  
  2. 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被創建的時候創建的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章