Android5.1中surface和CpuConsumer下生产者和消费者间的处理框架简述

来源:转载

 

前沿:

如果对SurfaceFlinger架构的工作原理较为熟悉的话,本文阅读起来会相对容易些。之所以撰写本文是因为在阅读Camera HAL3的实现过程中大量的出现了类似与SurfaceFlinger的工作模式。本文将以CallbackProcessor模块的为入口,和大家进行分享。

 

 

1 Preview模块Surface与SurfaceFlinger的基础知识

开发过Android Camera模块的人,基本都应该熟悉实时采集的视频如果要显示到手机屏上,对应的Framework层就应该构建一个Surface对象,这对所有Android版本都是通用的。该Surface本质是一个在APP端的ANativeWindow,是需要从SurfaceFlinger端的Gralloc模块获取Buffer的,然后填充帧图像数据并送显示的过程。详细内容可以参考之前的专栏我心所向之Android4.2关于SurfaceFlinger相关的内容。

由于目前Android系统版本升级过快,在5.0以上的版本中SurfaceFlinger部分框架发生了变化(目前还没有深入去研读过),了解到的是:

一方面他去掉了SurfaceTexture/SurfaceTextureClient等内容,增强了Surface的功能。

另一方面BufferQueue的使用也更加简单与明了,Producer与Consumer的关系也更加明确,BufferQueue不再是以前的消费者角色,转而成为ProducerBufferQueue和Consumer相互关联的桥梁。

此外,如果你在深入的话,会了解到Gralloc模块中非framebuff的缓存管理与共享不在是那个Ashmem匿名共享内存,而是出现了一种新的内存管理机制/dev/ION/,后面会和大家分享他部分的工作机制。

对于SurfaceFlinger与Camera Preview Surface而言,ANativeWindow作为两者的共性负责管理和维护Buffer的创建与共享,在SurfaceFlinger端ANativeWindow创建buffer,在Surface侧通过dequeuebuffer获取buffer handle到本地进行共享,在填充完数据后通过queuebuffer告诉SurfaceFlinger当前buffer可用,这样就形成了一个buffer生产与消费的关系,基于这种原理我们在Camera3Device中除了看到正常的Preview Surface之外还看到了其他模块中出现了Surface的创建。

 

2 CallbackProcessor::updateStream() 创建Surface

 

 sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer);//BufferQueueProducer与BufferQueueConsumer mCallbackConsumer = new CpuConsumer(consumer, kCallbackHeapCount); mCallbackConsumer->setFrameAvailableListener(this);//当前CallbackProcessor继承于CpuConsumer::FrameAvailableListener mCallbackConsumer->setName(String8(Camera2Client::CallbackConsumer)); mCallbackWindow = new Surface(producer);//用于queue操作,这里直接进行本地的buffer操作
上述代码看上去很简单,但就是他最终形成了一个bufferstream Product和Consumer的处理,这种方式也为Camera2Client下出现多路stream,多路数据流存在奠定了基础,下面我们来简单的描述他的工作机制。

 

 

2.1 BufferQueue::createBufferQueue

 

