WM 与 SF 的交互机制——Transaction

782 阅读7分钟

笔者计划写一些系列文章,分享和介绍 Android framework 中的重要模块。不同于大部分文章会去详细介绍具体流程细节,笔者可能不会聚焦到每个的 api 上,而希望从更宏观角度去分析 AOSP 的设计架构和思想。本文将会介绍 WM_surface 中非常基本的 Transaction 机制。

一、准备知识

在 Android 中,SurfaceControl 负责控制 WindowManager 侧相关的逻辑,而真正指向 Surface 中图像数据的指针则保存在 native 层的 Layer 中,由 SurfaceFlinger 管理。WM 对窗口的操作都发生在应用层,SF 没法直接收到,所以自然需要一个从 Java 层通信到 native 服务的传递机制,即 Transaction

二、初识 Transaction 类

我们首先来看 Transaction 类的定义:

// [frameworks/base/core/java/android/view/SurfaceControl.java]
/**
 * An atomic set of changes to a set of SurfaceControl.
 */
public static class Transaction implements Closeable, Parcelable {
    // ...
}

从注释可以看到 Transaction 类是对一组 SurfaceControl 的原子修改的集合,需要牢牢把握住这一点,后续的很多分析都建立在其基础上。另外我想提醒一点, Transaction 是 SurfaceControl 的一个 内部静态类,这意味着从设计上说,SurfaceControl 不会脱离 SurfaceControl 单独使用,否则 Google 为什么不单独起一个 Transaction.java(笑)?

第一节提到 Transaction 的作用是将 SurfaceControl 中的窗口变化信息传递给 native 层,Java 层中 Transaction 类的定义已经明显体现出变化这点,它又是如何传递给 native 层的呢?具体传递过程按下不表,不妨先看 native 层中对 Transaction 的定义:

// [frameworks/native/libs/gui/include/gui/SurfaceComposerClient.h]
class Transaction : public Parcelable {
    // ...
};

注意 native 层的 Transaction 类是 SurfaceComposerClient 的一个内部类,而不是 SurfaceControl(不妨思考一下为什么会有这样的差异)。和 Java 层的定义对比,我们可以发现 native 层的定义里多了很多成员变量,后续用到的时候可能会进一步展开分析。

三、 Transaction 的桥梁作用

如前文所述,Transaction 是 WM 与 SF 交互的途径,负责将 Java 层的窗口变化信息传递给 native 层,下面将具体分析 Transaction 如何发挥这一桥梁作用。

3.1 Transaction#setPosition 方法分析

我们以一个非常典型的 api SurfaceControl#Transaction#setPosition 为例进行分析:

/**
 * Sets the SurfaceControl to the specified position relative to the parent
 * SurfaceControl
 *
 * @param sc The SurfaceControl to change position
 * @param x the X position
 * @param y the Y position
 * @return this transaction
 */
@NonNull
public Transaction setPosition(@NonNull SurfaceControl sc, float x, float y) {
    checkPreconditions(sc);
    if (SurfaceControlRegistry.sCallStackDebuggingEnabled) {
        SurfaceControlRegistry.getProcessInstance().checkCallStackDebugging(
                "setPosition", this, sc, "x=" + x + " y=" + y);
    }
    nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
    return this;
}

可以看到,SurfaceControl#Transaction#setPosition 的入参包含一个(非空的)SurfaceControl 对象 sc,以及两个浮点坐标 xy。它的内部逻辑很简单,先检查前置条件,再调用 nativeSetPosition 方法往 native 层走。这个 nativeSetPosition 方法定义在 SurfaceControl 中,它会通过 JNI 调用到 android_view_SurfaceControl.cpp 中的 nativeSetPosition 函数(JNI 的具体调用流程本文不做分析,挖个坑以后可能会填):

// [frameworks/base/core/jni/android_view_SurfaceControl.cpp]
static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong transactionObj,
        jlong nativeObject, jfloat x, jfloat y) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);

    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
    transaction->setPosition(ctrl, x, y);
}

这里会进一步调用 native 层中的 SurfaceComposerClient::Transaction::setPosition 函数:

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
        const sp<SurfaceControl>& sc, float x, float y) {
    layer_state_t* s = getLayerState(sc);
    if (!s) {
        mStatus = BAD_INDEX;
        return *this;
    }
    s->what |= layer_state_t::ePositionChanged;
    s->x = x;
    s->y = y;

    registerSurfaceControlForCallback(sc);
    return *this;
}

SurfaceComposerClient::Transaction::setPosition 函数的逻辑也很简单,核心是从 SurfaceControl 拿一个 layer_state_t* 指针 s,再给 s->what 按位或上 layer_state_t::ePositionChanged,并分别更新 s->xs->y 的值。

注意这里出现了一个新的类型 layer_state_t,先来看它的定义:

// [frameworks/native/1ibs/gui/inc1ude/gui/Layerstate.h]
/*
 * Used to communicate layer information between SurfaceFlinger and its clients.
 */
struct layer_state_t {
    // ...
};

