Android P 显示流程分析--- buffer的生产消费者模式

Posted Give.Me.Five

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android P 显示流程分析--- buffer的生产消费者模式相关的知识,希望对你有一定的参考价值。

上篇分析到了FramebufferSurface调用acquireBufferLocked()时,从mConsumer->acquireBuffer 消费者模式中获取的,这篇我们来分析下消费者模式。

  • StreamSpliter
  • ComsumerListener
  • BufferQueue
  • BufferQueueProducter
  • BufferQueueComsumer
  • BufferQueueCore
  • BufferLayer

每个BufferLayer在onFirstRef()也就是初始化时, 都会调用createBufferQueue,初始化一个BufferQueueProducer 和 一个BufferQueueConsumer,然后将这个BufferQueueProducer和surfaceFlinger 指针 封装到MonitoredProducer中。 将 BufferQueueConsumer 和 SurfaceFinger中的RenderEngine 一起封装到BufferLayerConsumer, 然后这个BufferLayerConsumer 设置监听setContentsChangedListener(this)。 同时在BufferLayer中实现了onFrameAvailable(*), 文件当contentChange时, 调用onFrameAvailable。

那我们来看看谁调用了onFrameAvailable()。grep一番之后,发现BufferQueueProducer的queueBuffer里,有调用onFrameAvailable。继续跟进,发现Surface的queueBuffer中有调用mGraphicBufferProducer->queueBuffer(slot, queueInput, queueOutput), 继续往下追,发现Surface的unlockAndPost()会调用,它会被dispatchUnlockAndPost调用。 还发现另外一个地方就是ANativeWindow中 ANativeWindow_dequeueBuffer里有调用。这个就与android里的window挂上构了。同时发现Surface里的attachAndQueueBuffer会queeuBuffer了。这个再向上追溯可以查到android.view.surface的通过jni调用attachAndQueueBuffer 以及 SurfaceControl 调用的screenShot。而Surface的attachAndQueueBuffer 更多的是被应用快照所调用。

因为现在BufferQueueProducer和BufferQueueConsumer里都有attachBuffer, detachBuffer 和 queueBuffer , dequeueBuffer 这四个函数, 那我们先来看看BufferQueueProducer是怎么获取attachBuffer里的Buffer的

那现在看到的attachBuffer的都不是普通的调用, 一个是Camera的视频流方式,另一种是ScreenShot的截图方式。这种不是我们想要找的,那我们去看看BufferQueueProducer的requestBuffer的流程。

status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) 
	......
    mSlots[slot].mRequestBufferCalled = true;
    *buf = mSlots[slot].mGraphicBuffer;
    return NO_ERROR;

就是把mSlots[slot]的mGraphicBuffer的地址赋值给参数buf。

int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) 
	...
	  int buf = -1;
    sp<Fence> fence;
    nsecs_t startTime = systemTime();

    FrameEventHistoryDelta frameTimestamps;
    //graphicBufferProducer 调用 dequeueBuffer,获取buf 和 fence
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
                                                            reqFormat, reqUsage, &mBufferAge,
                                                            enableFrameTimestamps ? &frameTimestamps
                                                                                  : nullptr);
    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
      if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) 
        if (mReportRemovedBuffers && (gbuf != nullptr)) 
            mRemovedBuffers.push_back(gbuf);
        //获取buf和gbuf
        result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
        if (result != NO_ERROR) 
            ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result);
            mGraphicBufferProducer->cancelBuffer(buf, fence);
            return result;
        
    

    if (fence->isValid()) 
        *fenceFd = fence->dup();
        if (*fenceFd == -1) 
            ALOGE("dequeueBuffer: error duping fence: %d", errno);
            // dup() should never fail; something is badly wrong. Soldier on
            // and hope for the best; the worst that should happen is some
            // visible corruption that lasts until the next frame.
        
     else 
        *fenceFd = -1;
    
	//gbuf 赋值给buffer
    *buffer = gbuf.get();
    

surface的dequeueBuffer中 会先调用mGraphicBufferProducer的dequeueBuffer , 然后再调用mGraphicBufferProducer里的requestBuffer,

Surface里的lock()函数会调用dequeueBuffer函数:
Surface里的dispatchlock() 又会调用lock(), perform() 通过NATIVE_WINDOW_LOCK 也会调用dispatchLock()。最后android_view_TextureView.cpp 中 android_view_textureView_lockCanvas() 通过native_window_lock() 又会调用到NATIVE_WINDOW_LOCK。很明显 android_view_textureView_lockCanvas() 就是TextureView 调用lockCanvas()调用到的。这样就明白了TextureView是如何画出来的了。

那我们来总结下GraphicBufferProducer的使用

那我们看看GraphicBufferConsumer是如何对应处理的
我们还是接之前的BufferLayer来分析,当应用快照时,会调用到BufferLayer的onFrameAvailable()

