在上一篇SurfaceFlinger创建Surface流程中,我们会关联到BufferQueue对GraphicBuffer的管理机制,我们这次就来分析一下它的原理。
角色扮演
Android应用的UI显示到Display的过程中,SurfaceFlinger扮演的角色只是“Flinger”,就是定于检查Layer更新,然后计算DirtyRegion,然后将结果推送给底层显示驱动进行显示。但是在App端,Surface的内容绘制却由应用层来承担。应用层绘制UI内容都需要一个GraphicBuffer,那么Surface对GraphicBuffer的申请、绘制完毕交给SurfaceFlinger去合成然后显示,这个工作也需要一套机制去管理。所以对于GraphicBuffer的管理,Android也设计了一套机制:BufferQueue,作为SurfaceFlinger管理和消费surface的中介。
生产-消费 模型
回顾Android SurfaceFlinger 学习之路(二)—-SurfaceFlinger概述,我们可以用这副简图表示App、BufferQueue和SurfaceFlinger的关系。
虽说是三者的关系,但是他们所属的层却只有两个,app属于Java层,BufferQueue/SurfaceFlinger属于native层。也就是说BufferQueue也是隶属SurfaceFlinger,所有工作围绕SurfaceFlinger展开。
生产者模型
这里IGraphicBufferProducer就是app和BufferQueue重要桥梁,GraphicBufferProducer承担着单个应用进程中的UI显示需求,与BufferQueue打交道的就是它。
根据上一篇Surface的创建流程,我们从Surface类图分析了GraphicBufferProducer在Surface中的位置,下图也可以表示:
BpGraphicBufferProducer是GraphicBufferProducer在客户端这边的代理对象,负责和SF交互,GraphicBufferProducer通过gbp(IGraphicBufferProducer类对象)向BufferQueue获取buffer,然后进行填充UI信息,当填充完毕会通知SF,SF知道后就对该Buffer进行下一步操作。典型的生产-消费者模式。
消费者模型
BufferQueue和SurfaceFlinger之间的通信模式如下:
也是有一对BpGraphicBufferConsumer/BnGraphicBufferConsumer支持他们之间的信息传输。
模型实现
上一篇创建Surface流程中,当创建Layer时候,在onFirstRef里面创建了一个生产者和消费者,并对两者进行了包装:
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;//生产者
sp<IGraphicBufferConsumer> consumer;//消费者
BufferQueue::createBufferQueue(&producer, &consumer);//创建生产者和消费者
mProducer = new MonitoredProducer(producer, mFlinger);//包装生产者
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);//包装消费者
//设置消费者相关回调
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
......
}
|
MonitoredProducer对象,这个对象只是一个代理,真正实是BufferQueueProducer类,这个对象和BufferQueueCore有关联,可以管理最多达64块的缓冲区。
SurfaceFlingerConsumer构造函数将BufferQueueConsumer传入,并设置相关回调,以便生产者填充完GraphicBuffer然后通知Consumer消费。
Core
所以创建生产者和消费者就是由BufferQueue来创建,我们可以看看BufferQueue的createBufferQueue函数,位于frameworks/native/libs/gui/BufferQueue.cpp:
void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
const sp<IGraphicBufferAlloc>& allocator) {//allocator == NULL
......
//创建一个BufferQueueCore,她是核心
sp<BufferQueueCore> core(new BufferQueueCore(allocator));
......
//用BufferQueueCore创建生产者
sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
......
//用core创建消费者
sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
......
//向外面传入指针赋值
*outProducer = producer;
*outConsumer = consumer;
}
|
所以核心都是这个BufferQueueCore,他是管理图形缓冲区的中枢。这里举一个SurfaceTexture的例子,来看看他们之间的关系:
可以认为BufferQueueCore是一个服务中心,生产者、消费者都要通过它来管理buffer。
- 里面有一个重要的成员数组:BufferQueueDefs::SlotsType mSlots;
- 这个BufferSlot中有一个成员变量:sp< GraphicBuffer >mGraphicBuffer;记录这个slot所涉及的缓冲区;
- 另一个变量BufferState mBufferState;用于跟踪这个缓冲区的状态。
1)在BufferQueueCore类中定义了一个64项的数据mSlots,framework/native/libs/gui/BufferQueueCore.h:
// mSlots is an array of buffer slots that must be mirrored on the producer
// side. This allows buffer ownership to be transferred between the producer
// and consumer without sending a GraphicBuffer over Binder. The entire
// array is initialized to NULL at construction time, and buffers are
// allocated for a slot when requestBuffer is called with that slot's index.
BufferQueueDefs::SlotsType mSlots;
|
我们看看这个mSlot定义所在的位置,位于frameworks/native/include/gui/BufferQueueDefs.h中:
namespace BufferQueueDefs {
// BufferQueue will keep track of at most this value of buffers.
// Attempts at runtime to increase the number of buffers past this
// will fail.
enum { NUM_BUFFER_SLOTS = 64 };
typedef BufferSlot SlotsType[NUM_BUFFER_SLOTS];
} // namespace BufferQueueDefs
|
我们可以看到这是一个容量大小为64的数组,因此BufferQueueCore可以管理最多64块的GraphicBuffer。
我们可以帖一幅图表示Slot的角色:
2)BufferSlot的定义位于frameworks/native/include/gui/BufferSlot.h中:
struct BufferSlot {
BufferSlot()
: mEglDisplay(EGL_NO_DISPLAY),
mBufferState(BufferSlot::FREE),
mRequestBufferCalled(false),
mFrameNumber(0),
mEglFence(EGL_NO_SYNC_KHR),
mAcquireCalled(false),
mNeedsCleanupOnRelease(false),
mAttachedByConsumer(false) {
}
// mGraphicBuffer points to the buffer allocated for this slot or is NULL
// if no buffer has been allocated.
sp<GraphicBuffer> mGraphicBuffer;
// BufferState represents the different states in which a buffer slot
// can be. All slots are initially FREE.
enum BufferState {
// FREE indicates that the buffer is available to be dequeued
// by the producer. The buffer may be in use by the consumer for
// a finite time, so the buffer must not be modified until the
// associated fence is signaled.
//
// The slot is "owned" by BufferQueue. It transitions to DEQUEUED
// when dequeueBuffer is called.
FREE = 0,
// DEQUEUED indicates that the buffer has been dequeued by the
// producer, but has not yet been queued or canceled. The
// producer may modify the buffer's contents as soon as the
// associated ready fence is signaled.
//
// The slot is "owned" by the producer. It can transition to
// QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
DEQUEUED = 1,
// QUEUED indicates that the buffer has been filled by the
// producer and queued for use by the consumer. The buffer
// contents may continue to be modified for a finite time, so
// the contents must not be accessed until the associated fence
// is signaled.
//
// The slot is "owned" by BufferQueue. It can transition to
// ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
// queued in asynchronous mode).
QUEUED = 2,
// ACQUIRED indicates that the buffer has been acquired by the
// consumer. As with QUEUED, the contents must not be accessed
// by the consumer until the fence is signaled.
//
// The slot is "owned" by the consumer. It transitions to FREE
// when releaseBuffer is called.
ACQUIRED = 3
};
// mBufferState is the current state of this buffer slot.
BufferState mBufferState;
}
|
mGraphicBuffer代表一块图形缓冲区GraphicBuffer,用于应用绘制UI。
mBufferState类型为BufferState ,BufferState 的定义也位于其中,代表图形缓冲区的几种状态:
- FREE:buffer当前可用,可以被生产者dequeued,此时owner是BufferQueueCore,当dequeuebuffer调用时,状态可以转为dequeued。
- DEQUEUED:buffer已经被dequeued,还没被queue或canceld,此时owner是producer。
- QUEUED:buffer已经被生产者填充,并被queued,此时的owner是bufferQueueCore。
- ACQUIRED:buffer已经被消费者获得,此时的owner是consumer。
一般的buffer大致会经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个流程,我们下面会讲到它。
3)在BufferQueueCore创建时候,还会创建一个GraphicBufferAlloc,并将它赋值给BufferQueueCore的mAllocator成员变量。我们可以看看BufferQueueCore的构造函数,位于framework/native/libs/gui/BufferQueueCore.cpp:
BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) ://allocator为NULL
mAllocator(allocator),
mMutex(),
mIsAbandoned(false),
mConsumerControlledByApp(false),
mConsumerName(getUniqueName()),
mConsumerListener(),
mConsumerUsageBits(0),
mConnectedApi(NO_CONNECTED_API),
mConnectedProducerListener(),
mSlots(),
mQueue(),
mOverrideMaxBufferCount(0),
mDequeueCondition(),
mUseAsyncBuffer(true),
mDequeueBufferCannotBlock(false),
mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
mDefaultWidth(1),
mDefaultHeight(1),
mDefaultMaxBufferCount(2),
mMaxAcquiredBufferCount(1),
mBufferHasBeenQueued(false),
mFrameCounter(0),
mTransformHint(0),
mIsAllocating(false),
mIsAllocatingCondition()
{
if (allocator == NULL) {//NULL
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
//请求SurfaceFlinger创建GraphicBufferAlloc
mAllocator = composer->createGraphicBufferAlloc();
if (mAllocator == NULL) {
BQ_LOGE("createGraphicBufferAlloc failed");
}
}
}
|
然后回去请求SurfaceFlinger创建一个GraphicBufferAlloc,位于frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp中:
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
{
//创建一个GraphicBufferAlloc对象,并赋给强指针
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
return gba;
}
|
因为BufferQueueCore的mAllocator 类型为IGraphicBufferAlloc,继承于IInterface,所以又是跨进程调用创建。我们下面会分析到它的。
Producer
BufferQueueProducer是生产者的实现,需要实现IGraphicBufferProducer接口,相关方法如下:
/*
* This class defines the Binder IPC interface for the producer side of
* a queue of graphics buffers. It's used to send graphics data from one
* component to another. For example, a class that decodes video for
* playback might use this to provide frames. This is typically done
* indirectly, through Surface.
*
* The underlying mechanism is a BufferQueue, which implements
* BnGraphicBufferProducer. In normal operation, the producer calls
* dequeueBuffer() to get an empty buffer, fills it with data, then
* calls queueBuffer() to make it available to the consumer.
*
* This class was previously called ISurfaceTexture.
*/
class IGraphicBufferProducer : public IInterface
{
public:
......
virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
virtual status_t queueBuffer(int slot,
const QueueBufferInput& input, QueueBufferOutput* output) = 0;
virtual void cancelBuffer(int slot, const sp<Fence>& fence) = 0;
......
}
|
这几个函数的注释写的很清楚,但是限于篇幅,没有贴出来。
BufferQueueProducer的dequeueBuffer函数用来向BufferQueueCore申请一个空闲的slot,这个slot可能已经有缓冲区,也可能没有,如果没有缓冲区,dequeueBuffer函数会分配一块新的缓冲区。得到空闲的slot后,还需要调用requestBuffer函数来取出一块缓冲区,也是从BufferQueueCore中的mSlots数组根据index获取这个位置的slot。得到缓冲区,如果不需要了,可以使用cancelBuffer函数来释放这个slot。调用dequeueBuffer函数之后,缓冲区的拥有者是生产者,缓冲区处于DEQUEUED状态。一旦缓冲区复制数据完成,通过queueBuffer函数把缓冲区的控制权交还给BufferQueueCore,这时候缓冲区将处于QUEUED状态。这些函数的使用之处我们下面会讲到。
BufferQueueProducer类图结构如下:
Consumer
同样,BufferQueueConsumer是消费者的实现,需要实现IGraphicBufferConsumer接口,相关方法如下:
class IGraphicBufferConsumer : public IInterface {
public:
......
virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0;
virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
EGLDisplay display, EGLSyncKHR fence,
const sp<Fence>& releaseFence) = 0;
......
}
|
注释写的很清晰,但是限于篇幅。。。
BufferQueueConsumer类是接口IGraphicBufferComsumer的实现,是一个回调接口,如果BufferQueue中有数据准备好了通知消费者取走数据。取走数据的时候,需要调用acquireBuffer函数,将缓冲区状态变成ACQUIRED,使用完之后调用releaseBuffer函数可以吧缓冲区数据归还给BufferQueueCore,这样缓冲区就变成FREE。
那consumer怎么知道一块buffer已经填充好了
?
所以我们顺着Layer的onFirstRef函数,里面还有一个对于消费者的封装:SurfaceFlingerConsumer。为了方便,我再贴一遍Layer的onFirstRef函数:
void Layer::onFirstRef() {
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
mProducer = new MonitoredProducer(producer, mFlinger);
//创建一个SurfaceFlingerConsumer用于通知消费者消费
mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
//给消费者设置监听者
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
}
|
为了方便起见,我们将BufferQueueConsumer和SurfaceFlingerConsumer的类图都贴出来:
为了通知消费消费GraphicBuffer,这里提供了另外一个类ConsumerListener,位于frameworks/native/include/gui/IConsumerListener.h:
ConsumerListener() { }
virtual ~ConsumerListener() { }
// onFrameAvailable is called from queueBuffer each time an additional
// frame becomes available for consumption. This means that frames that
// are queued while in asynchronous mode only trigger the callback if no
// previous frames are pending. Frames queued while in synchronous mode
// always trigger the callback.
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
virtual void onFrameAvailable() = 0; /* Asynchronous */
// onBuffersReleased is called to notify the buffer consumer that the
// BufferQueue has released its references to one or more GraphicBuffers
// contained in its slots. The buffer consumer should then call
// BufferQueue::getReleasedBuffers to retrieve the list of buffers
//
// This is called without any lock held and can be called concurrently
// by multiple threads.
virtual void onBuffersReleased() = 0; /* Asynchronous */
// onSidebandStreamChanged is called to notify the buffer consumer that the
// BufferQueue's sideband buffer stream has changed. This is called when a
// stream is first attached and when it is either detached or replaced by a
// different stream.
virtual void onSidebandStreamChanged() = 0; /* Asynchronous */
};
|
两个纯虚函数,当一块buffer可以被消费时,onFrameAvailable会被调用;当BufferQueue通知consumer它已经释放其mSlot中的一个或多个GraphicBuffer的引用时,会调用onBuffersReleased。
那么什么时候注册的这个监听呢?我们需要跟随一下SurfaceFlingerConsumer 的构造函数,位于frameworks/native/services/surfaceflinger/SurfaceFlingerConsumer.h中:
SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
uint32_t tex)
//调用了GLConsumer的构造函数
: GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
mTransformToDisplayInverse(false)
{}
|
我们需要继续查看GLConsumer的构造函数,位于frameworks/native/libs/gui/GLConsumer.cpp:
GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
ConsumerBase(bq, isControlledByApp), //有调用了ConsumerBase的构造函数,猫腻应该在这里
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentFence(Fence::NO_FENCE),
mCurrentTimestamp(0),
mCurrentFrameNumber(0),
mDefaultWidth(1),
mDefaultHeight(1),
mFilteringEnabled(true),
mTexName(tex),
mUseFenceSync(useFenceSync),
mTexTarget(texTarget),
mEglDisplay(EGL_NO_DISPLAY),
mEglContext(EGL_NO_CONTEXT),
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
mAttached(true)
{
ST_LOGV("GLConsumer");
memcpy(mCurrentTransformMatrix, mtxIdentity,
sizeof(mCurrentTransformMatrix));
mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}
|
又调用了ConsumerBase的构造函数,猫腻应该在这里,我们继续查看ConsumerBase的构造函数,位于frameworks/native/libs/gui/ConsumerBase.cpp中:
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
mAbandoned(false),
mConsumer(bufferQueue) {
// Choose a name using the PID and a process-unique ID.
mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
// Note that we can't create an sp<...>(this) in a ctor that will not keep a
// reference once the ctor ends, as that would cause the refcount of 'this'
// dropping to 0 at the end of the ctor. Since all we need is a wp<...>
// that's what we create.
//创建监听者对象
wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
//包装成一个代理
sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
//mConsumer调用consumerConnect函数,通过mConsumer,把consumerListener注册到服务者类bufferQueuecore中
status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
if (err != NO_ERROR) {
CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
strerror(-err), err);
} else {
mConsumer->setConsumerName(mName);
}
}
|
上面代码主要工作有:
1)创建监听者对象;
2)包装成一个代理;
3)mConsumer调用consumerConnect函数,通过mConsumer,把consumerListener注册到服务者类bufferQueuecore中。
那么注册操作就在于第三部。这里BufferQueueConsumer调用consumerConnect函数,位于frameworks/native/libs/gui/BufferQueueConsumer.h中:
virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
bool controlledByApp) {
return connect(consumer, controlledByApp);
}
|
在头文件里定义了consumerConnect函数,调用connect函数,位于frameworks/native/libs/gui/BufferQueueConsumer.cpp中:
status_t BufferQueueConsumer::connect(
const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
ATRACE_CALL();
if (consumerListener == NULL) {
BQ_LOGE("connect(C): consumerListener may not be NULL");
return BAD_VALUE;
}
BQ_LOGV("connect(C): controlledByApp=%s",
controlledByApp ? "true" : "false");
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("connect(C): BufferQueue has been abandoned");
return NO_INIT;
}
//这里把consumerListener注册到服务者类bufferQueuecore中
mCore->mConsumerListener = consumerListener;
mCore->mConsumerControlledByApp = controlledByApp;
return NO_ERROR;
}
|
connect连接,经过层层调用,把listener监听注册到bufferQueuecore中,
这样bufferQueuecore就可以利用这个监听通知到具体的消费者。
接着就是设置监听者:mSurfaceFlingerConsumer->setContentsChangedListener(this);我们可以看看他的操作:
void SurfaceFlingerConsumer::setContentsChangedListener(
const wp<ContentsChangedListener>& listener) {
//调用了ConsumerBase的setFrameAvailableListener函数
setFrameAvailableListener(listener);
Mutex::Autolock lock(mMutex);
mContentsChangedListener = listener;
}
/**ConsumerBase的setFrameAvailableListener函数**/
void ConsumerBase::setFrameAvailableListener(
const wp<FrameAvailableListener>& listener) {
CB_LOGV("setFrameAvailableListener");
Mutex::Autolock lock(mMutex);
mFrameAvailableListener = listener;
}
|
这样就构成了完整的监听者模式了,有Observer,也有Observable。
这样就清楚了buffer的生产者,消费者,管理者之间的关系。
Chris Simmonds
老爷子的话,就是如下内容:
- Mechanism for passing GraphicBuffers to SurfaceFlinger
- Contains an array of between 2 and 64 GraphicBuffers
- Uses interface IGraphicBufferAlloc to allocate buffers (see later)
- Provides two Binder interfaces:
- IGraphicBufferProducer for the client (Activity)
- IGraphicBufferConsumer for the consumer (SurfaceFlinger)
- Buffers cycle between producer and consumer
分配图形缓冲区
首先buffer是共享缓冲区,故肯定会涉及到互斥锁,所以buffer的状态也有很多种,一般buffer大致会经过FREE->DEQUEUED->QUEUED->ACQUIRED->FREE这个过程。如果所示:
或者这样表示这个过程:
申请图形缓冲区
前面看到,bufferqueuecore中mSlots数组管理缓冲区,最大容量是64,这个mSlots一开始静态分配了64个bufferslot大小的空间,但是其中的数据缓冲区不是一次性分配的,不然就太浪费空间了,所以缓冲区的空间分配是动态的,具体就是producer在dequeuebuffer时,如果没有获取到可用的缓冲区,那就要重新分配空间了。
分配图形缓冲区,即GraphicBuffer,我们需要查看BufferQueueProducer的dequeuebuffer函数:
status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
sp<android::Fence> *outFence, bool async,
uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
ATRACE_CALL();
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
} // Autolock scope
BQ_LOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x",
async ? "true" : "false", width, height, format, usage);
//宽高不正常,则返回失败
if ((width && !height) || (!width && height)) {
BQ_LOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height);
return BAD_VALUE;
}
//一些变量赋初值
status_t returnFlags = NO_ERROR;
EGLDisplay eglDisplay = EGL_NO_DISPLAY;
EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
bool attachedByConsumer = false;
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
//如果正在申请Grabuffer,则要wait。里面是一个mIsAllocating标志位判断,如果为true则要等待
mCore->waitWhileAllocatingLocked();
//如果format为0,则赋为初值PIXEL_FORMAT_RGBA_8888
if (format == 0) {
format = mCore->mDefaultBufferFormat;
}
// Enable the usage bits the consumer requested
usage |= mCore->mConsumerUsageBits;
int found;//先在mSlot数组中查找FREE状态的slot,如果找到了就返回这个slot中的index。
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
&found, &returnFlags);
if (status != NO_ERROR) {
return status;
}
// This should not happen
//这种情况一般不会发生,因为如何found是INVALID_BUFFER_SLOT状态,上面的status就不会是NO_Error,就不会走到这里
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("dequeueBuffer: no available buffer slots");
return -EBUSY;
}
//将找到的slot的index赋给外面传入的outSlot指向内容
*outSlot = found;
ATRACE_BUFFER_INDEX(found);
attachedByConsumer = mSlots[found].mAttachedByConsumer;
const bool useDefaultSize = !width && !height;
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
}
//改变BufferState状态为DEQUEUED
mSlots[found].mBufferState = BufferSlot::DEQUEUED;
//然后将返回index的slot的Graphicbuffer赋给buffer变量
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
//判断这个GraphicBuffer是否需要重新分配空间,判断条件就是buffer为空,因为它初始值是null,第一次使用它需要分配空间,
//如果不为null,但是buffer的width、height、format、usage属性跟要求的不一致,也要重新分配
if ((buffer == NULL) ||
(static_cast<uint32_t>(buffer->width) != width) ||
(static_cast<uint32_t>(buffer->height) != height) ||
(static_cast<uint32_t>(buffer->format) != format) ||
((static_cast<uint32_t>(buffer->usage) & usage) != usage))
{
//如果需要重新分配GraphicBuffer,先初始化这些变量
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
mSlots[found].mRequestBufferCalled = false;
mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
//增加BUFFER_NEEDS_REALLOCATION标志,已重新分配GraphicBuffer
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
"slot=%d w=%d h=%d format=%u",
found, buffer->width, buffer->height, buffer->format);
}
//给一些临时变量赋值
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
*outFence = mSlots[found].mFence;
//给fence变量赋初值
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
} // Autolock scope
//如果需要重新分配GraphicBuffer
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
//需要重新分配,调用BufferQueueCore中的GraphicBufferAlloc中函数createGraphicBuffer,生成一个newGraphicBuffer
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
width, height, format, usage, &error));
if (graphicBuffer == NULL) {
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
return error;
}
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("dequeueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
新分配的buffer,将slot的mFrameNumber 置为最大。mFrameNumber 用于LRU排序
mSlots[*outSlot].mFrameNumber = UINT32_MAX;
//将分配的buffer赋给slot中的mGraphicBuffer
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
}
if (attachedByConsumer) {
returnFlags |= BUFFER_NEEDS_REALLOCATION;
}
//如果eglFence不等于EGL_NO_SYNC_KHR。Fence我们后面会讲到,一种围栏机制
if (eglFence != EGL_NO_SYNC_KHR) {
//等待Buffer状态就绪,然后fence围栏放行
EGLint result = eglClientWaitSyncKHR(eglDisplay, eglFence, 0,
1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
if (result == EGL_FALSE) {
BQ_LOGE("dequeueBuffer: error %#x waiting for fence",
eglGetError());
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
BQ_LOGE("dequeueBuffer: timeout waiting for fence");
}
eglDestroySyncKHR(eglDisplay, eglFence);
}
BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
*outSlot,
mSlots[*outSlot].mFrameNumber,
mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
return returnFlags;
}
|
代码虽然多,但是逻辑不复杂,我们分步查看:
1)先在mSlot数组中查找FREE状态的slot,如果找到了就返回这个slot中的index。这个操作是调用了waitForFreeSlotThenRelock函数,我们看看这个函数的实现:
status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
bool async, int* found, status_t* returnFlags) const {
bool tryAgain = true;//默认是true
while (tryAgain) {
if (mCore->mIsAbandoned) {//如果没有初始化,BufferQueue被abandoned
BQ_LOGE("%s: BufferQueue has been abandoned", caller);
return NO_INIT;
}
//getMaxBufferCountLocked returns the maximum number of buffers that can be allocated at once
//注释还有一些,不贴了。就是获取一次申请的buffer的最大值。查看了代码,就是所有状态的buffer个数。
const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
//如果async为true,即异步操作,并且mOverrideMaxBufferCount不为0
//(一般mOverrideMaxBufferCount是在BufferQueueProducer调用setBufferCount函数改变,
//这个函数会更新mSlot中所有Slot的状态为未分配的,并把ower还给BufferQueue)
if (async && mCore->mOverrideMaxBufferCount) {
// FIXME: Some drivers are manually setting the buffer count
// (which they shouldn't), so we do this extra test here to
// handle that case. This is TEMPORARY until we get this fixed.
//因为是异步的关系,一些驱动会修改buffer count,但是返回不及时,所以这两个值可能不相等
if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
BQ_LOGE("%s: async mode is invalid with buffer count override",
caller);
return BAD_VALUE;
}
}
// Free up any buffers that are in slots beyond the max buffer count
//释放所有超出buffer数组最大数64的buffer
for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
assert(mSlots[s].mBufferState == BufferSlot::FREE);
if (mSlots[s].mGraphicBuffer != NULL) {
mCore->freeBufferLocked(s);
*returnFlags |= RELEASE_ALL_BUFFERS;
}
}
// Look for a free buffer to give to the client
//开始查找FREE状态的Buffer,并返回
*found = BufferQueueCore::INVALID_BUFFER_SLOT;
int dequeuedCount = 0;
int acquiredCount = 0;
for (int s = 0; s < maxBufferCount; ++s) {
switch (mSlots[s].mBufferState) {
case BufferSlot::DEQUEUED:
++dequeuedCount;//DEQUEUED + 1
break;
case BufferSlot::ACQUIRED:
++acquiredCount;//ACQUIRED + 1
break;
case BufferSlot::FREE:
// We return the oldest of the free buffers to avoid
// stalling the producer if possible, since the consumer
// may still have pending reads of in-flight buffers
//返回最老的FREE buffer,为了避免当consumer还在等待消费pending的正在起飞的buffer时候,producer突然GG了
if (*found == BufferQueueCore::INVALID_BUFFER_SLOT ||//第一次找到FREE buffer,会将found指针指向这个index
//下次来的FREE buffer,就和上此找到的buffer对比slot的mFrameNumber ,找到mFrameNumber 最小的。
//这个就是根绝mFrameNumber 的大小进行LRU排序,最新的就是mFrameNumber 最大的,最老的就是mFrameNumber 最小的
mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) {
*found = s;
}
break;
default:
break;
}
}
// Producers are not allowed to dequeue more than one buffer if they
// did not set a buffer count
//Producers 如果没有调用setBufferCount是不允许dequeue buffer的
if (!mCore->mOverrideMaxBufferCount && dequeuedCount) {
BQ_LOGE("%s: can't dequeue multiple buffers without setting the "
"buffer count", caller);
return INVALID_OPERATION;
}
// See whether a buffer has been queued since the last
// setBufferCount so we know whether to perform the min undequeued
// buffers check below
//在queueBuffer调用后,mBufferHasBeenQueued会置为true
//如果在上次setBufferCount调用后,当buffer被queue进入BufferQueue,
//这时候需要检查undequeue的数量是否大于最小的临界值
if (mCore->mBufferHasBeenQueued) {
// Make sure the producer is not trying to dequeue more buffers
// than allowed
//总count - dequeue的count = undequeue的count
const int newUndequeuedCount =
maxBufferCount - (dequeuedCount + 1);
const int minUndequeuedCount =
mCore->getMinUndequeuedBufferCountLocked(async);
if (newUndequeuedCount < minUndequeuedCount) {
BQ_LOGE("%s: min undequeued buffer count (%d) exceeded "
"(dequeued=%d undequeued=%d)",
caller, minUndequeuedCount,
dequeuedCount, newUndequeuedCount);
return INVALID_OPERATION;
}
}
// If we disconnect and reconnect quickly, we can be in a state where
// our slots are empty but we have many buffers in the queue. This can
// cause us to run out of memory if we outrun the consumer. Wait here if
// it looks like we have too many buffers queued up.
//如果我们调用disconnect后迅速的reconnect,会出现mSlot数组为空但是mQueue队列中的BufferItem不为空
//所以这样会造成内存耗尽的后果
//就是判断放入mQueue中BufferItem的个数是否大于mSlot中的个数
//mQueue是用来存放申请的缓冲区的,是一个Vector
bool tooManyBuffers = mCore->mQueue.size()
> static_cast<size_t>(maxBufferCount);
if (tooManyBuffers) {
BQ_LOGV("%s: queue size is %zu, waiting", caller,
mCore->mQueue.size());
}
// If no buffer is found, or if the queue has too many buffers
// outstanding, wait for a buffer to be acquired or released, or for the
// max buffer count to change.
//如果没有找到FREE的buffer,或者mQueue中有太多buffer占据内存未释放
//那么等待buffer被acquired or released;
//或者等待最大buffer个数改变
tryAgain = (*found == BufferQueueCore::INVALID_BUFFER_SLOT) ||
tooManyBuffers;
if (tryAgain) {
// Return an error if we're in non-blocking mode (producer and
// consumer are controlled by the application).
// However, the consumer is allowed to briefly acquire an extra
// buffer (which could cause us to have to wait here), which is
// okay, since it is only used to implement an atomic acquire +
// release (e.g., in GLConsumer::updateTexImage())
if (mCore->mDequeueBufferCannotBlock &&
(acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
return WOULD_BLOCK;
}
//等待有buffer可以返回
mCore->mDequeueCondition.wait(mCore->mMutex);
}
} // while (tryAgain)
return NO_ERROR;
}
|
代码虽然多,但是大多数都是处理特殊情况的。核心就是从现存maxBufferCount找出FREE状态的slot,然后根据LRU匹配,取出最老的slot,然后返回index给found指针内容。
这样取出来FREE的slot(如果能找到)。
如果所有的buffer都不是free的,则等待。
2)将找到的buf所对应的状态修改为DEQUEUED;
3)然后将上面查询mSlot中返回index的slot的Graphicbuffer赋给buffer变量;
4)判断这个GraphicBuffer是否需要重新分配空间,判断条件就是buffer为空,因为它初始值是null,第一次使用它需要分配空间;如果不为null,但是buffer的width、height、format、usage属性跟要求的不一致,也要重新分配,并打上BUFFER_NEEDS_REALLOCATION标志位。
5)如果上面的buffer为null,则需要重新分配GraphicBuffer,调用BufferQueueCore中的GraphicBufferAlloc中函数createGraphicBuffer,生成一个new GraphicBuffer。
6)等待eglFence状态就绪。Fence机制我们以后会讲到。
创建图形缓冲区
GraphicBuffer创建
所以上述流程的核心是GraphicBuffer的分配,我们需要沿着上面继续分析。因此最后BufferQueueProducer中的dequeueBuffer函数中调用mCore->mAllocator的createGraphicBuffer函数就是调用了GraphicBufferAlloc的createGraphicBufferAlloc函数。mAllocator的类型为sp< IGraphicBufferAlloc >,要跨进程调用SurfaceFlinger的createGraphicBufferAlloc函数,上面讲过了。
上面刚刚说mAllocator的类型为sp< IGraphicBufferAlloc >,所以创建GraphicBuffer的函数createGraphicBuffer也需要Bp/Bn 的IPC跨进程调用过程。GraphicBuffer通过Binder传递对象是Parcel类型可序列化的,所以他要从模板类Flattenable派生。因为这个牵扯到内存缓冲区的fd传递到客户进程,所以我们放到后面讲。
所以我们先忽略IPC过程,直接查看生成结果,位于frameworks/native/libs/gui/GraphicBufferAlloc.cpp中:
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage, status_t* error) {
//创建一个GraphicBuffer对象
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
status_t err = graphicBuffer->initCheck();
*error = err;
if (err != 0 || graphicBuffer->handle == 0) {
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
"failed (%s), handle=%p",
w, h, strerror(-err), graphicBuffer->handle);
return 0;
}
return graphicBuffer;
}
|
上面创建一个GraphicBuffer对象,我们看看GraphicBuffer的构造函数,位于frameworks/native/libs/ui/GraphicBuffer.cpp:
GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
PixelFormat reqFormat, uint32_t reqUsage)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId())
{
width =
height =
stride =
format =
usage = 0;
handle = NULL;
//这里调用了initSize函数
mInitCheck = initSize(w, h, reqFormat, reqUsage);
}
|
构造函数给一些变量赋了初值,并调用了initSize函数,我们看看这个函数:
status_t GraphicBuffer::initSize(uint32_t w, uint32_t h, PixelFormat format,
uint32_t reqUsage)
{
//获取一个GraphicBufferAllocator对象,它是个单例
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
//调用allocator 的alloc函数
status_t err = allocator.alloc(w, h, format, reqUsage, &handle, &stride);
if (err == NO_ERROR) {
this->width = w;
this->height = h;
this->format = format;
this->usage = reqUsage;
}
return err;
}
|
先创建一个GraphicBufferAllocator的单例对象,我们先看看它的构造函数,位于frameworks/native/libs/ui/GraphicBufferAllocator.cpp中:
alloc_device_t *mAllocDev;
GraphicBufferAllocator::GraphicBufferAllocator()
: mAllocDev(0)
{
hw_module_t const* module;
//加载gralloc设备
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
//打开gralloc设备
gralloc_open(module, &mAllocDev);
}
}
|
GraphicBufferAllocator构造函数里主要是加载了gralloc设备,然后打开它,因此mAllocDev指向了Gralloc模块。这一部分可以查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现,Gralloc模块的加载过程、Gralloc设备的打开过程。
加载完Gralloc模块,并打开之后,接着就是分配图形缓冲区了。我们可以继续往下看看是不是,查看GraphicBufferAllocator的alloc函数:
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage, buffer_handle_t* handle, int32_t* stride)
{
ATRACE_CALL();
// make sure to not allocate a N x 0 or 0 x N buffer, since this is
// allowed from an API stand-point allocate a 1x1 buffer instead.
if (!w || !h)
w = h = 1;
// we have a h/w allocator and h/w buffer is requested
status_t err;
//这里内部是调用Gralloc模块中的函数gralloc_alloc来分配一块图形缓冲区
err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
w, h, format, usage, err, strerror(-err));
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
int bpp = bytesPerPixel(format);
if (bpp < 0) {
// probably a HAL custom format. in any case, we don't know
// what its pixel size is.
bpp = 0;
}
alloc_rec_t rec;
rec.w = w;
rec.h = h;
rec.s = *stride;
rec.format = format;
rec.usage = usage;
rec.size = h * stride[0] * bpp;
list.add(*handle, rec);
}
return err;
}
|
这里调用alloc分配了一块共享的内存缓冲区,就是我们的图形缓冲区。内部是调用Gralloc模块中的函数gralloc_alloc,可以产查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现,分配图形缓冲区。
这样我们GraphicBuffer的创建工作就完成了。
既然GraphicBuffer中的缓冲区是共享内存,我们知道使用共享内存需要传递共享内存的句柄fd。下面我们看看是如何传到客户进程的,填掉我们上面的坑。
内存缓冲区映射到应用进程
GraphicBuffer类是从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。
为了方便分析,我们可以看看GraphicBuffer的类图:
上面说到mAllocator的类型为sp< IGraphicBufferAlloc >,它的创建GraphicBuffer的函数createGraphicBuffer也需要Bp/Bn 的IPC跨进程调用过程,序列化传递和反序列话取出这里用于IPC传递数据,我们可以在这里看看客户端和服务端的工作流程。
我们先看看客户端Bp端,位于frameworks/native/libs/gui/IGraphicBufferAlloc.cpp中:
class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
{
public:
BpGraphicBufferAlloc(const sp<IBinder>& impl)
: BpInterface<IGraphicBufferAlloc>(impl)
{
}
//客户端创建图形缓冲区函数
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage, status_t* error) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
data.writeInt32(usage);
//通过binder驱动,执行服务端对应函数。这里服务端是将创建的GraphicBuffer序列化后,塞给replay
remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
sp<GraphicBuffer> graphicBuffer;
status_t result = reply.readInt32();
if (result == NO_ERROR) {
//创建一个空壳子
graphicBuffer = new GraphicBuffer();
//然后客户端从服务端(SurfaceFlinger)返回的序列化后的replay,
//反序列化出Graphicbuffer,放入空壳子中
result = reply.read(*graphicBuffer);
// reply.readStrongBinder();
// here we don't even have to read the BufferReference from
// the parcel, it'll die with the parcel.
}
*error = result;
return graphicBuffer;
}
};
|
客户端这里主要通过binder驱动,取出从服务端返回的序列化后的对象replay,然后自己造一个空壳子,然后读取replay信息,反序列化出GraphicBuffer。
那么服务端(SurfaceFlinger)创建GraphicBuffer并反序列化就在Bn端,我们看看Bn端实现,同样位于位于frameworks/native/libs/gui/IGraphicBufferAlloc.cpp中:
status_t BnGraphicBufferAlloc::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// codes that don't require permission check
/* BufferReference just keeps a strong reference to a
* GraphicBuffer until it is destroyed (that is, until
* no local or remote process have a reference to it).
*/
class BufferReference : public BBinder {
sp<GraphicBuffer> buffer;
public:
BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { }
};
switch(code) {
case CREATE_GRAPHIC_BUFFER: {
CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
PixelFormat format = data.readInt32();
uint32_t usage = data.readInt32();
status_t error;
//调用GraphicBufferAlloc的createGraphicBuffer函数,创建一个GraphicBuffer实例
sp<GraphicBuffer> result =
createGraphicBuffer(w, h, format, usage, &error);
reply->writeInt32(error);
if (result != 0) {
GraphicBuffer进行序列化,传给client
reply->write(*result);
// We add a BufferReference to this parcel to make sure the
// buffer stays alive until the GraphicBuffer object on
// the other side has been created.
// This is needed so that the buffer handle can be
// registered before the buffer is destroyed on implementations
// that do not use file-descriptors to track their buffers.
reply->writeStrongBinder( new BufferReference(result) );
}
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
|
GraphicBufferAlloc的createGraphicBuffer函数我们上面分析过了。这样就将创建的GraphicBuffer实例序列化后,在通过binder驱动传给client。
我们知道,一个对象要在进程间传输必须继承于Flattenable类,并且实现flatten和unflatten方法,flatten方法用于序列化该对象,unflatten方法用于反序列化对象。
上面说到GraphicBuffer中的缓冲区是共享内存,使用共享内存需要传递共享内存的句柄fd,那么这个fd的传递就应该在GraphicBuffer的序列化/反序列化中,我们就来看看这个过程。
这里我先回顾一下Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现的内容:
图形缓冲区可以从系统帧缓冲区分配也可以从内存中分配,分配一个图形缓冲区后还需要将该图形缓冲区映射到分配该buffer的进程地址空间来,在Android系统中,图形缓冲区的管理由SurfaceFlinger服务来负责。在系统帧缓冲区中分配的图形缓冲区是在SurfaceFlinger服务中使用,而在内存中分配的图形缓冲区既可以在SurfaceFlinger服务中使用,也可以在其它的应用程序中使用。当其它的应用程序需要使用图形缓冲区的时候,它们就会请求SurfaceFlinger服务为它们分配并将SurfaceFlinger服务返回来的图形缓冲区映射到应用程序进程地址空间。在从内存中分配buffer时,已经将分配的buffer映射到了SurfaceFlinger服务进程地址空间,如果该buffer是应用程序请求SurfaceFlinger服务为它们分配的,那么还需要将SurfaceFlinger服务返回来的图形缓冲区映射到应用程序进程地址空间。
GraphicBuffer类从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。
1)将一个对象写入到Parcel中,需要使用flatten函数序列化该对象,我们先来看下flatten函数:
status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = GraphicBuffer::getFdCount();
if (count < fdCountNeeded) return NO_MEMORY;
int32_t* buf = static_cast<int32_t*>(buffer);
buf[0] = 'GBFR';
buf[1] = width;
buf[2] = height;
buf[3] = stride;
buf[4] = format;
buf[5] = usage;
buf[6] = static_cast<int32_t>(mId >> 32);
buf[7] = static_cast<int32_t>(mId & 0xFFFFFFFFull);
buf[8] = 0;
buf[9] = 0;
if (handle) {
buf[8] = handle->numFds;
buf[9] = handle->numInts;
native_handle_t const* const h = handle;
//把handle中的data复制到fds中
memcpy(fds, h->data, h->numFds*sizeof(int));
memcpy(&buf[10], h->data + h->numFds, h->numInts*sizeof(int));
}
buffer = reinterpret_cast<void*>(static_cast<int*>(buffer) + sizeNeeded);
size -= sizeNeeded;
if (handle) {
fds += handle->numFds;
count -= handle->numFds;
}
return NO_ERROR;
}
|
这个handle类型为native_handle_t ,且typedef成了buffer_handle_t,如果忘记了这一部分,可以查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现。我们贴一下它的定义:
typedef struct native_handle
{
int version; //设置为结构体native_handle_t的大小,用来标识结构体native_handle_t的版本
int numFds; //表示结构体native_handle_t所包含的文件描述符的个数,这些文件描述符保存在成员变量data所指向的一块缓冲区中。
int numInts; //表示结构体native_handle_t所包含的整数值的个数,这些整数保存在成员变量data所指向的一块缓冲区中。
int data[0]; //指向的一块缓冲区中
} native_handle_t;
|
所以我们回到flatten函数中,fds参数用来传递文件句柄,函数把handle中的表示指向图形缓冲区文件描述符句柄复制到fds中,因此这些句柄就能通过binder传递到目标进程中去。
2)在应用程序读取来自服务进程的GraphicBuffer对象时,也就是result = reply.read(*p),会调用GraphicBuffer类的unflatten函数进行反序列化过程:
status_t GraphicBuffer::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
if (size < 8*sizeof(int)) return NO_MEMORY;
int const* buf = static_cast<int const*>(buffer);
if (buf[0] != 'GBFR') return BAD_TYPE;
const size_t numFds = buf[8];
const size_t numInts = buf[9];
const size_t sizeNeeded = (10 + numInts) * sizeof(int);
if (size < sizeNeeded) return NO_MEMORY;
size_t fdCountNeeded = 0;
if (count < fdCountNeeded) return NO_MEMORY;
if (handle) {
// free previous handle if any
free_handle();
}
if (numFds || numInts) {
width = buf[1];
height = buf[2];
stride = buf[3];
format = buf[4];
usage = buf[5];
//创建一个native_handle对象
native_handle* h = native_handle_create(numFds, numInts);
//将fds复制到native_handle对象的data中,和flatten操作相反
memcpy(h->data, fds, numFds*sizeof(int));
memcpy(h->data + numFds, &buf[10], numInts*sizeof(int));
handle = h;
} else {
width = height = stride = format = usage = 0;
handle = NULL;
}
mId = static_cast<uint64_t>(buf[6]) << 32;
mId |= static_cast<uint32_t>(buf[7]);
mOwner = ownHandle;
if (handle != 0) {
//使用GraphicBufferMapper将服务端创建的图形缓冲区映射到当前进程地址空间
status_t err = mBufferMapper.registerBuffer(handle);
if (err != NO_ERROR) {
width = height = stride = format = usage = 0;
handle = NULL;
ALOGE("unflatten: registerBuffer failed: %s (%d)",
strerror(-err), err);
return err;
}
}
buffer = reinterpret_cast<void const*>(static_cast<int const*>(buffer) + sizeNeeded);
size -= sizeNeeded;
fds += numFds;
count -= numFds;
return NO_ERROR;
}
|
调用unflatten函数时,共享区的文件句柄已经准备好了,但是内存还没有进行映射,调用了mBufferMapper.registerBuffer函数来进行内存映射。
GraphicBufferMapper是单例的模板类派生的,mBufferMapper对象在GraphicBuffer的构造函数中初始化赋值了,上面我们列出过了。我们看看GraphicBufferMapper的构造函数,位于frameworks/native/libs/ui/GraphicBufferMapper.cpp:
GraphicBufferMapper::GraphicBufferMapper()
: mAllocMod(0)
{
hw_module_t const* module;
//加载gralloc模块
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
ALOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
if (err == 0) {
将hw_module_t的指针转换为gralloc_module_t类型指针
mAllocMod = (gralloc_module_t const *)module;
}
}
|
这里根据模块ID加载Gralloc模块,并得到Gralloc模块的HMI符号首地址,并强制转换为gralloc_module_t类型指针。
我们接着看下GraphicBufferMapper::registerBuffer函数:
status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
{
ATRACE_CALL();
status_t err;
//将服务端创建的图形缓冲区映射到当前进程地址空间
err = mAllocMod->registerBuffer(mAllocMod, handle);
ALOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
handle, err, strerror(-err));
return err;
}
|
调用了mAllocMod的registerBuffer函数,mAllocMod同样是指向了Gralloc模块的指针,因此实际是调用了Gralloc模块的gralloc_register_buffer函数。这个函数就是调用了mmap来进行共享内存的映射。
这一部分仍然可以查看Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现。我们仍然回顾一下以前的内容:
registerBuffer和unregisterBuffer分别用来注册和注销一个指定的图形缓冲区,所谓注册图形缓冲区,实际上就是将一块图形缓冲区映射到一个进程的地址空间去,而注销图形缓冲区就是执行相反的操作。lock和unlock分别用来锁定和解锁一个指定的图形缓冲区,在访问一块图形缓冲区的时候,例如,向一块图形缓冲写入内容的时候,需要将该图形缓冲区锁定,用来避免访问冲突。在锁定一块图形缓冲区的时候,可以指定要锁定的图形绘冲区的位置以及大小,这是通过参数l、t、w和h来指定的,其中,参数l和t指定的是要访问的图形缓冲区的左上角位置,而参数w和h指定的是要访问的图形缓冲区的宽度和长度。锁定之后,就可以获得由参数参数l、t、w和h所圈定的一块缓冲区的起始地址,保存在输出参数vaddr中。另一方面,在访问完成一块图形缓冲区之后,需要解除这块图形缓冲区的锁定。
这就是内存缓冲区映射到应用进程的过程。因为需要映射共享内存,所以必须要序列化和反序列Pracel对象。如下图:
这里我们创建GraphicBuffer流程就分析完了。
小结
本节主要分析GraphicBuffer的创建过程,下一节我们分析对它的管理流程。