SurfaceFlinger源码分析

针对Jelly Bean版本的代码。
SurfaceFlinger是什么,这些介绍大家可以在网络上找找看,这里就直接上代码。

首先我们得了解一种常用的编程做法,生产者/消费者模型,也许都会觉得很简单,但是这里就用到了很多这些基本概念。
BufferQueue 数据都queue到这里面,前提是它是先从BufferQueue取出一个空的数据单元,称为一个buffer,实际为GraphicBuffer类型。

ConsumerBase 它是消费者端使用的接口,它实现了BufferQueue::ConsumerListener接口,也就是BufferQueue当中有buffer被queue的时候,它能被通知到(onFrameAvailable)。同理当生产者disconnect与BufferQueue的连接或者setBufferCount被调用(该方法释放掉所有buffer,让buffer都归BufferQueue所有,如果有buffer处于DEQUEUED状态,此方法返回错误),它也会被通知到(onBuffersReleased)。

BufferItemConsumer和CpuConsumer 它们都是ConsumerBase的子类,BufferItemConsumer一次可以acquire多个buffer,ConsumerBase一次只能一个,BufferItemConsumer是修改了BufferQueue的mMaxAcquiredBufferCount参数,ConsumerBase使用的默认值1。CpuBuffer可以把buffer锁起来供CPU使用,它也是调用GRALLOC的方法来完成这个功能的。
FramebufferSurface ConsumerBase的子类,会把收到的数据通过HWComposer往荧幕上贴。
SurfaceTexture ConsumerBase的子类,它可以把GraphicBuffer转换成texture image,然后交给OpenGL。

SurfaceTextureLayer是一个定制化的BufferQueue,NATIVE_WINDOW_API_MEDIA/NATIVE_WINDOW_API_CAMERA过来的请求会把BufferQueue设置为异步模式。

BufferQueue当中buffer的状态,这个很简单,但是也很重要。

// BufferState represents the different states in which a buffer slot
// can be.
enum BufferState {
    // FREE indicates that the buffer is not currently being used and
    // will not be used in the future until it gets dequeued and
    // subsequently queued by the client.
    // aka "owned by BufferQueue, ready to be dequeued"
    FREE = 0,

    // DEQUEUED indicates that the buffer has been dequeued by the
    // client, but has not yet been queued or canceled. The buffer is
    // considered 'owned' by the client, and the server should not use
    // it for anything.
    //
    // Note that when in synchronous-mode (mSynchronousMode == true),
    // the buffer that's currently attached to the texture may be
    // dequeued by the client.  That means that the current buffer can
    // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
    // however, the current buffer is always in the QUEUED state.
    // aka "owned by producer, ready to be queued"
    DEQUEUED = 1,

    // QUEUED indicates that the buffer has been queued by the client,
    // and has not since been made available for the client to dequeue.
    // Attaching the buffer to the texture does NOT transition the
    // buffer away from the QUEUED state. However, in Synchronous mode
    // the current buffer may be dequeued by the client under some
    // circumstances. See the note about the current buffer in the
    // documentation for DEQUEUED.
    // aka "owned by BufferQueue, ready to be acquired"
    QUEUED = 2,

    // aka "owned by consumer, ready to be released"
    ACQUIRED = 3
};

BufferQueue主要方法
dequeueBuffer取一个buffer(返回slot,这个bufer是从State为FREE的当中取的)给client使用,必要时候(null/height/width/format/usage任何一点不满足都会触发)它会使用GraphicBufferAlloc::createGraphicBuffer()去分配buffer

requestBuffer根据一个指定的slot获取它的buffer的地址,这个主要用在刚刚分配buffer之后(或者是意外的发现指定slot的buffer地址为空),目前在SurfaceTextureClient(Surface)当中被使用到

queueBuffer通知BufferQueue压入了一个装满数据的buffer,QueueBufferInput是该buffer的描述数据,QueueBufferOutput是BufferQueue当前的状态(默认height/width/transformHint/slot的数量,这个slot只是当前被还回给BufferQueue)

acquireBuffer获取一个pending buffer的拥有权,这个buffer是mQueue当中,也就是状态为QUEUED的(有没有数据?)。

releaseBuffer放弃持有的指定slot的buffer

freeBuffer或者cancelBuffer都会导致这个buffer处于FREE状态

ConsumerBase的主要方法
acquireBufferLocked/releaseBufferLocked/freeBufferLocked/abandonLocked