从注释中可以看到 layer_state_t 的作用是在 SurfaceFlinger 和其客户端之间传输 layer 信息。结合上面对 setPosition 分析,不难看出 xy 等成员变量就是保存在 layer_state_t 中的 layer 信息(亦即 SC 的变化),what 是一个 64 位 int 型变量,它起到一个标志位的作用,记录发生了哪些变化。

3.2 Transaction#apply 方法分析

上一节我们以 Transaction#setPosition 方法为例分析了 Transaction 如何表示 SC 的变化信息,但无论是 Java 层的 Transaction#setPosition,还是 native 层的 SurfaceComposerClient::Transaction::setPosition,都运行在应 用层,并没有传递给 SF,那么 Transction 又如何实现传递?这就需要用到 Transaction#apply

/**
 * Apply the transaction, clearing it's state, and making it usable
 * as a new transaction.
 */
public void apply() {
    apply(/*sync*/ false);
}

SurfaceControl#Transaction#apply 的逻辑很简单,仅有调用 SurfaceControl#apply 这一个操作。同样经过 JNI 调用,最终会走到 SurfaceComposerClient::Transaction::apply

status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay) {
    // ...
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
                            mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
                            mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId,
                            mMergedTransactionIds);
    // ...
}

SurfaceComposerClient::Transaction::apply 的关键在于会去获取一个 ISurfaceComposer 指针 sf,它指向的正是 SurfaceFlinger。通过这个 sf 指针,Transaction 实现了将应用侧的窗口变化传递到 SF 侧。

3.3 Transaction#merge 方法分析

上面两节分析了 Transaction#setPositionTransaction#apply 两个方法,厘清了 Transaction 如何从应用侧传递到 SF 侧。但如果 Transaction 只是单纯起到传递作用,直接在 SC 里去拿 SurfaceFlinger 指针不是更为简单直接,何必这样通过 Transaction 大费周章?其实这就涉及到了 Transaction 机制的设计思想,我们还有一个重要方法没有分析,即 Transaction#merge 方法,分析清楚了它才算基本厘清 Transaction 的原理。

/**
 * Merge the other transaction into this transaction, clearing the
 * other transaction as if it had been applied.
 *
 * @param other The transaction to merge in to this one.
 * @return This transaction.
 */
@NonNull
public Transaction merge(@NonNull Transaction other) {
    if (this == other) {
        return this;
    }
    mResizedSurfaces.putAll(other.mResizedSurfaces);
    other.mResizedSurfaces.clear();
    mReparentedSurfaces.putAll(other.mReparentedSurfaces);
    other.mReparentedSurfaces.clear();
    nativeMergeTransaction(mNativeObject, other.mNativeObject);
    return this;
}

从注释可以看到,Transaction#merge 方法可以将另一个没有执行的 Transaction 合并到这个 Transaction 上,并将另一个 Transaction 清除。这表明不是所有 Transaction 都会完整地走一遍 Java 层到 native 层的传递。事实上,绝大部分 Transaction 都会被合并。

接下来我们直接看 native 层对应的函数,SurfaceComposerClient::Transaction::merge

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
    // ...
    for (auto const& [handle, composerState] : other.mComposerStates) {
        if (mComposerStates.count(handle) == 0) {
            mComposerStates[handle] = composerState;
        } else {
            if (composerState.state.what & layer_state_t::eBufferChanged) {
                releaseBufferIfOverwriting(mComposerStates[handle].state);
            }
            mComposerStates[handle].state.merge(composerState.state);
        }
    }

    // ...
}

主要逻辑是将 other 中的信息合并到 this 上,核心是上面代码片段中的将 mComposerStates 中每个 handlelayer_state_t 进行合并。此外,SurfaceComposerClient::Transaction::merge 函数还将 mDisplayStatesmInputWindowCommands 等信息都进行了合并。

最后我们来看 layer_state_t::merge 的逻辑,还是以 setPosition 相关逻辑为例:

void layer_state_t::merge(const layer_state_t& other) {
    if (other.what & ePositionChanged) {
        what |= ePositionChanged;
        x = other.x;
        y = other.y;
    }
    // ...
}

代码非常简单,如果 other 中包含位置变换,就给 this 设置一个与 other 相同的变换。

四、为什么要设计 Transaction 机制?

Google 为什么要设计 Transaction 这样一套机制来实现 WM 到 SF 的交互?笔者认为至少有以下几个优点:

  1. 通过 Transaction 定义时的注释和对 Transaction#merge 方法的分析,笔者认为首要目的是减少 WM 到 SF 的 IPC 通信,这无疑会大幅提高性能。
  2. Transaction 机制还能保证不同类型变换的同步。设想一个非常基础的场景,打开桌面应用的动画,它同时包含多个变换,如缩放、平移、透明度等。如果两个(或更多)变化不能保证同步,则显示效果会突兀甚至错乱。Transaction 机制可以将不同变换合并到一起,通过集合的形式去更新,从而保证了同步性。
  3. Transaction 传递的不止有 layer_state_t 中定义的 SC 变化,还能传递 input 等变化,具备更灵活的扩展性。

术语表

TermsDefinition
SCSurfaceControl
SFSurfaceFlinger
WMWindowManager

本文中所有 AOSP 代码的版本均为 android15-qpr1-release。