Android Surfaceflinger服务 ----- BufferQueue分析

丈夫志四海,万里犹比邻。这篇文章主要讲述Android Surfaceflinger服务 ----- BufferQueue分析相关的知识,希望能为你提供帮助。
生产者和消费者模型是编程中运用比较广泛的模型。在SurfaceFlinger图像绘制、合成、显示也用到了该模型。利用该模型合理的管理图像缓冲区buffer。让整个android系统从绘制到显示的过程有条不紊的进行。
BufferQueue图像缓冲管理者。其成员函数createBufferQueue创建一个缓冲区队列。

void BufferQueue::createBufferQueue(sp< IGraphicBufferProducer> * outProducer, sp< IGraphicBufferConsumer> * outConsumer, const sp< IGraphicBufferAlloc> & 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< BufferQueueCore> core(new BufferQueueCore(allocator)); LOG_ALWAYS_FATAL_IF(core == NULL, "BufferQueue: failed to create BufferQueueCore"); sp< IGraphicBufferProducer> producer(new BufferQueueProducer(core)); LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer"); sp< IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core)); LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer"); *outProducer = producer; *outConsumer = consumer; }

  • outProducer outConsumer为输出参数,输出对应的生产者接口,和消费者接口
  • allocator为输入参数,输入一个图像缓冲区内存分配接口,用于内存的申请
  • 首先通用allocator构造一个BufferQueueCore对象,然后在用该对象构造生产者对象(BufferQueueProducer)和消费者对象(BufferQueueConsumer)