另外这个protected的数组也很重要,子类可以直接从它里面获取buffer的信息,它实际就相当于缓存了BufferQueue的一些必要信息。

// mSlots stores the buffers that have been allocated by the BufferQueue
// for each buffer slot.  It is initialized to null pointers, and gets
// filled in with the result of BufferQueue::acquire when the
// client dequeues a buffer from a
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
Slot mSlots[BufferQueue::NUM_BUFFER_SLOTS];

SurfaceTextureClient是一个ANativeWindow,为native_window_api_*和native_window_*方法(这些都在system/core/include/system/window.h当中)做具体实现,另外它还持有SurfaceTexture。

// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval  = hook_setSwapInterval;
ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
ANativeWindow::cancelBuffer     = hook_cancelBuffer;
ANativeWindow::queueBuffer      = hook_queueBuffer;
ANativeWindow::query            = hook_query;
ANativeWindow::perform          = hook_perform;

ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;

const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;

一些重要的命名改动

早期的Jelly Bean当中,比如(4.1/4.2)                  4.3
================================================================================
SurfaceTextureClient和Surface(继承                 被简化成了Surface(ANativeWindow)
自SurfaceTextureClient)实际就是一个
ANativeWindow

================================================================================
ISurfaceTexture                                   IGraphicBufferProducer,
                                                  Binder IPC接口,用来在不同组件之间
                                                  传输数据使用(跨进程的),BufferQueue
                                                  实现了BnGraphicBufferProducer

================================================================================
SurfaceTexture(ConsumerBase)                      GLConsumer(ConsumerBase)它取
                                                  BufferQueue里面的数据,然后作为一个
                                                  texture提供给OpenGL使用
                                                  

上面是会用到的基本知识,下面基本才直接和SurfaceFlinger相关。
箭头的方向为继承的方向

                             BpSurface       ---->>>>      ISurface
                                                           sp<ISurfaceTexture> ISurface::getSurfaceTexture()

BSurface       ---->>>>      BnSurface       ---->>>>      ISurface
sp<ISurfaceTexture> BSurface::getSurfaceTexture()
        SurfaceTexture::getBufferQueue()
Layer       ---->>>>      LayerBaseClient       ---->>>>       LayerBase
sp<ISurface> Layer::createSurface()
        new BSurface

                          sp<ISurface> LayerBaseClient::getSurface()
                                  sp<ISurface> LayerBaseClient::createSurface() 
                           BpSurfaceComposerClient       ---->>>>      ISurfaceComposerClient
                                                                       sp<ISurface> ISurfaceComposerClient::createSurface()

Client       ---->>>>      BnSurfaceComposerClient       ---->>>>      ISurfaceComposerClient
Client::createSurface()
        SurfaceFlinger::createLayer()
                createXXXLayer()
                        new LayerXXX
                Layer::getSurface()
                	Layer::createSurface()
sp<SurfaceControl> SurfaceComposerClient::createSurface()
              ISurfaceComposerClient::createSurface()
              new SurfaceControl(ISurface)
// SurfaceComposerClient只是个普通的工具类,它的createSurface会去调用ISurfaceComposerClient和createSurface

现在来看一种情况,假设客户端要创建一个SurfaceView,这中间会发生什么样的事情。
当然你先得了解在Java层当中SurfaceView/SurfaceHolder/Surface这三者是什么关系。

=================================Java=====================================================
new SurfaceView
	surface = new Surface // 这个是SurfaceView当中的Surface(这都是空的,不会在服务端真正的去创建一个Surface)
	newSurface = new Surface // 这个是新的Surface,当Surface改变/被创建/被销毁/需要重绘,
							 // 都会是现在系统层准备好,然后再复制来替代我们SurfaceView当
							 // 中的原来的Surface(通过transferFrom完成)

真正创建Surface的方法是系统去调用的,app不会直接去调用,但是一旦被调用之后就会进入到JNI层相应方法之中,
会用到一个SurfaceSession,书面解释是表示到Surface Flinger的一次会话,因为客户端要同服务端沟通,就存在这样一个会话的概念,这个实际就是Native层SurfaceComposerClient的一个实例。

=================================JNI&Native========================================
android_view_Surface.cpp nativeCreate()
	android_view_SurfaceSession_getClient
	SurfaceComposerClient->createSurface
		ISurfaceComposerClient->createSurface // IPC
			Client->createSurface
				SurfaceFlinger->createLayer
					createXXXLayer()
						new LayerXXX
					Layer->getSurface()
		new SurfaceControl // SurfaceControl包含创建出来的ISurface
	setSurfaceControl // 保存到JNI Context当中

