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) {
....
//处理数据格以上是关于Android P 显示流程分析--- buffer的生产消费者模式的主要内容,如果未能解决你的问题,请参考以下文章
Android P 显示流程---Display设备初始化过程分析
Android P 显示流程分析---EventThread MessageQueue 交互分析
Android P 显示流程分析--- buffer的生产消费者模式