[Android禅修之路] SurfaceFlinger合成总览

3,343 阅读9分钟

SurfaceFlinger合成总览

Android禅修之路

一 概述

SurfaceFlinger 所做的最主要的工作, 就是图元的合成和显示, 这所做的一切都是由系统的 Vsync 信号控制的, 关于 Vsync 信号本篇暂不研究, 本篇会对 SurfaceFlinger 接收到刷新的消息后的具体处理逻辑展开说明,这也是 SurfaceFlinger 的合成引擎所做的最主要的事情。

首先,还是从我们最熟悉的界面刷新开始说起。如果我们的手机想要刷新,会执行什么逻辑呢,因为刷新的触发逻辑和 Vsync 相关,所以我们这里直接看 SurfaceFlinger 接收到刷新消息之后的执行逻辑。

二 SurfaceFlinger的消息处理

首先,我们看 SurfaceFlinger 的消息处理函数 onMessageReceived,这里只有两种消息类型,所以逻辑也比较简单。

  • INVALIDATE:重绘消息
  • REFRESH:刷新消息
[frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
/**
 * SurfaceFlinger收到消息后的处理逻辑
 * 主要消息有INVALIDATE和REFRESH
 */
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
    ATRACE_CALL();
    switch (what) {
        case MessageQueue::INVALIDATE: {
            //处理INVALIDATE事件
            ...
            break;
        }
        case MessageQueue::REFRESH: {
            //处理REFRESH事件
            handleMessageRefresh();
            break;
        }
    }
}

这两个事件我们都比较熟悉,一个是 INVALIDATE 的重绘事件,一个是 REFRESH 的刷新事件,其中 INVALIDATE 事件最后还是会引发 REFRESH 事件,所以为了浏览整个流程, 我们先从 INVALIDATE 事件开始看起

2.1 SurfaceFlinger的INVALIDATE事件

//SurfaceFlinger INVALIDATE事件的逻辑
case MessageQueue::INVALIDATE: {
    //首先判断是否丢帧
    bool frameMissed = previousFrameMissed();
    //记录具体的丢帧原因
    bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
    bool gpuFrameMissed = mHadClientComposition && frameMissed;
    if (frameMissed) {
        mFrameMissedCount++;
        mTimeStats->incrementMissedFrames();
    }
    if (hwcFrameMissed) {
        mHwcFrameMissedCount++;
    }
    if (gpuFrameMissed) {
        mGpuFrameMissedCount++;
    }
    //丢帧的逻辑结束后,调用updateFpsBasedOnContent
    if (mUseSmart90ForVideo) {
        //这个是Fps视频检测功能
        mScheduler->updateFpsBasedOnContent();
    }
​
    if (performSetActiveConfig()) {
        break;
    }
    
    //如果丢帧,则不处理此次VSYNC
    if (frameMissed && mPropagateBackpressure) {
        if ((hwcFrameMissed && !gpuFrameMissed) ||
            mPropagateBackpressureClientComposition) {
            signalLayerUpdate();
            break;
        }
    }
​
    //调用Vr显示
    updateVrFlinger();
​
    //调用handleMessageTransaction
    bool refreshNeeded = handleMessageTransaction();
    //调用handleMessageInvalidate
    refreshNeeded |= handleMessageInvalidate();
​
    updateCursorAsync();
    updateInputFlinger();
​
    refreshNeeded |= mRepaintEverything;
    if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
        //如果事务修改了窗口状态、新缓冲区被锁存或 HWC 已请求完全重绘,则发出刷新信号
        signalRefresh();
    }
   break;
}

到此, 我们可以浏览整个 INVALIDATE 事件的流程, 发现最后它还是会执行刷新的逻辑, 只不过中执行刷新逻辑之前, 做了两件比较重要的事情

  • handleMessageTransaction
  • handleMessageInvalidate

三 刷新之前的工作

3.1 handleMessageTransaction

handleMessageTransaction 实际上就是调用了 handleTransaction 进行事务的处理。

bool SurfaceFlinger::handleMessageTransaction() {
    //peekTransactionFlags 函数是拿到 mTransactionFlags,这个标志会在接收到一些事务的时候发生改变
    uint32_t transactionFlags = peekTransactionFlags();
​
    bool flushedATransaction = flushTransactionQueues();
​
    bool runHandleTransaction = transactionFlags &&
            ((transactionFlags != eTransactionFlushNeeded) || flushedATransaction);
​
    // 先看是否有需要处理的事务,如果有的话就执行 handleTransaction
    // 如果没有调用 eTransactionFlushNeeded 修改 mTransactionFlags 的值
    if (runHandleTransaction) {
        handleTransaction(eTransactionMask);
    } else {
        getTransactionFlags(eTransactionFlushNeeded);
    }
​
    // 如果 mTransactionQueues 不为空,就需要需要处理事务,修改 mTransactionFlags 的值
    if (transactionFlushNeeded()) {
        setTransactionFlags(eTransactionFlushNeeded);
    }
​
    return runHandleTransaction;
}
​
bool SurfaceFlinger::transactionFlushNeeded() {
    return !mTransactionQueues.empty();
}

