//frameworks/native/libs/gui/BufferQueueProducer.cpp
classBufferQueueProducer:publicBnGraphicBufferProducer{status_tBufferQueueProducer::queueBuffer(intslot,constQueueBufferInput&input,QueueBufferOutput*output){ATRACE_CALL();ATRACE_BUFFER_INDEX(slot);int64_trequestedPresentTimestamp;boolisAutoTimestamp;android_dataspacedataSpace;Rectcrop(Rect::EMPTY_RECT);intscalingMode;uint32_ttransform;uint32_tstickyTransform;sp<Fence>acquireFence;boolgetFrameTimestamps=false;input.deflate(&requestedPresentTimestamp,&isAutoTimestamp,&dataSpace,&crop,&scalingMode,&transform,&acquireFence,&stickyTransform,&getFrameTimestamps);constRegion&surfaceDamage=input.getSurfaceDamage();constHdrMetadata&hdrMetadata=input.getHdrMetadata();if(acquireFence==nullptr){BQ_LOGE("queueBuffer: fence is NULL");returnBAD_VALUE;}autoacquireFenceTime=std::make_shared<FenceTime>(acquireFence);switch(scalingMode){caseNATIVE_WINDOW_SCALING_MODE_FREEZE:caseNATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:caseNATIVE_WINDOW_SCALING_MODE_SCALE_CROP:caseNATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:break;default:BQ_LOGE("queueBuffer: unknown scaling mode %d",scalingMode);returnBAD_VALUE;}sp<IConsumerListener>frameAvailableListener;sp<IConsumerListener>frameReplacedListener;intcallbackTicket=0;uint64_tcurrentFrameNumber=0;BufferItemitem;{// Autolock scope
std::lock_guard<std::mutex>lock(mCore->mMutex);if(mCore->mIsAbandoned){BQ_LOGE("queueBuffer: BufferQueue has been abandoned");returnNO_INIT;}if(mCore->mConnectedApi==BufferQueueCore::NO_CONNECTED_API){BQ_LOGE("queueBuffer: BufferQueue has no connected producer");returnNO_INIT;}if(slot<0||slot>=BufferQueueDefs::NUM_BUFFER_SLOTS){BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",slot,BufferQueueDefs::NUM_BUFFER_SLOTS);returnBAD_VALUE;}elseif(!mSlots[slot].mBufferState.isDequeued()){BQ_LOGE("queueBuffer: slot %d is not owned by the producer ""(state = %s)",slot,mSlots[slot].mBufferState.string());returnBAD_VALUE;}elseif(!mSlots[slot].mRequestBufferCalled){BQ_LOGE("queueBuffer: slot %d was queued without requesting ""a buffer",slot);returnBAD_VALUE;}// If shared buffer mode has just been enabled, cache the slot of the
// first buffer that is queued and mark it as the shared buffer.
if(mCore->mSharedBufferMode&&mCore->mSharedBufferSlot==BufferQueueCore::INVALID_BUFFER_SLOT){mCore->mSharedBufferSlot=slot;mSlots[slot].mBufferState.mShared=true;}BQ_LOGV("queueBuffer: slot=%d/%"PRIu64" time=%"PRIu64" dataSpace=%d"" validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s",slot,mCore->mFrameCounter+1,requestedPresentTimestamp,dataSpace,hdrMetadata.validTypes,crop.left,crop.top,crop.right,crop.bottom,transform,BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));constsp<GraphicBuffer>&graphicBuffer(mSlots[slot].mGraphicBuffer);RectbufferRect(graphicBuffer->getWidth(),graphicBuffer->getHeight());RectcroppedRect(Rect::EMPTY_RECT);crop.intersect(bufferRect,&croppedRect);if(croppedRect!=crop){BQ_LOGE("queueBuffer: crop rect is not contained within the ""buffer in slot %d",slot);returnBAD_VALUE;}// Override UNKNOWN dataspace with consumer default
if(dataSpace==HAL_DATASPACE_UNKNOWN){dataSpace=mCore->mDefaultBufferDataSpace;}mSlots[slot].mFence=acquireFence;mSlots[slot].mBufferState.queue();// Increment the frame counter and store a local version of it
// for use outside the lock on mCore->mMutex.
++mCore->mFrameCounter;currentFrameNumber=mCore->mFrameCounter;mSlots[slot].mFrameNumber=currentFrameNumber;item.mAcquireCalled=mSlots[slot].mAcquireCalled;item.mGraphicBuffer=mSlots[slot].mGraphicBuffer;item.mCrop=crop;item.mTransform=transform&~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);item.mTransformToDisplayInverse=(transform&NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY)!=0;item.mScalingMode=static_cast<uint32_t>(scalingMode);item.mTimestamp=requestedPresentTimestamp;item.mIsAutoTimestamp=isAutoTimestamp;item.mDataSpace=dataSpace;item.mHdrMetadata=hdrMetadata;item.mFrameNumber=currentFrameNumber;item.mSlot=slot;item.mFence=acquireFence;item.mFenceTime=acquireFenceTime;item.mIsDroppable=mCore->mAsyncMode||(mConsumerIsSurfaceFlinger&&mCore->mQueueBufferCanDrop)||(mCore->mLegacyBufferDrop&&mCore->mQueueBufferCanDrop)||(mCore->mSharedBufferMode&&mCore->mSharedBufferSlot==slot);item.mSurfaceDamage=surfaceDamage;item.mQueuedBuffer=true;item.mAutoRefresh=mCore->mSharedBufferMode&&mCore->mAutoRefresh;item.mApi=mCore->mConnectedApi;mStickyTransform=stickyTransform;// Cache the shared buffer data so that the BufferItem can be recreated.
if(mCore->mSharedBufferMode){mCore->mSharedBufferCache.crop=crop;mCore->mSharedBufferCache.transform=transform;mCore->mSharedBufferCache.scalingMode=static_cast<uint32_t>(scalingMode);mCore->mSharedBufferCache.dataspace=dataSpace;}output->bufferReplaced=false;if(mCore->mQueue.empty()){// When the queue is empty, we can ignore mDequeueBufferCannotBlock
// and simply queue this buffer
mCore->mQueue.push_back(item);frameAvailableListener=mCore->mConsumerListener;}else{// When the queue is not empty, we need to look at the last buffer
// in the queue to see if we need to replace it
constBufferItem&last=mCore->mQueue.itemAt(mCore->mQueue.size()-1);if(last.mIsDroppable){if(!last.mIsStale){mSlots[last.mSlot].mBufferState.freeQueued();// After leaving shared buffer mode, the shared buffer will
// still be around. Mark it as no longer shared if this
// operation causes it to be free.
if(!mCore->mSharedBufferMode&&mSlots[last.mSlot].mBufferState.isFree()){mSlots[last.mSlot].mBufferState.mShared=false;}// Don't put the shared buffer on the free list.
if(!mSlots[last.mSlot].mBufferState.isShared()){mCore->mActiveBuffers.erase(last.mSlot);mCore->mFreeBuffers.push_back(last.mSlot);output->bufferReplaced=true;}}// Make sure to merge the damage rect from the frame we're about
// to drop into the new frame's damage rect.
if(last.mSurfaceDamage.bounds()==Rect::INVALID_RECT||item.mSurfaceDamage.bounds()==Rect::INVALID_RECT){item.mSurfaceDamage=Region::INVALID_REGION;}else{item.mSurfaceDamage|=last.mSurfaceDamage;}// Overwrite the droppable buffer with the incoming one
mCore->mQueue.editItemAt(mCore->mQueue.size()-1)=item;frameReplacedListener=mCore->mConsumerListener;}else{mCore->mQueue.push_back(item);frameAvailableListener=mCore->mConsumerListener;}}mCore->mBufferHasBeenQueued=true;mCore->mDequeueCondition.notify_all();mCore->mLastQueuedSlot=slot;output->width=mCore->mDefaultWidth;output->height=mCore->mDefaultHeight;output->transformHint=mCore->mTransformHintInUse=mCore->mTransformHint;output->numPendingBuffers=static_cast<uint32_t>(mCore->mQueue.size());output->nextFrameNumber=mCore->mFrameCounter+1;ATRACE_INT(mCore->mConsumerName.string(),static_cast<int32_t>(mCore->mQueue.size()));#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());#endif
// Take a ticket for the callback functions
callbackTicket=mNextCallbackTicket++;VALIDATE_CONSISTENCY();}// Autolock scope
// It is okay not to clear the GraphicBuffer when the consumer is SurfaceFlinger because
// it is guaranteed that the BufferQueue is inside SurfaceFlinger's process and
// there will be no Binder call
if(!mConsumerIsSurfaceFlinger){item.mGraphicBuffer.clear();}// Update and get FrameEventHistory.
nsecs_tpostedTime=systemTime(SYSTEM_TIME_MONOTONIC);NewFrameEventsEntrynewFrameEventsEntry={currentFrameNumber,postedTime,requestedPresentTimestamp,std::move(acquireFenceTime)};addAndGetFrameTimestamps(&newFrameEventsEntry,getFrameTimestamps?&output->frameTimestamps:nullptr);// Call back without the main BufferQueue lock held, but with the callback
// lock held so we can ensure that callbacks occur in order
intconnectedApi;sp<Fence>lastQueuedFence;{// scope for the lock
std::unique_lock<std::mutex>lock(mCallbackMutex);while(callbackTicket!=mCurrentCallbackTicket){mCallbackCondition.wait(lock);}if(frameAvailableListener!=nullptr){frameAvailableListener->onFrameAvailable(item);//通知消费者去消费
}elseif(frameReplacedListener!=nullptr){frameReplacedListener->onFrameReplaced(item);}connectedApi=mCore->mConnectedApi;lastQueuedFence=std::move(mLastQueueBufferFence);mLastQueueBufferFence=std::move(acquireFence);mLastQueuedCrop=item.mCrop;mLastQueuedTransform=item.mTransform;++mCurrentCallbackTicket;mCallbackCondition.notify_all();}// Wait without lock held
if(connectedApi==NATIVE_WINDOW_API_EGL){// Waiting here allows for two full buffers to be queued but not a
// third. In the event that frames take varying time, this makes a
// small trade-off in favor of latency rather than throughput.
lastQueuedFence->waitForever("Throttling EGL Production");}returnNO_ERROR;}}
//frameworks/native/libs/gui/ConsumerBase.cpp
classConsumerBase:publicvirtualRefBase,protectedConsumerListener{voidConsumerBase::onFrameAvailable(constBufferItem&item){CB_LOGV("onFrameAvailable");sp<FrameAvailableListener>listener;{// scope for the lock
Mutex::Autolocklock(mFrameAvailableMutex);listener=mFrameAvailableListener.promote();}if(listener!=nullptr){CB_LOGV("actually calling onFrameAvailable");listener->onFrameAvailable(item);}}}