void BufferLayer::onFrameAvailable(const BufferItem& item) 
	...
		//BufferItem 加入到mQueueItem的队列中
        mQueueItems.push_back(item);
        android_atomic_inc(&mQueuedFrames);
        // Wake up any pending callbacks
        mLastFrameNumberReceived = item.mFrameNumber;
        mQueueItemCondition.broadcast();
		//surfaceFlinger 通知图层更新
        mFlinger->signalLayerUpdate();

void SurfaceFlinger::signalLayerUpdate() 
	//通知事件队列有可用的事件
    mEventQueue->invalidate();

void MessageQueue::invalidate() 
	//请示刷新
    mEvents->requestNextVsync();

void EventThread::Connection::requestNextVsync() 
    mEventThread->requestNextVsync(this);

void EventThread::requestNextVsync(const sp<EventThread::Connection>& connection) 
    std::lock_guard<std::mutex> lock(mMutex);

    if (mResyncWithRateLimitCallback) 
    	//异步刷新的回调,会调用到SurfaceFlinger-> resyncWithRateLimit()
        mResyncWithRateLimitCallback();
    

    if (connection->count < 0) 
        connection->count = 0;
        mCondition.notify_all();
    

void SurfaceFlinger::resyncWithRateLimit() 
    static constexpr nsecs_t kIgnoreDelay = ms2ns(500);

    // No explicit locking is needed here since EventThread holds a lock while calling this method
    static nsecs_t sLastResyncAttempted = 0;
    const nsecs_t now = systemTime();
    if (now - sLastResyncAttempted > kIgnoreDelay) 
    	//请求硬件fence刷新
        resyncToHardwareVsync(false);
    
    sLastResyncAttempted = now;

到这一步,将bufferItem 的加入到bufferQueue中,然后再那异步请求界面刷新,硬件刷新,同时请求VsyncEvent。

status_t EventThread::Connection::postEvent(const DisplayEventReceiver::Event& event) 
    ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
    return size < 0 ? status_t(size) : status_t(NO_ERROR);

ssize_t DisplayEventReceiver::sendEvents(gui::BitTube* dataChannel,
        Event const* events, size_t count)

    return gui::BitTube::sendObjects(dataChannel, events, count);

BitTube 是一个消息传输机制,类似PIPE管道。其实也就是一对socket, 一边是sendObject,用于发送事件,另一端也就对应着recvObject。在MessageQueue里的setEventThread里 有设置EventTube的事件监听回调,MessageQueue::cb_eventReceiver.

void MessageQueue::setEventThread(android::EventThread* eventThread) 
....
    mEvents->stealReceiveChannel(&mEventTube);
    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
                   this);

int MessageQueue::cb_eventReceiver(int fd, int events, void* data) 
    MessageQueue* queue = reinterpret_cast<MessageQueue*>(data);
    return queue->eventReceiver(fd, events);


int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) 
    ssize_t n;
    DisplayEventReceiver::Event buffer[8];
    //getEvents 就是通过EventTube 来调用recvObject来获取
    while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) 
        for (int i = 0; i < n; i++) 
        	//VSYNC事件的处理
            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) 
                mHandler->dispatchInvalidate();
                break;
            
        
    
    return 1;

ssize_t DisplayEventReceiver::getEvents(gui::BitTube* dataChannel,
        Event* events, size_t count)

    return gui::BitTube::recvObjects(dataChannel, events, count);

在这里就和前面的sendOjects 连接起来了。这里获取事件后,判断是DISPLAY_EVENT_VSYNC事件后,就做下一步处理:

void MessageQueue::Handler::dispatchInvalidate() 
    if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) 
        mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
    