我们先看具体处理事务的逻辑。

3.1.1 handleTransaction

void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
    // 用 mDrawingState 创建一个副本 drawingState
    State drawingState(mDrawingState);
​
    Mutex::Autolock _l(mStateLock);
    mDebugInTransaction = systemTime();
​
    mVsyncModulator.onTransactionHandled();
    transactionFlags = getTransactionFlags(eTransactionMask);
    // 调用 handleTransactionLocked 这个是真正处理事务的函数
    handleTransactionLocked(transactionFlags);
​
    mDebugInTransaction = 0;
    invalidateHwcGeometry();
}
​

3.1.2 handleTransactionLocked

handleTransactionLocked 这段代码很长,但是核心逻辑就只有两块

  1. 图层是否发生了改变
  2. 显示设备是否发生了改变

针对以上两块逻辑,它对图层进行了遍历,判断了图层的属性是否变化,并判断了图层所属的显示设备是否在 mDisplays 集合中,最后处理了被移除的图层,然后提交了事务。

void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
    // 通知所有的图层有可用帧
    mCurrentState.traverseInZOrder([](Layer* layer) {
        layer->notifyAvailableFrames();
    });
​
    // 遍历子对象(如果需要,为每个子对象执行事务)
    if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
        mCurrentState.traverseInZOrder([&](Layer* layer) {
            // 获取图层的 TransactionFlags
            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
            if (!trFlags) return;
            // 调用图层的 doTransaction
            const uint32_t flags = layer->doTransaction(0);
            if (flags & Layer::eVisibleRegion)
                // 如果返回的值是需要计算可见区域,那么 mVisibleRegionsDirty 就设为 true
                mVisibleRegionsDirty = true;
​
            if (flags & Layer::eInputInfoChanged) {
                mInputInfoChanged = true;
            }
        });
        mTraversalNeededMainThread = false;
    }
​
    // 如果需要,执行显示自己的事务
    if (transactionFlags & eDisplayTransactionNeeded) {
        processDisplayChangesLocked();
        processDisplayHotplugEventsLocked();
    }
​
    // 如果显示设备发生了改变或者有显示设备的事务需要处理
    if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) {
        sp<const DisplayDevice> hintDisplay;
        uint32_t currentlayerStack = 0;
        bool first = true;
        mCurrentState.traverseInZOrder([&](Layer* layer) {
            // layerStack 是一个 uint32_t 的值,它表示当前的图层关联的图层堆栈
            uint32_t layerStack = layer->getLayerStack();
            if (first || currentlayerStack != layerStack) {
                // 如果是第一个图层,或者是遍历时 Layer 的图层堆栈并不相同
                currentlayerStack = layerStack;
                // 确定此layerstack是否已镜像(多个显示)。如果是镜像就选择默认显示;如果不是镜像就选择唯一显示。
                hintDisplay = nullptr;
                for (const auto& [token, display] : mDisplays) {
                    if (display->getCompositionDisplay()
                                ->belongsInOutput(layer->getLayerStack(),
                                                  layer->getPrimaryDisplayOnly())) {
                        if (hintDisplay) {
                            hintDisplay = nullptr;
                            break;
                        } else {
                            hintDisplay = display;
                        }
                    }
                }
            }
​
            if (!hintDisplay) {
                // 这里是一段修复bug的代码
                // 当该层使用在任何显示器上都不可见的 layerStack 时,可能为空。可能在屏幕关闭/打开时发生
                hintDisplay = getDefaultDisplayDeviceLocked();
            }
            if (hintDisplay) {
                layer->updateTransformHint(hintDisplay);
            }
​
            first = false;
        });
    }
​
    // 如果需要,执行我们自己的交易
    if (mLayersAdded) {
        mLayersAdded = false;
        mVisibleRegionsDirty = true;
    }