这样Isurface就创建好了

再来看另外一路发生了什么事情,Window/View System需要初始化整个Window,这样在SurfaceView当中一些callback(比如resize/new-surface/onWindowVisibilityChanged/setVisibility/onDetachedFromWindow)就会被调用到,这个时候最终会去调用updateWindow,然后IWindowSession.relayout之后就会有新的Surface被产生出来,然后通过Surface.transferFrom复制到SurfaceView的Surface当中。

还有一点注意的地方Java层的Surface(Surface.java)是如何转化为Native层的Surface(Surface.h|cpp,也就是SurfaceTextureClient)的,注意Surface.java持有一个名为mNativeSurface的Surface.h|cpp的指针,然后每次新创建Native层的Surface之后,就会把它保存到JNI Context当中,然后Java/Native就是通过这么来转换的。

接着我们就只看Native层Surface的管理,android_view_Surface.h|cpp当中有这么个方法android_view_Surface_getNativeWindow
而它又去调用一个内部方法getSurface,如下:

static sp<Surface> getSurface(JNIEnv* env, jobject surfaceObj) {
    sp<Surface> result(android_view_Surface_getSurface(env, surfaceObj)); // 如果取出来为空
    if (result == NULL) {
        /*
         * if this method is called from the WindowManager's process, it means
         * the client is is not remote, and therefore is allowed to have
         * a Surface (data), so we create it here.
         * If we don't have a SurfaceControl, it means we're in a different
         * process.
         */

        SurfaceControl* const control = reinterpret_cast<SurfaceControl*>(
                env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurfaceControl));
        if (control) {
            result = control->getSurface(); // 创建Surface(SurfaceTextureClient)
            if (result != NULL) {
                result->incStrong(surfaceObj);
                env->SetIntField(surfaceObj, gSurfaceClassInfo.mNativeSurface, // Native关联变量,gui/Surface.h
                        reinterpret_cast<jint>(result.get()));
            }
        }
    }
    return result;
}

sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) { // 这是供Native Activity使用的
    return getSurface(env, surfaceObj);
}

看似这就是创建Surface的地方,实则不然,这是供Native Activity使用。我们普通的Java Activity是createFromParcel。
创建的过程当中会初始化ISurface变量,这个是从SurfaceFlinger的Layer的创建的,另外也会通过ISurface->getSurfaceTexture()取得BufferQueue,这样(Surface)SurfaceTextureClient和BufferQueue也就建立起了联系,也就能通过native_window_*或者ANativeWindow往BufferQueue里压入数据。

举个Camera的例子,我们知道在HAL当中每个Stream创建的时候都会有一个camera2_stream_ops参数传进去,并且在Stream的callback当中都会调用camera2_stream_ops->enqueue_buffer,然后调用到ANativeWindow->queueBuffer,最终会调用到BufferQueue的方法,所以你看如果我们喂给Camera HAL的ANativeWindow是SurfaceFlinger当中创建的话,那么Stream的数据就会回到SurfaceFlinger当中,SurfaceFlinger对需要的Layer的数据进行merge之后就可以给FB显示出来了,这就是Camera preview的原理。

SurfaceFlinger内部比较重要的一些功能或者类分析:
我们知道在Jelly Bean当中有黄油计划,主要就是引入VSYNC, Triple Buffer这些东西,Triple Buffer在Layer.h|cpp当中有提到。
那VSYNC是什么东西,简单来说就是一个固定频率的时钟,通常由显示器硬件来提供,如果硬件没有提供,那Android这里自己会模拟一个,参见HWComposer.h|cpp当中的VSyncThread这个类,实现也是非常简洁明了,自己看看代码就能明白。其实VSYNC/Triple Buffer这些东西在PC领域已经是应用多年的老技术了,感兴趣的可以自己搜索看看。

那简单的理解来看,硬件实现就是我们有注册一个callback给硬件,当有VSYNC过来的话就会被调用,当然最终会被调用到onVSyncReceived这个方法,那软件方式就是利用时钟了,每间隔固定的时间就调用onVSyncReceived。
另外还有个和VSYNC没有关系,但是却在这里出现的一个就是onHotplugReceived,就是你的外接或者虚拟显示器被拔掉或者接上会发生的事件,这里的话拔掉会导致从硬件VSYNC切换回软件方式,接上的话又会从软件切换回硬件的方式,总之这里优先使用硬件方式。

IDisplayEventConnection是客户端用来和SurfaceFlinger做VSYNC沟通的通道,利用Binder实现,比如setVsyncRate/requestNextVsync/getDataChannel这些方法,从字面意思就比较容易理解出这几个方法的含义,set就设置VSYNC事件被通知的频率,request就是手动请求一次VSYNC事件,data channel就是获取数据传递的通道,这里是BitTube实现,它是一个利用Socket实现的跨进程通信的管道,并且你可以在它上面注册感兴趣的事件,当事件到来时候,它通知你(利用epoll实现)。
所以每个客户端可以选择自己要的VYSNC的事件的频率,然后就收听事件通知就可以了,Java层的Choreographer就是利用这个实现的。我们要指导这个IDisplayEventConnection是可以有多个的,比如View系统或者Animation系统都用到这个,比如你自己写的App如果不用系统View/Animation相关的,你也可以自己利用Choreographer来注册。
那现在SurfaceFlinger是如何管理这些事件请求或者监听通知的呢?
通过EventThread,这是一个普通的Thread,客户端每调用一次SurfaceFlinger的createDisplayEventConnection就会创建一个Connection,随后被加入到EventThreade当中的mDisplayEventConnections,并触发这个线程的threadLoop来执行(没有事件需要执行的时候,该线程是睡眠状态,因为waitForEvent方法里面有wait),最后将结果通过postEvent提交给BitTupe,这样之前有在上面注册事件监听的就会收到对应的事件。
详细的代码分析请参见(https://github.com/guohai/and-notes/tree/master/surfaceflinger-jb-4.2)中文注释/可能也有少部分是我添加的英文注释。

杂项:
另外FrameBufferNativeWindow已经不再被使用了。

我们通常说在新的支持硬件加速的设备和系统上,我们倾向于使用TextureView来替代SurfaceView,这里面又是什么原因呢?
都知道SurfaceView会单独创建一个Surface,在SurfaceFlinger当中的体现也是多创建一个Layer,然后与原有的,比如Window/Status Bar等等这些Layer合并之后再在display上画出来。
那使用TextureView就不会有这么一个过程吗?是的,因为TextureView里面利用了SurfaceTexture,SurfaceTexture的创建不会导致SurfaceFlinger中多出来一个Layer,因为它是使用硬件来做的,所以TextureView必须是支持硬件加速,并且开启的情况下才能使用,否则它什么也做不了。但是它还是会创建一个Layer,只不过这个Layer是硬件来创建,管理,那软件层面就不用花这个功来做这件事情。Native层的SurfaceTexture(ConsumerBase)它负责接收过来的数据,然后通过JNI往上传View层,软件层面的工作就结束了。

P.S. 详细信息待补充

Bitmap备忘

这是一篇阅读Bitmap相关内容的笔记!
程序运行环境:

Linux KNIGHT 3.0.0-28-generic #45-Ubuntu SMP Wed Nov 14 21:57:26 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

BMP图像文件被分成4个部分:位图文件头(Bitmap File Header)、位图信息头(Bitmap Info Header)、颜色表(Color Map)和位图数据(即图像数据,Data Bits或Data Body)。

这本书(http://vipbase.net/ipbook/chap01.htm)第一章节有讲这些。

biBitCount:每个像素所占的位数(bit),其值必须为1(黑白图像)、4(16色图)、8(256色)、24(真彩色图),32(带透明度alpha通道,位于前8位)。

以下这几篇博客有讲些基本的东西。
http://www.cnblogs.com/shengansong/archive/2011/09/23/2186409.html
http://blog.csdn.net/yutianzuijin/article/details/8243343
http://blog.csdn.net/scut1135/article/details/5573395

我有参考以上资料修改出一个可以在x86_64 GNU/Linux编译并运行的程序,注释里面有写些需要注意的地方。

some pitfalls of __attribute__((packed)), plz refer
http://stackoverflow.com/questions/8568432/is-gccs-attribute-packed-pragma-pack-unsafe
http://stackoverflow.com/questions/11770451/what-is-the-meaning-of-attribute-packed-aligned4
http://stackoverflow.com/questions/11667181/why-does-padding-have-to-be-a-power-of-two
http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member
http://en.wikipedia.org/wiki/Data_structure_alignment

Linux下BMP转化为JPEG程序源代码
http://www.linuxidc.com/Linux/2011-03/33193.htm

如果你自己要开发JPEG相关的话,确保这些包是有安装的。

sudo apt-get install libjpeg62
sudo apt-get install libjpeg62-dev