class BufferQueueCore : public virtual RefBase {friend class BufferQueueProducer; friend class BufferQueueConsumer; public: // Used as a placeholder slot number when the value isn‘t pointing to an // existing buffer. enum { INVALID_BUFFER_SLOT = BufferItem::INVALID_BUFFER_SLOT }; // We reserve two slots in order to guarantee that the producer and // consumer can run asynchronously. enum { MAX_MAX_ACQUIRED_BUFFERS = BufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; // The default API number used to indicate that no producer is connected enum { NO_CONNECTED_API = 0 }; typedef Vector< BufferItem> Fifo; // BufferQueueCore manages a pool of gralloc memory slots to be used by // producers and consumers. allocator is used to allocate all the needed // gralloc buffers. BufferQueueCore(const sp< IGraphicBufferAlloc> & allocator = NULL); virtual ~BufferQueueCore(); private: // Dump our state in a string void dump(String8& result, const char* prefix) const; // getMinUndequeuedBufferCountLocked returns the minimum number of buffers // that must remain in a state other than DEQUEUED. The async parameter // tells whether we‘re in asynchronous mode. int getMinUndequeuedBufferCountLocked(bool async) const; // getMinMaxBufferCountLocked returns the minimum number of buffers allowed // given the current BufferQueue state. The async parameter tells whether // we‘re in asynchonous mode. int getMinMaxBufferCountLocked(bool async) const; // getMaxBufferCountLocked returns the maximum number of buffers that can be // allocated at once. This value depends on the following member variables: // //mDequeueBufferCannotBlock //mMaxAcquiredBufferCount //mDefaultMaxBufferCount //mOverrideMaxBufferCount //async parameter // // Any time one of these member variables is changed while a producer is // connected, mDequeueCondition must be broadcast. int getMaxBufferCountLocked(bool async) const; // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots // that will be used if the producer does not override the buffer slot // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The // initial default is 2. status_t setDefaultMaxBufferCountLocked(int count); // freeBufferLocked frees the GraphicBuffer and sync resources for the // given slot. void freeBufferLocked(int slot); // freeAllBuffersLocked frees the GraphicBuffer and sync resources for // all slots. void freeAllBuffersLocked(); // stillTracking returns true iff the buffer item is still being tracked // in one of the slots. bool stillTracking(const BufferItem* item) const; // waitWhileAllocatingLocked blocks until mIsAllocating is false. void waitWhileAllocatingLocked() const; // validateConsistencyLocked ensures that the free lists are in sync with // the information stored in mSlots void validateConsistencyLocked() const; // mAllocator is the connection to SurfaceFlinger that is used to allocate // new GraphicBuffer objects. sp< IGraphicBufferAlloc> mAllocator; // mMutex is the mutex used to prevent concurrent access to the member // variables of BufferQueueCore objects. It must be locked whenever any // member variable is accessed. mutable Mutex mMutex; // mIsAbandoned indicates that the BufferQueue will no longer be used to // consume image buffers pushed to it using the IGraphicBufferProducer // interface. It is initialized to false, and set to true in the // consumerDisconnect method. A BufferQueue that is abandoned will return // the NO_INIT error from all IGraphicBufferProducer methods capable of // returning an error. bool mIsAbandoned; // mConsumerControlledByApp indicates whether the connected consumer is // controlled by the application. bool mConsumerControlledByApp; // mConsumerName is a string used to identify the BufferQueue in log // messages. It is set by the IGraphicBufferConsumer::setConsumerName // method. String8 mConsumerName; // mConsumerListener is used to notify the connected consumer of // asynchronous events that it may wish to react to. It is initially // set to NULL and is written by consumerConnect and consumerDisconnect. sp< IConsumerListener> mConsumerListener; // mConsumerUsageBits contains flags that the consumer wants for // GraphicBuffers. uint32_t mConsumerUsageBits; // mConnectedApi indicates the producer API that is currently connected // to this BufferQueue. It defaults to NO_CONNECTED_API, and gets updated // by the connect and disconnect methods. int mConnectedApi; // mConnectedProducerToken is used to set a binder death notification on // the producer. sp< IProducerListener> mConnectedProducerListener; // 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; // mQueue is a FIFO of queued buffers used in synchronous mode. Fifo mQueue; // mFreeSlots contains all of the slots which are FREE and do not currently // have a buffer attached std::set< int> mFreeSlots; // mFreeBuffers contains all of the slots which are FREE and currently have // a buffer attached std::list< int> mFreeBuffers; // mOverrideMaxBufferCount is the limit on the number of buffers that will // be allocated at one time. This value is set by the producer by calling // setBufferCount. The default is 0, which means that the producer doesn‘t // care about the number of buffers in the pool. In that case, // mDefaultMaxBufferCount is used as the limit. int mOverrideMaxBufferCount; // mDequeueCondition is a condition variable used for dequeueBuffer in // synchronous mode. mutable Condition mDequeueCondition; // mUseAsyncBuffer indicates whether an extra buffer is used in async mode // to prevent dequeueBuffer from blocking. bool mUseAsyncBuffer; // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to // block. This flag is set during connect when both the producer and // consumer are controlled by the application. bool mDequeueBufferCannotBlock; // mDefaultBufferFormat can be set so it will override the buffer format // when it isn‘t specified in dequeueBuffer. PixelFormat mDefaultBufferFormat; // mDefaultWidth holds the default width of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. uint32_t mDefaultWidth; // mDefaultHeight holds the default height of allocated buffers. It is used // in dequeueBuffer if a width and height of 0 are specified. uint32_t mDefaultHeight; // mDefaultBufferDataSpace holds the default dataSpace of queued buffers. // It is used in queueBuffer if a dataspace of 0 (HAL_DATASPACE_UNKNOWN) // is specified. android_dataspace mDefaultBufferDataSpace; // mDefaultMaxBufferCount is the default limit on the number of buffers that // will be allocated at one time. This default limit is set by the consumer. // The limit (as opposed to the default limit) may be overriden by the // producer. int mDefaultMaxBufferCount; // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1, and can be changed by the consumer // via setMaxAcquiredBufferCount, but this may only be done while no // producer is connected to the BufferQueue. This value is used to derive // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. int mMaxAcquiredBufferCount; // mBufferHasBeenQueued is true once a buffer has been queued. It is reset // when something causes all buffers to be freed (e.g., changing the buffer // count). bool mBufferHasBeenQueued; // mFrameCounter is the free running counter, incremented on every // successful queueBuffer call and buffer allocation. uint64_t mFrameCounter; // mTransformHint is used to optimize for screen rotations. uint32_t mTransformHint; // mSidebandStream is a handle to the sideband buffer stream, if any sp< NativeHandle> mSidebandStream; // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which // releases mMutex while doing the allocation proper). Producers should not modify any of the // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to // false. bool mIsAllocating; // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating // becomes false. mutable Condition mIsAllocatingCondition; // mAllowAllocation determines whether dequeueBuffer is allowed to allocate // new buffers bool mAllowAllocation; // mBufferAge tracks the age of the contents of the most recently dequeued // buffer as the number of frames that have elapsed since it was last queued uint64_t mBufferAge; // mGenerationNumber stores the current generation number of the attached // producer. Any attempt to attach a buffer with a different generation // number will fail. uint32_t mGenerationNumber; }; // class BufferQueueCore