void BufferQueue::createBufferQueue(sp* outProducer, sp* outConsumer, const sp& allocator) { LOG_ALWAYS_FATAL_IF(outProducer == NULL, BufferQueue: outProducer must not be NULL); LOG_ALWAYS_FATAL_IF(outConsumer == NULL, BufferQueue: outConsumer must not be NULL); sp core(new BufferQueueCore(allocator)); LOG_ALWAYS_FATAL_IF(core == NULL, BufferQueue: failed to create BufferQueueCore); sp producer(new BufferQueueProducer(core));//本地Bn的BufferQueueProducer LOG_ALWAYS_FATAL_IF(producer == NULL, BufferQueue: failed to create BufferQueueProducer); sp consumer(new BufferQueueConsumer(core));//本地Bn的BufferQueueConsumer LOG_ALWAYS_FATAL_IF(consumer == NULL, BufferQueue: failed to create BufferQueueConsumer); *outProducer = producer; *outConsumer = consumer;}
当前Android5.1版本中可以看到BufferQueue已经改变了原先的角色,成为了一个用于创建一组操作BufferQueue的接口,实现了BufferQueueProducer与BufferQueueConsumer的创建。更本质说现在BufferQueue的工作量已经很小,基本由Surface来全盘操作。这里通过BufferQueueCore会将BufferQueueProducer与BufferQueueConsumer绑定在一起,BufferQueueProducer可以说是替代了旧版本Android4.2中的SurfaceTextureClient,而BufferQueueConsumer则直接是SurfaceTexture以及BufferQueue的替代者。下图是在Android4.2.2中Surface和SurfaceFlinger间基于Bn/BpSurfaceTexture的多进程间buffer的queue操作机制。

 

2.2 CpuConsumer

在2.1中本质上是创建了BufferQueueProducer和BufferQueueConsumer,一般是成对出现。

这个CpuConsumer的地位本质是和SurfaceFlinger是一样的,主要角色就是来处理已经带有帧数据的buffer块,所以整个的处理机制都是类型的,其中两者均为继承一个ConsumerBase类,用于实现对buffer块的处理。

 

CpuConsumer::CpuConsumer(const sp& bq, uint32_t maxLockedBuffers, bool controlledByApp) : ConsumerBase(bq, controlledByApp), mMaxLockedBuffers(maxLockedBuffers), mCurrentLockedBuffers(0){ // Create tracking entries for locked buffers mAcquiredBuffers.insertAt(0, maxLockedBuffers); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); mConsumer->setMaxAcquiredBufferCount(maxLockedBuffers);}

 

 

2.3 mCallbackConsumer->setFrameAvailableListener(this)

这里所完成的过程是需要Consumer去将一个listener加入到Productor端去,便于在帧数据可用时,可以监听到并告知Consumer去做数据的处理,Product需要在数据可用时触发这个listener的onFrameAvailable,从而让数据从Productor转到Consumer则,数据处理应该是在同一进程的而不是跨进程。

如果作为Consumer如CPUConsumer没有使用setFrameAvailableListener将自己加入到listener中去,会由ConsumerBase的接口onFrameAvailable来替代完成。

2.4 mCallbackWindow = new Surface(producer)

这里是建立一个Surface,也就是类型于Preview模式下创建的Surface,两者的本质是一样的。在Android5.1中,Surface已经拥有了绝对的控制权,Preview模式下的Surface是跨进程的和SF进行交互,故构造函数传入的sp& bufferProducer参数一般是一个BufferQueue中BufferQueueProducer侧匿名的binder BpGraphicBufferProducer。对于CPUConsumer而言,两者是处于同一进程之中的,Surface主要行驶如下的操作,而在旧版本中这些主要由SurfaceTextureClient来管理的:

 

 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;
一般对Buffer的操作都先是基于Struct ANativeWindow这个本地的窗口类来处理,再是通过hook到实际的surface再交由GraphicBufferProducer来完成的。

 

 

3 Android5.1下Surface的queuebuffer操作逻辑

对比上一图可知,当前CPUConsumer模式下,从queuebuffer的处理过程来看更加体现出Productor和Consumer这种设计模式,整个架构代码看起来也更明了,这也是谷歌不断升级系统去冗存精的道理吧。整个用户在调用这种逻辑是,只需几句代码就可以获得对一个buffer块的读与写的操作接口,具体后续在分析Camera HAL3的数据流时可以很深刻的看到。

总的来说Surface在Camera3Device的架构下,与HAL3相组合是充当了消费者,与CPUCOnsumer或者Surfaceflinger来说就是生产者。或者说surface充当了buffer信息的传输与过渡。

 

 

 

 

分享给朋友:
您可能感兴趣的文章:
随机阅读: