博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
/sf/bq/consumer/producer
阅读量:3622 次
发布时间:2019-05-21

本文共 11594 字,大约阅读时间需要 38 分钟。

本篇文章主要介绍了"BufferQueue/consumer/producer",主要涉及到BufferQueue/consumer/producer方面的内容,对于BufferQueue/consumer/producer感兴趣的同学可以参考一下。

针对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的状态,这个很简单,但是也很重要。1//BufferState represents the different states in which a buffer slot2//can be.3enumBufferState {4    //FREE indicates that the buffer is not currently being used and5    //will not be used in the future until it gets dequeued and6    //subsequently queued by the client.7    //aka "owned by BufferQueue, ready to be dequeued"8    FREE= 0,9 10    //DEQUEUED indicates that the buffer has been dequeued by the11    //client, but has not yet been queued or canceled. The buffer is12    //considered 'owned' by the client, and the server should not use13    //it for anything.14    //15    //Note that when in synchronous-mode (mSynchronousMode == true),16    //the buffer that's currently attached to the texture may be17    //dequeued by the client.  That means that the current buffer can18    //be in either the DEQUEUED or QUEUED state.  In asynchronous mode,19    //however, the current buffer is always in the QUEUED state.20    //aka "owned by producer, ready to be queued"21    DEQUEUED= 1,22 23    //QUEUED indicates that the buffer has been queued by the client,24    //and has not since been made available for the client to dequeue.25    //Attaching the buffer to the texture does NOT transition the26    //buffer away from the QUEUED state. However, in Synchronous mode27    //the current buffer may be dequeued by the client under some28    //circumstances. See the note about the current buffer in the29    //documentation for DEQUEUED.30    //aka "owned by BufferQueue, ready to be acquired"31    QUEUED= 2,32 33    //aka "owned by consumer, ready to be released"34    ACQUIRED= 335};BufferQueue主要方法dequeueBuffer取一个buffer(返回slot,这个bufer是从State为FREE的当中取的)给client使用,必要时候(null/height/width/format/usage任何一点不满足都会触发)它会使用GraphicBufferAlloc::createGraphicBuffer()去分配bufferrequestBuffer根据一个指定的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的bufferfreeBuffer或者cancelBuffer都会导致这个buffer处于FREE状态ConsumerBase的主要方法acquireBufferLocked/releaseBufferLocked/freeBufferLocked/abandonLocked另外这个protected的数组也很重要,子类可以直接从它里面获取buffer的信息,它实际就相当于缓存了BufferQueue的一些必要信息。1//mSlots stores the buffers that have been allocated by the BufferQueue2//for each buffer slot.  It is initialized to null pointers, and gets3//filled in with the result of BufferQueue::acquire when the4//client dequeues a buffer from a5//slot that has not yet been used. The buffer allocated to a slot will also6//be replaced if the requested buffer usage or geometry differs from that7//of the buffer allocated to a slot.8SlotmSlots[BufferQueue::NUM_BUFFER_SLOTS];SurfaceTextureClient是一个ANativeWindow,为native_window_api_*和native_window_*方法(这些都在system/core/include/system/window.h当中)做具体实现,另外它还持有SurfaceTexture。1//Initialize the ANativeWindow function pointers.2ANativeWindow::setSwapInterval = hook_setSwapInterval;3ANativeWindow::dequeueBuffer   = hook_dequeueBuffer;4ANativeWindow::cancelBuffer    = hook_cancelBuffer;5ANativeWindow::queueBuffer     = hook_queueBuffer;6ANativeWindow::query           = hook_query;7ANativeWindow::perform         = hook_perform;8 9ANativeWindow::dequeueBuffer_DEPRECATED= hook_dequeueBuffer_DEPRECATED;10ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;11ANativeWindow::lockBuffer_DEPRECATED   = hook_lockBuffer_DEPRECATED;12ANativeWindow::queueBuffer_DEPRECATED  = hook_queueBuffer_DEPRECATED;13 14const_cast<int&>(ANativeWindow::minSwapInterval)= 0;15const_cast<int&>(ANativeWindow::maxSwapInterval)= 1;一些重要的命名改动1早期的JellyBean当中,比如(4.1/4.2)                 4.32================================================================================3SurfaceTextureClient和Surface(继承                被简化成了Surface(ANativeWindow)4自SurfaceTextureClient)实际就是一个5ANativeWindow6 7================================================================================8ISurfaceTexture                                  IGraphicBufferProducer,9                                                  BinderIPC接口,用来在不同组件之间10                                                  传输数据使用(跨进程的),BufferQueue11                                                  实现了BnGraphicBufferProducer12 13================================================================================14SurfaceTexture(ConsumerBase)                     GLConsumer(ConsumerBase)它取15                                                  BufferQueue里面的数据,然后作为一个16                                                  texture提供给OpenGL使用上面是会用到的基本知识,下面基本才直接和SurfaceFlinger相关。箭头的方向为继承的方向1                             BpSurface      ---->>>>      ISurface2                                                           sp<ISurfaceTexture>ISurface::getSurfaceTexture()3 4BSurface      ---->>>>      BnSurface       ---->>>>      ISurface5sp<ISurfaceTexture>BSurface::getSurfaceTexture()6        SurfaceTexture::getBufferQueue()1Layer      ---->>>>      LayerBaseClient       ---->>>>       LayerBase2sp<ISurface>Layer::createSurface()3        newBSurface4 5                          sp<ISurface>LayerBaseClient::getSurface()6                                  sp<ISurface>LayerBaseClient::createSurface()1                           BpSurfaceComposerClient      ---->>>>      ISurfaceComposerClient2                                                                       sp<ISurface>ISurfaceComposerClient::createSurface()3 4Client      ---->>>>      BnSurfaceComposerClient       ---->>>>      ISurfaceComposerClient5Client::createSurface()6        SurfaceFlinger::createLayer()7                createXXXLayer()8                        newLayerXXX9                Layer::getSurface()10                    Layer::createSurface()1sp<SurfaceControl>SurfaceComposerClient::createSurface()2              ISurfaceComposerClient::createSurface()3              newSurfaceControl(ISurface)4//SurfaceComposerClient只是个普通的工具类,它的createSurface会去调用ISurfaceComposerClient和createSurface现在来看一种情况,假设客户端要创建一个SurfaceView,这中间会发生什么样的事情。当然你先得了解在Java层当中SurfaceView/SurfaceHolder/Surface这三者是什么关系。1=================================Java=====================================================2newSurfaceView3    surface= newSurface //这个是SurfaceView当中的Surface(这都是空的,不会在服务端真正的去创建一个Surface)4    newSurface= newSurface //这个是新的Surface,当Surface改变/被创建/被销毁/需要重绘,5                             //都会是现在系统层准备好,然后再复制来替代我们SurfaceView当6                             //中的原来的Surface(通过transferFrom完成)真正创建Surface的方法是系统去调用的,app不会直接去调用,但是一旦被调用之后就会进入到JNI层相应方法之中,会用到一个SurfaceSession,书面解释是表示到Surface Flinger的一次会话,因为客户端要同服务端沟通,就存在这样一个会话的概念,这个实际就是Native层SurfaceComposerClient的一个实例。1=================================JNI&Native========================================2android_view_Surface.cppnativeCreate()3    android_view_SurfaceSession_getClient4    SurfaceComposerClient->createSurface5        ISurfaceComposerClient->createSurface//IPC6            Client->createSurface7                SurfaceFlinger->createLayer8                    createXXXLayer()9                        newLayerXXX10                    Layer->getSurface()11        newSurfaceControl //SurfaceControl包含创建出来的ISurface12    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,如下:1staticsp<Surface> getSurface(JNIEnv* env, jobject surfaceObj) {2    sp<Surface>result(android_view_Surface_getSurface(env, surfaceObj)); //如果取出来为空3    if(result == NULL) {4        /*5         *if this method is called from the WindowManager's process, it means6         *the client is is not remote, and therefore is allowed to have7         *a Surface (data), so we create it here.8         *If we don't have a SurfaceControl, it means we're in a different9         *process.10         */11 12        SurfaceControl*constcontrol = reinterpret_cast<SurfaceControl*>(13                env->GetIntField(surfaceObj,gSurfaceClassInfo.mNativeSurfaceControl));14        if(control) {15            result= control->getSurface(); //创建Surface(SurfaceTextureClient)16            if(result != NULL) {17                result->incStrong(surfaceObj);18                env->SetIntField(surfaceObj,gSurfaceClassInfo.mNativeSurface, //Native关联变量,gui/Surface.h19                        reinterpret_cast<jint>(result.get()));20            }21        }22    }23    returnresult;24}25 26sp<ANativeWindow>android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) { //这是供Native Activity使用的27    returngetSurface(env, surfaceObj);28}看似这就是创建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显示出来了,这就是Camerapreview的原理。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层,软件层面的工作就结束了。

转载地址:http://nmkun.baihongyu.com/

你可能感兴趣的文章
oracle自动提交事务以及手动
查看>>
几分钟学会密码学(一)——维吉尼亚密码
查看>>
vulhub环境搭建+靶场使用
查看>>
Nginx 配置错误导致漏洞
查看>>
Webmin 远程命令执行漏洞
查看>>
Nginx越界读取缓存漏洞(CVE-2017-7529)
查看>>
DNS域传送漏洞——vulhub漏洞复现 007
查看>>
利用21端口的思路
查看>>
木马工作原理——病毒木马 002
查看>>
DHT11使用详解
查看>>
android
查看>>
Android——广播
查看>>
Android——内容提供者
查看>>
Android——网络编程
查看>>
Android——服务
查看>>
HarmonyOS工作原理解析
查看>>
数据库事务的四个特性及含义
查看>>
主题模型探讨
查看>>
stop word理解及超全的停用词表
查看>>
同义词挖掘的一些常用方法 及同义词替换程序
查看>>