​
    // 对于某些图层已被删除,需要更新它们所在的可见区域
    if (mLayersRemoved) {
        mLayersRemoved = false;
        mVisibleRegionsDirty = true;
        mDrawingState.traverseInZOrder([&](Layer* layer) {
            // 属于删除图层
            if (mLayersPendingRemoval.indexOf(layer) >= 0) {
                // 删除不可见的图层
                Region visibleReg;
                visibleReg.set(layer->getScreenBounds());
                invalidateLayerStack(layer, visibleReg);
            }
        });
    }
​
    // 提交事务
    commitInputWindowCommands();
    commitTransaction();
}

3.1.3 提交事务

提交事务有两个函数,commitInputWindowCommands 和 commitTransaction

commitInputWindowCommands
[frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::commitInputWindowCommands() {
    mInputWindowCommands = mPendingInputWindowCommands;
    mPendingInputWindowCommands.clear();
}

commitInputWindowCommands 这个函数就是做了一个指令的赋值。

commitTransaction
void SurfaceFlinger::commitTransaction()
{
    // 先移除待移除的图层
    if (!mLayersPendingRemoval.isEmpty()) {
        // 通知删除的图层不要进行绘制
        for (const auto& l : mLayersPendingRemoval) {
            recordBufferingStats(l->getName().string(),
                    l->getOccupancyHistory(true));
​
            // 确保释放设置为在任何显示设备上的所有缓冲区
            if (l->isRemovedFromCurrentState()) {
                latchAndReleaseBuffer(l);
            }
            // 如果该层已被删除且没有父层,则在屏幕上遍历层时将无法访问该层。
            // 将图层添加到 offscreenLayers 集合中,以确保可以将其当前状态复制到绘图状态。
            if (!l->getParent()) {
                mOffscreenLayers.emplace(l.get());
            }
        }
        mLayersPendingRemoval.clear();
    }
    // 如果此事务是窗口动画的一部分,那么我们合成的下一帧也应视为动画
    mAnimCompositionPending = mAnimTransactionPending;
​
    withTracingLock([&]() {
        // 切换显示状态,将当前的状态赋值给绘图的状态
        mDrawingState = mCurrentState;
        // 清楚改变的标记
        mCurrentState.colorMatrixChanged = false;
​
        mDrawingState.traverseInZOrder([&](Layer* layer) {
            layer->commitChildList();
​
            // 如果在遍历 mDrawingState 时可以到达该层,则该层不再是屏幕外的。从offscreenLayer集合中删除该层
            if (mOffscreenLayers.count(layer)) {
                mOffscreenLayers.erase(layer);
            }
        });
​
        commitOffscreenLayers();
    });
​
    mTransactionPending = false;
    mAnimTransactionPending = false;
    mTransactionCV.broadcast();
}

3.2 handleMessageInvalidate

bool SurfaceFlinger::handleMessageInvalidate() {
    //调用 handlePageFlip,返回是否需要刷新
    bool refreshNeeded = handlePageFlip();
​
    if (mVisibleRegionsDirty) {
        //计算 Layer 的边界
        computeLayerBounds();
    }
​
    // 在 handlePageFlip 中加进去的图层
    for (auto& layer : mLayersPendingRefresh) {
        Region visibleReg;
        visibleReg.set(layer->getScreenBounds());
        invalidateLayerStack(layer, visibleReg);
    }
    mLayersPendingRefresh.clear();
    return refreshNeeded;
}

3.2.1 computeLayerBounds

void SurfaceFlinger::computeLayerBounds() {
    for (const auto& pair : mDisplays) {
        const auto& displayDevice = pair.second;
        const auto display = displayDevice->getCompositionDisplay();
        for (const auto& layer : mDrawingState.layersSortedByZ) {
            if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
                continue;
            }
            layer->computeBounds(displayDevice->getViewport().toFloatRect(), ui::Transform());
        }
    }
}

这里调用了 Layer 的 computeBounds 来计算它的边界。

3.2.2 handlePageFlip

handlePageFlip 的字面意思就是翻页,它实际上就是看看新的一页有哪些数据需要处理(测量,重绘等等),并返回一个布尔变量来决定后续是否需要刷新。

