android surfaceflinger研究----Surface机制

来源:互联网 发布:erp软件界面 编辑:程序博客网 时间:2024/04/28 06:28
前一篇文章介绍了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

[cpp] view plaincopy
  1. class Client : public BnSurfaceComposerClient  

@SurfaceComposerClient.cpp
[cpp] view plaincopy
  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

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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::createSurface@SurfaceFlinger.cpp  

[cpp] view plaincopy
  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

[cpp] view plaincopy
  1. ssize_t token = addClientLayer(client, layer);  

    第二种方式,将所有的创建的普通的Layer保存起来,以便Client Surface在请求实现Buffer时能够辨识Client Surface对应的Layer。

SurfaceFlinger::createSurface()@SurfaceFlinger.cpp

[cpp] view plaincopy
  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关联的。

[cpp] view plaincopy
  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存储空间。

[cpp] view plaincopy
  1. bitmap.setPixels(info.bits);  

    这样Canvas的绘制空间就有了。下一步就该绘制窗口了。

draw()@ViewRoot.java

[cpp] view plaincopy
  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

[cpp] view plaincopy
  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 SharedClient@SharedBufferStack.h

[cpp] view plaincopy
  1. SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];  
    

2.2.2 SharedBufferStack

    SharedBufferStack在这个模块中所处的地位在上一小节中介绍了,下面主要介绍一下它的作用。
    1. 设置当前窗口要显示的区域等信息;
class SharedBufferStack@SharedBufferStack.h
[cpp] view plaincopy
  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
[cpp] view plaincopy
  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被创建的时候创建的。


原创粉丝点击