Android 图层状态变动史

470 阅读7分钟

Android 系统的显示依赖于 SurfaceFlinger 对图层的合成,想要获得正确的显示效果,SurfaceFlinger 必须要正确处理图层。然而,图层处于不断地变化中,所以 SurfaceFlinger 需要不断获取和更新图层的信息。如何表示图层的状态、如何获取图层的状态、如何消费图层的状态等问题就成了 SurfaceFlinger 合成流程中重要的一环。

一、图层状态的概念

图层状态 (Layer State) 指的是用于描述 android::Layer 状态的结构体 State,在最初的 AOSP 版本中,它的定义如下:

// [frameworks/native/libs/surfaceflinger/LayerBase.h]
struct State {
    uint32_t        w;
    uint32_t        h;
    uint32_t        z;
    uint8_t         alpha;
    uint8_t         flags;
    uint8_t         reserved[2];
    uint32_t        sequence;   // changes when visible regions can change
    uint32_t        tint;
    Transform       transform;
    Region          transparentRegion;
};

随着 Android 版本的变动,图层状态包含的信息也在频繁变动。但是,图层状态的核心功能始终保持一致——存储图层的状态信息,以供合成引擎使用。

二、图层状态的使用逻辑

从上一节的概念中可以看到。图层状态是定义在图层中的一个内部结构体,所以只在图层类中有图层状态类型的成员变量。仍以最初的 AOSP 版本为例:

class LayerBase
{
                // ...
                // these are protected by an external lock
                State           mCurrentState;
                State           mDrawingState;
                // ...
};

此时,在图层中定义有两个 State 变量:mCurrentStatemDrawingState

2.1 mCurrentState 的概念和用法

mCurrentState 表示图层当前的状态,对图层进行更新时直接操作的是 mCurrentState,使用前需要获得外部锁的保护。

更新 mCurrentState 的逻辑分两种。一种是在创建图层时,把构造函数中的参数赋值给 mCurrentState

void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
{
    // ...
    mCurrentState.z         = 0;
    mCurrentState.w         = w;
    mCurrentState.h         = h;
    mCurrentState.alpha     = 0xFF;
    mCurrentState.flags     = layerFlags;
    mCurrentState.sequence  = 0;
    mCurrentState.transform.set(0, 0);
    // ...
}

另一种是在各类 set 函数中,将传入的参数赋值给 mCurrentState 的对应变量。下面以 setPosition 函数为例:

bool LayerBase::setPosition(uint32_t x, uint32_t y)
{
    // ...
    mCurrentState.sequence++;
    mCurrentState.transform.set(x, y);
    // ...
}

2.2 mDrawingState 的概念和用法

mDrawingState 表示图层绘制时的状态,SurfaceFlinger 会把 mDrawingState 中的信息提交给合成引擎使用。图层不会直接更新 mDrawingState 中的变量,而是通过将 mCurrentState 赋值给 mDrawingState 实现间接更新。更新 mDrawingState 的逻辑也有两处,一处在 initStates 函数中,另一处在 commitTransaction 函数中。

void LayerBase::initStates(uint32_t w, uint32_t h, uint32_t flags)
{
    // ...
    // drawing state & current state are identical
    mDrawingState = mCurrentState;
}

void LayerBase::commitTransaction(bool skipSize)
{
    // ...
    mDrawingState = mCurrentState;
    // ...
}

2.3 SurfaceFlinger 如何使用图层状态

Step 1: SurfaceFlinger 在 createNormalSurfaceLocked 函数中创建 LayerLayer 初始化时也会初始化 mCurrentStatemDrawingState

LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked(
        Client* client, DisplayID display,
        int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
{
    // ...
    Layer* layer = new Layer(this, display, client, id);
    // ...
}

Step 2: SurfaceFlinger 在 setClientState 函数中根据客户端状态去更新对应图层的状态。仍以 setPosition 相关逻辑为例:

status_t SurfaceFlinger::setClientState(
        ClientID cid, int32_t count,
        const layer_state_t* state)
{
    // ...
    for (int i=0; i<count; i++) {
        const layer_state_t& s = state[i];
        LayerBaseClient* layer = getLayerUser_l(s.surface | cid);
        if (layer) {
            const uint32_t what = s.what;
            // ...
            if (what & ePositionChanged) {
                if (layer->setPosition(s.x, s.y))
                    flags |= eTraversalNeeded;
            }
            // ...
        }
    }
    // ...
}

Step 3: SurfaceFlinger 在 handleTransaction 函数中对每个图层调用 Layer::doTransaction,实现将 mCurrentState 赋值给 mDrawingState

// [frameworks/native/libs/surfaceflinger/SurfaceFlinger.cpp]
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
    // ...
    const bool layersNeedTransaction = transactionFlags & eTraversalNeeded;
    if (layersNeedTransaction) {
        for (size_t i=0; i<count; i++) {
            LayerBase* const layer = currentLayers[i];
            // ...
            const uint32_t flags = layer->doTransaction(0);
            // ...
        }
    }
    // ...
}
// [frameworks/native/libs/surfaceflinger/Layer.cpp]
void Layer::doTransaction(uint32_t flags)
{
    // ...
    return LayerBase::commitTransaction(flags);
}
// [frameworks/native/libs/surfaceflinger/LayerBase.cpp]
void LayerBase::commitTransaction(bool skipSize)
{
    // ...
    mDrawingState = mCurrentState;
    // ...
}