// 从各 Layer 的 BufferQueue 拿到最新的缓冲数据,并根据内容更新脏区域
bool SurfaceFlinger::handlePageFlip()
{
    nsecs_t latchTime = systemTime();
    bool visibleRegions = false;
    bool frameQueued = false;
    bool newDataLatched = false;
​
    // 存储需要更新的Layer,当缓冲区被锁存时,这个集合不能改变,因为这可能导致死锁。
    mDrawingState.traverseInZOrder([&](Layer* layer) {
        // 返回 layer 是否有准备好的帧
        if (layer->hasReadyFrame()) {
            frameQueued = true;
            nsecs_t expectedPresentTime;
            expectedPresentTime = mScheduler->expectedPresentTime();
            // 如果有了准备好的帧,还需要判断这个帧是否需要当前显示,
            // Layer 会根据当前帧的时间还有自己期望的显示时间来判断自己当前是否需要显示准备好的帧
            if (layer->shouldPresentNow(expectedPresentTime)) {
                // 如果需要显示,就把这个图层添加进队列中
                mLayersWithQueuedFrames.push_back(layer);
            } else {
                // 如果没有准备好,或者不需要当前显示,就不做显示逻辑
                layer->useEmptyDamage();
            }
        } else {
            layer->useEmptyDamage();
        }
    });
​
    // 如果需要显示的队列不为空
    if (!mLayersWithQueuedFrames.empty()) {
        Mutex::Autolock lock(mStateLock);
        for (auto& layer : mLayersWithQueuedFrames) {
            // 每次重新绘制屏幕时调用 latchBuffer,并返回是否需要重新计算可见区域
            //(这是一个相当繁重的操作,因此只有在需要时才应设置)。通常,这用于确定 Surface 的内容或大小是否已更改
            if (layer->latchBuffer(visibleRegions, latchTime)) {
                // 如果需要重新计算,就将图层添加进 mLayersPendingRefresh 集合中
                mLayersPendingRefresh.push_back(layer);
            }
            layer->useSurfaceDamage();
            if (layer->isBufferLatched()) {
                newDataLatched = true;
            }
        }
    }
​
    mVisibleRegionsDirty |= visibleRegions;
    //如果我们需要在未来某个时间唤醒以处理不应在此 vsync 周期内显示的排队帧,请在下一个 vsync 周期唤醒以再次检查。 
    if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
        // 传递图层的重绘事件
        signalLayerUpdate();
    }
​
    // 如果是 BOOTLOADER,就启动 Boot 动画
    if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
        mBootStage = BootStage::BOOTANIMATION;
    }
​
    // 仅在确实有新工作要做时才需要继续刷新
    return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
​
void SurfaceFlinger::signalLayerUpdate() {
    mScheduler->resetIdleTimer();
    mEventQueue->invalidate();
}

四 handleMessageRefresh

最后终于到了 handleMessageRefresh,就是 SurfaceFlinger 做的正式的刷新工作了。虽然说是刷新,但是它依然分了几个阶段进行

关于这三个部分,之后再详细说明,这里就先简单看一下代码。

void SurfaceFlinger::handleMessageRefresh() {
    mRefreshPending = false;
​
    const bool repaintEverything = mRepaintEverything.exchange(false);
    // 合成前预处理
    preComposition();
    // 重建Layer集合,并计算每个Layer的可见区域的脏数据
    rebuildLayerStacks();
    // 计算工作区间
    calculateWorkingSet();
  
    
    for (const auto& [token, display] : mDisplays) {
        beginFrame(display);
        prepareFrame(display);
        doDebugFlashRegions(display, repaintEverything);
        // 合成中的工作
        doComposition(display, repaintEverything);
    }
​
    // 合成后的工作
    logLayerStats();
​
    postFrame();
    postComposition();
​
    mHadClientComposition = false;
    mHadDeviceComposition = false;
    for (const auto& [token, displayDevice] : mDisplays) {
        auto display = displayDevice->getCompositionDisplay();
        const auto displayId = display->getId();
        mHadClientComposition =
                mHadClientComposition || getHwComposer().hasClientComposition(displayId);
        mHadDeviceComposition =
                mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
    }
​
    mVsyncModulator.onRefreshed(mHadClientComposition);
    mLayersWithQueuedFrames.clear();
}

五 总结

SurfaceFlinger 的合成工作极其复杂,本篇本来只是打算简单的介绍一下 SurfaceFlinger 的合成流程,没有想到就介绍几个合成前的函数,篇幅就已经不少了,之后 SurfaceFlinger 的具体合成过程涉及到的东西只会更多。

最后还是做一个简单的总结

  1. SurfaceFlinger 会通过它的消息回调来接收两种事务,它们分别是 INVALIDATE 和 REFRESH,而 INVALIDATE 事件最后还是会走到 REFRESH 事件的逻辑。
  2. 在 INVALIDATE 中 SurfaceFlinger 会遍历所有的图层,判断哪些图层需要重新测量,哪些图层需要刷新,并判断图层的改变和显示设备的改变,最后调用 handlePageFlip 来决定是否需要刷新
  3. handleMessageRefresh 是 SurfaceFlinger 的刷新逻辑