void MessageQueue::Handler::handleMessage(const Message& message) 
    switch (message.what) 
        case INVALIDATE:
            android_atomic_and(~eventMaskInvalidate, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
        case REFRESH:
            android_atomic_and(~eventMaskRefresh, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
    

void SurfaceFlinger::onMessageReceived(int32_t what) 
    ATRACE_CALL();
    switch (what) 
        case MessageQueue::INVALIDATE: 
            bool frameMissed = !mHadClientComposition &&
                    mPreviousPresentFence != Fence::NO_FENCE &&
                    (mPreviousPresentFence->getSignalTime() ==
                            Fence::SIGNAL_TIME_PENDING);
            ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
            if (frameMissed) 
                mTimeStats.incrementMissedFrames();
                if (mPropagateBackpressure) 
                    signalLayerUpdate();
                    break;
                
            

            // Now that we're going to make it to the handleMessageTransaction()
            // call below it's safe to call updateVrFlinger(), which will
            // potentially trigger a display handoff.
            updateVrFlinger();

			//处理消息的传递
            bool refreshNeeded = handleMessageTransaction();
            //处理不可用的消息
            refreshNeeded |= handleMessageInvalidate();
            refreshNeeded |= mRepaintEverything;
            if (refreshNeeded) 
                // Signal a refresh if a transaction modified the window state,
                // a new buffer was latched, or if HWC has requested a full
                // repaint
                signalRefresh();
            
            break;
        
        case MessageQueue::REFRESH: 
             handleMessageRefresh();
            break;
        
    

bool SurfaceFlinger::handleMessageInvalidate() 
    ATRACE_CALL();
    //3buffer 轮换
    return handlePageFlip();

bool SurfaceFlinger::handlePageFlip()

    ALOGV("handlePageFlip");

    nsecs_t latchTime = systemTime();

    bool visibleRegions = false;
    bool frameQueued = false;
    bool newDataLatched = false;

    // Store the set of layers that need updates. This set must not change as
    // buffers are being latched, as this could result in a deadlock.
    // Example: Two producers share the same command stream and:
    // 1.) Layer 0 is latched
    // 2.) Layer 0 gets a new frame
    // 2.) Layer 1 gets a new frame
    // 3.) Layer 1 is latched.
    // Display is now waiting on Layer 1's frame, which is behind layer 0's
    // second frame. But layer 0's second frame could be waiting on display.
    //遍历Z轴的图层,然后加入到图层队列
    mDrawingState.traverseInZOrder([&](Layer* layer) 
        if (layer->hasQueuedFrame()) 
            frameQueued = true;
            if (layer->shouldPresentNow(mPrimaryDispSync)) 
                mLayersWithQueuedFrames.push_back(layer);
             else 
                layer->useEmptyDamage();
            
         else 
            layer->useEmptyDamage();
        
    );

    for (auto& layer : mLayersWithQueuedFrames) 
    	//绑定图层buffer的区域
        const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
        layer->useSurfaceDamage();
        invalidateLayerStack(layer, dirty);
        if (layer->isBufferLatched()) 
            newDataLatched = true;
        
    

    mVisibleRegionsDirty |= visibleRegions;

    // If we will need to wake up at some time in the future to deal with a
    // queued frame that shouldn't be displayed during this vsync period, wake
    // up during the next vsync period to check again.
    if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) 
        signalLayerUpdate();
    

    // Only continue with the refresh if there is actually new work to do
    return !mLayersWithQueuedFrames.empty() && newDataLatched;


Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) 
    ...
    // This boolean is used to make sure that SurfaceFlinger's shadow copy
    // of the buffer queue isn't modified when the buffer queue is returning
    // BufferItem's that weren't actually queued. This can happen in shared
    // buffer mode.
    bool queuedBuffer = false;
    LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                    getProducerStickyTransform() != 0, mName.string(),
                    mOverrideScalingMode, mFreezeGeometryUpdates);
    //BufferLayerConsumer 更新buffer图层                    
    status_t updateResult =
            mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
                                                    &mAutoRefresh, &queuedBuffer,
                                                    mLastFrameNumberReceived);
    if (updateResult == BufferQueue::PRESENT_LATER) 
        // Producer doesn't want buffer to be displayed yet.  Signal a
        // layer update so we check again at the next opportunity.
        mFlinger->signalLayerUpdate();
        return outDirtyRegion;
     else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) 
        // If the buffer has been rejected, remove it from the shadow queue
        // and return early
        if (queuedBuffer) 
            Mutex::Autolock lock(mQueueItemLock);
            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
            mQueueItems.removeAt(0);
            android_atomic_dec(&mQueuedFrames);
        
        return outDirtyRegion;
     else if (updateResult != NO_ERROR || mUpdateTexImageFailed) 
        //错误处理
        return outDirtyRegion;
    
	......
    // Decrement the queued-frames count.  Signal another event if we
    // have more frames pending.
    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) ||
        mAutoRefresh) 
        mFlinger->signalLayerUpdate();
    

	//更新当前帧
    // update the active buffer
    getBE().compositionInfo.mBuffer =
            mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
    // replicated in LayerBE until FE/BE is ready to be synchronized
    mActiveBuffer = getBE().compositionInfo.mBuffer;
    if (getBE().compositionInfo.mBuffer == nullptr) 
        // this can only happen if the very first buffer was rejected.
        return outDirtyRegion;
    

	//处理当前buffer的帧的数量
    mBufferLatched = true;
    mPreviousFrameNumber = mCurrentFrameNumber;
    mCurrentFrameNumber = mConsumer->getFrameNumber();
    
        Mutex::Autolock lock(mFrameEventHistoryMutex);
        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
    

    mRefreshPending = true;
    mFrameLatencyNeeded = true;
    ......
    ui::Dataspace dataSpace = mConsumer->getCurrentDataSpace();
    // treat modern dataspaces as legacy dataspaces whenever possible, until
    // we can trust the buffer producers
    switch (dataSpace) 
       ....
       //处理数据格式
    
    mCurrentDataSpace = dataSpace;
	Android P 显示流程---Display设备初始化过程分析

Android P 显示流程分析---EventThread MessageQueue 交互分析

Android P 显示流程分析---获取显示屏配置

Android P 显示流程分析--- buffer的生产消费者模式

Android P 显示流程分析--- buffer的生产消费者模式

Android画面显示流程分析