Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

时间:2021-02-14 03:57:17


http://windrunnerlihuan.com/2017/06/22/Android-SurfaceFlinger-%E5%AD%A6%E4%B9%A0%E4%B9%8B%E8%B7%AF-%E4%B8%83-%E5%88%9B%E5%BB%BA%E5%9B%BE%E5%BD%A2%E7%BC%93%E5%86%B2%E5%8C%BAGraphicBuffer/


       在上一篇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的关系。

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       虽说是三者的关系,但是他们所属的层却只有两个,app属于Java层,BufferQueue/SurfaceFlinger属于native层。也就是说BufferQueue也是隶属SurfaceFlinger,所有工作围绕SurfaceFlinger展开。

生产者模型

        这里IGraphicBufferProducer就是app和BufferQueue重要桥梁,GraphicBufferProducer承担着单个应用进程中的UI显示需求,与BufferQueue打交道的就是它。
        根据上一篇Surface的创建流程,我们从Surface类图分析了GraphicBufferProducer在Surface中的位置,下图也可以表示:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       BpGraphicBufferProducer是GraphicBufferProducer在客户端这边的代理对象,负责和SF交互,GraphicBufferProducer通过gbp(IGraphicBufferProducer类对象)向BufferQueue获取buffer,然后进行填充UI信息,当填充完毕会通知SF,SF知道后就对该Buffer进行下一步操作。典型的生产-消费者模式

消费者模型

       BufferQueue和SurfaceFlinger之间的通信模式如下:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       也是有一对BpGraphicBufferConsumer/BnGraphicBufferConsumer支持他们之间的信息传输。

模型实现

       上一篇创建Surface流程中,当创建Layer时候,在onFirstRef里面创建了一个生产者和消费者,并对两者进行了包装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的例子,来看看他们之间的关系:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       可以认为BufferQueueCore是一个服务中心,生产者、消费者都要通过它来管理buffer。

  • 里面有一个重要的成员数组:BufferQueueDefs::SlotsType mSlots;
  • 这个BufferSlot中有一个成员变量:sp< GraphicBuffer >mGraphicBuffer;记录这个slot所涉及的缓冲区;
  • 另一个变量BufferState mBufferState;用于跟踪这个缓冲区的状态。

       1)在BufferQueueCore类中定义了一个64项的数据mSlots,framework/native/libs/gui/BufferQueueCore.h:

1
2
3
4
5
6
// 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中:

1
2
3
4
5
6
7
8
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的角色:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       2)BufferSlot的定义位于frameworks/native/include/gui/BufferSlot.h中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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中:

1
2
3
4
5
6
sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
{
//创建一个GraphicBufferAlloc对象,并赋给强指针
sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
return gba;
}

       因为BufferQueueCore的mAllocator 类型为IGraphicBufferAlloc,继承于IInterface,所以又是跨进程调用创建。我们下面会分析到它的。

Producer

       BufferQueueProducer是生产者的实现,需要实现IGraphicBufferProducer接口,相关方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
* 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类图结构如下:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

Consumer

       同样,BufferQueueConsumer是消费者的实现,需要实现IGraphicBufferConsumer接口,相关方法如下:

1
2
3
4
5
6
7
8
9
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。

       当一块buffer就绪后,消费者就开始工作了,consumer对buffer的处理是被动的,它必须要等到一块buffer填充好才能工作,那consumer怎么知道一块buffer已经填充好了

       所以我们顺着Layer的onFirstRef函数,里面还有一个对于消费者的封装:SurfaceFlingerConsumer。为了方便,我再贴一遍Layer的onFirstRef函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的类图都贴出来:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       为了通知消费消费GraphicBuffer,这里提供了另外一个类ConsumerListener,位于frameworks/native/include/gui/IConsumerListener.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    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中:

1
2
3
4
5
6
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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中:

1
2
3
4
virtual status_t consumerConnect(const sp<IConsumerListener>& consumer,
bool controlledByApp)
{

return connect(consumer, controlledByApp);
}

       在头文件里定义了consumerConnect函数,调用connect函数,位于frameworks/native/libs/gui/BufferQueueConsumer.cpp中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);我们可以看看他的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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的生产者,消费者,管理者之间的关系。

       所以稍微总结一下BufferQueue机制,借助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这个过程。如果所示:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       或者这样表示这个过程:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

申请图形缓冲区

       前面看到,bufferqueuecore中mSlots数组管理缓冲区,最大容量是64,这个mSlots一开始静态分配了64个bufferslot大小的空间,但是其中的数据缓冲区不是一次性分配的,不然就太浪费空间了,所以缓冲区的空间分配是动态的,具体就是producer在dequeuebuffer时,如果没有获取到可用的缓冲区,那就要重新分配空间了。

       分配图形缓冲区,即GraphicBuffer,我们需要查看BufferQueueProducer的dequeuebuffer函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
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函数,我们看看这个函数的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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函数,我们看看这个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

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函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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的类图:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       上面说到mAllocator的类型为sp< IGraphicBufferAlloc >,它的创建GraphicBuffer的函数createGraphicBuffer也需要Bp/Bn 的IPC跨进程调用过程,序列化传递和反序列话取出这里用于IPC传递数据,我们可以在这里看看客户端和服务端的工作流程。
       我们先看看客户端Bp端,位于frameworks/native/libs/gui/IGraphicBufferAlloc.cpp中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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方法用于反序列化对象。

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       上面说到GraphicBuffer中的缓冲区是共享内存,使用共享内存需要传递共享内存的句柄fd,那么这个fd的传递就应该在GraphicBuffer的序列化/反序列化中,我们就来看看这个过程。

       这里我先回顾一下Android SurfaceFlinger 学习之路(一)—-Android图形显示之HAL层Gralloc模块实现的内容:

       图形缓冲区可以从系统帧缓冲区分配也可以从内存中分配,分配一个图形缓冲区后还需要将该图形缓冲区映射到分配该buffer的进程地址空间来,在Android系统中,图形缓冲区的管理由SurfaceFlinger服务来负责。在系统帧缓冲区中分配的图形缓冲区是在SurfaceFlinger服务中使用,而在内存中分配的图形缓冲区既可以在SurfaceFlinger服务中使用,也可以在其它的应用程序中使用。当其它的应用程序需要使用图形缓冲区的时候,它们就会请求SurfaceFlinger服务为它们分配并将SurfaceFlinger服务返回来的图形缓冲区映射到应用程序进程地址空间。在从内存中分配buffer时,已经将分配的buffer映射到了SurfaceFlinger服务进程地址空间,如果该buffer是应用程序请求SurfaceFlinger服务为它们分配的,那么还需要将SurfaceFlinger服务返回来的图形缓冲区映射到应用程序进程地址空间。

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       GraphicBuffer类从模板类Flattenable派生,这个派生类可以通过Parcel传递,通常派生类需要重载flatten和unflatten方法,用于对象的序列化和反序列化。

       1)将一个对象写入到Parcel中,需要使用flatten函数序列化该对象,我们先来看下flatten函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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模块实现。我们贴一下它的定义:

1
2
3
4
5
6
7
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函数进行反序列化过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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:

1
2
3
4
5
6
7
8
9
10
11
12
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函数:

1
2
3
4
5
6
7
8
9
10
11
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对象。如下图:

Android SurfaceFlinger 学习之路(七)----创建图形缓冲区GraphicBuffer

       这里我们创建GraphicBuffer流程就分析完了。

小结

       本节主要分析GraphicBuffer的创建过程,下一节我们分析对它的管理流程。