Step 4: 当 SurfaceFlinger 进行合成时,在 computeVisibleRegions 函数中会获取每个图层的 mDrawingState,并根据其中的状态信息计算可见区域。

void SurfaceFlinger::computeVisibleRegion(uint32_t transactionFlags)
{
    // ...
    while (i--) {
        LayerBase* const layer = currentLayers[i];
        layer->vilidateVisibility(planeTransform);

        // start with the whole surface at its current location
        const Layer::State& s = layer->drawingState();
        const Rect bounds(layer->visibleBounds());
        // ...
    }
    // ...
}

三、图层状态变动史

笔者是从 Android 11 才开始接触 Android,所以仅分析 Android 11 及之后的版本。

3.1 Android 11

相较于最初的 Android 版本, Android 11 的代码结构发生了很大的变化,但是图层状态的核心逻辑没有变动。在 Android 11 中,Google 已经移除了 LayerBase 类,相关逻辑被整合进了 Layer 中。

class Layer : public virtual RefBase, compositionengine::LayerFE {
    // ...
    // These are only accessed by the main thread or the tracing thread
    State mDrawingState;

    // these are protected by an external lock (mStateLock)
    State mCurrentState;
    // ...
};

整体逻辑和 2.3 节一致,只是具体的实现形式有差异。

3.2 Android 12

Android 12 移除了 mCurrentState因为保证只在主线程中写当前状态,所以可以直接写绘制状态,这样就避免了每一帧提交事务时要将 mCurrentState 拷贝给 mDrawingState。根据 Google 对弹跳球用例的 simpleperf 测试,每帧可以节省大约 8% 的 CPU。详细信息参阅:

3.3 Android 14

3.3.1 新的 SurfaceFlinger 前端

Android 14 引入了 SurfaceFlinger 前端 以实现客户端接口,这些接口描述了缓冲区如何在屏幕上进行合成。

  • 图层 (Layer) 用于定义缓冲区如何合成,每个缓存区与一个图层相关联
  • 事务 (Transaction) 包含了一个或一组图层原子变化的集合
  • 快照 (LayerSnapshot) 用于描述一组缓冲区应该如何合成,它包含合成引擎和渲染引擎需要的所有数据

SurfaceFlinger 前端消费事务,维持图层的生命状态,在每一帧时给合成引擎提供一个快照,以描述一组缓冲区应该如何进行合成。

3.3.2 SurfaceFlinger 前端的工作流程

SurfaceFlinger 前端包含如下五个流程:

  1. 队列化和过滤待提交的事务
  2. 处理图层的生命周期并更新每个图层服务侧的状态
  3. 生成和/或更新遍历树
  4. 生成一个 z 排序的快照列表
  5. 发送回调给客户端

3.3.3 SurfaceFlinger 前端的设计目的

根据 Google 的文档, SurfaceFlinger 前端旨在优化可预测性和性能,因为状态的生成处于 关键路径 上。简单的缓冲区更新应该处于 快速路径 上,并且速度应始终很快。当进入快速路径时,SurfaceFlinger 无需生成一棵完整的遍历树,而只需要对遍历树进行更新,从而减少了这一帧的 CPU 开销。为了实现这一功能,SurfaceFlinger 前端引入了 LayerLifecycleManagerLayerSnapshotBuilder 等数据结构协助判断:

bool LayerSnapshotBuilder::tryFastUpdate(const Args& args)
{
    if (args.forceUpdate != ForceUpdateFlags::None || args.displayChanges) {
        // force update requested, or we have display changes, so skip the fast path
        return false;
    }

    if (args.layerLifecycleManager.getGlobalChanges().get() == 0) {
        return true;
    }

    if (args.layerLifecycleManager.getGlobalChanges().get() != RequestedLayerState::Changes::Content) {
        // we have changes that require us to walk the hierarchy and update child layers
        // No fast path for you.
        return false;
    }

    // ...
    return true;
}

详细信息参阅:

3.4 Android 15

Android 15 正式启用了新的 SurfaceFlinger 前端。详细信息参阅 bdf565b2b74ef70f167e4855699ce947ffofa6d7 - platform/frameworks/native - Git at Google

3.5 Android 16

在即将到来的 Android 16上,Google 正式移除了遗留的 SF 标志、图层操作逻辑和图层状态等逻辑。详细信息参阅 dc83d4b7ba27a5096e19884b548eb05e432bc3f2 - platform/frameworks/native - Git at Google

四、总结

四、总结

从图层状态的变动史上可以看出 Google 这些年对 Android 性能的不断优化,包括减少拷贝调用、优化传递数据量、优化可预测性等。Google 对图层状态的改动和优化提供了一个范本,可以启发各位安卓开发者实际业务工作中的性能优化思路。

最后,从 Android 11 到 Android 16,完整的图层状态的变动史如下图所示:

History_Android_Layer_State.png