  • 这个类是一个比较关键的类
  • 成员变量mSlots管理着队列中各个缓冲区的状态
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; // mEglDisplay is the EGLDisplay used to create EGLSyncKHR objects. EGLDisplay mEglDisplay; // BufferState represents the different states in which a buffer slot // can be.All slots are initially FREE. enum BufferState { FREE = 0, DEQUEUED = 1, QUEUED = 2, ACQUIRED = 3 }; static const char* bufferStateName(BufferState state); // mBufferState is the current state of this buffer slot. BufferState mBufferState; // mRequestBufferCalled is used for validating that the producer did // call requestBuffer() when told to do so. Technically this is not // needed but useful for debugging and catching producer bugs. bool mRequestBufferCalled; // mFrameNumber is the number of the queued frame for this slot.This // is used to dequeue buffers in LRU order (useful because buffers // may be released before their release fence is signaled). uint64_t mFrameNumber; // mEglFence is the EGL sync object that must signal before the buffer // associated with this buffer slot may be dequeued. It is initialized // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a // new sync object in releaseBuffer.(This is deprecated in favor of // mFence, below.) EGLSyncKHR mEglFence; // mFence is a fence which will signal when work initiated by the // previous owner of the buffer is finished. When the buffer is FREE, // the fence indicates when the consumer has finished reading // from the buffer, or when the producer has finished writing if it // called cancelBuffer after queueing some writes. When the buffer is // QUEUED, it indicates when the producer has finished filling the // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been // passed to the consumer or producer along with ownership of the // buffer, and mFence is set to NO_FENCE. sp< Fence> mFence; // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; // Indicates whether this buffer needs to be cleaned up by the // consumer.This is set when a buffer in ACQUIRED state is freed. // It causes releaseBuffer to return STALE_BUFFER_SLOT. bool mNeedsCleanupOnRelease; // Indicates whether the buffer was attached on the consumer side. // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued // to prevent the producer from using a stale cached buffer. bool mAttachedByConsumer; };

  • BufferState定义了缓冲区的五种状态
  • 该结构体描述了每个缓冲区的状态与属性
BufferQueue的生产步骤(生产者接口BufferQueueProducer):
  1. dequeueBuffer
  2. requestBuffer
  3. queueBuffer
BufferQueue消费步骤(消费者接口BufferQueueConsumer):
  1. acquireBuffer
  2. releaseBuffer
生产者在缓冲区填充完成后,调用queueBuffer方法将缓冲区加入队列,并且通知消费者。
status_t BufferQueueProducer::queueBuffer(int slot, const QueueBufferInput & input, QueueBufferOutput *output) { .......frameAvailableListener = mCore-> mConsumerListener; ......frameAvailableListener-> onFrameAvailable(item); ...... }

  • 获取BufferQueueCore内的成员变量mConsumerListener(消费者监听接口)
  • 回调接口方法onFrameAvailable
【Android Surfaceflinger服务 ----- BufferQueue分析】那么问题又来了,mConsumerListener又是在哪里给设置的呢?
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; }mCore-> mConsumerListener = consumerListener; mCore-> mConsumerControlledByApp = controlledByApp; return NO_ERROR; }

  • BufferQueueConsumer::connect函数中会传入consumerListener接口指针,并设置给mCore-> mConsumerListener
  • 最终决定在哪消费就那BufferQueueConsumer接口调用connect函数时传入的接口对象类型

    推荐阅读