DEX 布局优化和启动配置文件

本文档介绍了在构建 Android 应用时可以通过哪些步骤启用使用启动配置文件进行 DEX 布局优化的功能。

要求

如果想使用 DEX 布局优化及相关功能,您需要安装 Jetpack Macrobenchmarks 版本 1.2.0-alpha14 或更高版本,以及下表中所列的 Android Gradle 插件版本:

技术 最低 Android Gradle 插件版本
基准配置文件 7.4.1
DEX 布局优化 8.2.0-alpha09
改进了配置文件编译 8.2.0-alpha09

目前不支持 Bazel 等第三方构建系统。

启动配置文件

启动配置文件与基准配置文件类似。此类配置文件描述了对应用启动至关重要的类和方法,这些类和方法必须先做好加载准备。启动配置文件也使用与基准配置文件相同的人类可读格式 (HRF)

启动配置文件和基准配置文件之间的一个主要区别是,基准配置文件包含对应用启动以外的优化至关重要的类和方法,例如减少动画期间或应用启动以外的关键用户历程 (CUJ) 期间的卡顿。

启动配置文件和基准配置文件之间的另一个主要区别是,启动配置文件无法由库提供,也不受 Android Gradle 插件合并的约束。这是因为库不一定充分了解应用启动的关键类和方法有哪些。这些类和方法最好衍生自 Jetpack Macrobenchmark,并将 BaselineProfileRule 与专门针对应用启动的 CUJ(例如 collect)结合使用。

请参阅下表,快速了解基准配置文件与启动配置文件之间的主要区别。

配置文件类型 按 build 受合并约束
基准配置文件
启动配置文件

启动配置文件存储在 src/<variantName>/main/baselineProfiles/startup-prof.txt 中。

DEX 布局优化

这项优化能够改进启动期间所用代码的位置,缩短启动时间,从而减少应用启动期间发生的主要页面故障的数量。

为此,需要将启动期间要执行的所有代码添加到主要 classes.dex 文件中,同时将所有非启动代码从主要 classes.dex 文件中移除。

图 1. DEX 布局优化的代码位置改进。

使用 DEX 布局优化

本部分介绍了如何使用 DEX 布局优化。

构建启动配置文件

首先,您需要构建启动配置文件。

项目设置

在前面的示例中,插桩测试驱动了一个软件包名称为 com.example.appapp 模块。

当您使用 Jetpack Macrobenchmark 生成启动配置文件规则时,您会在 build 中定义新的基准变体。基准变体与发布变体相同,不过您会关闭缩减功能。

以下代码摘自应用模块的 build.gradle 文件。

Kotlin

buildTypes {
        ...
        create("benchmark") {
            initWith(buildTypes.getByName("release")
            isMinifyEnabled = false
            signingConfig = signingConfigs.getByName("debug")
            matchingFallbacks += "release"
        }
}

Groovy

buildTypes {
        ...
        benchmark {
            initWith buildTypes.release
            minifyEnabled false
            signingConfig signingConfigs.debug
            matchingFallbacks = ['release']
        }
}

生成启动规则

Kotlin

@RunWith(AndroidJUnit4::class)
class StartupProfileGenerator {
    @get:Rule
    val baselineProfileRule = BaselineProfileRule()

    @Test
    fun startup() =
        baselineProfileRule.collect(
            packageName = "com.example.app",
            includeInStartupProfile = true
    ) {
            // This scenario just starts the activity and waits for it to draw
            // the first frame. If you have animations or async content in your
            // startup, wait for them with UiAutomator.
            startActivityAndWait()
        }
}

Java

@RunWith(AndroidJUnit4.class)
public class StartupProfileGenerator {
    @Rule
    BaselineProfileRule baselineProfileRule = new BaselineProfileRule();

    @Test
    public void startup() {
        baselineProfileRule.collect(
            "com.example.app",
            /* includeInStartupProfile = */ true,
            (scope -> {
                // This scenario just starts the activity and waits for it to
                // draw the first frame. If you have animations or async content
                // in your startup, wait for them with UiAutomator.
                scope.startActivityAndWait();
                return null;
            }
        ));
    }
}

输出

运行测试将会生成如下所示的文件:

HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;

将输出文件的内容复制到 src/main/baselineProfiles/startup-prof.txt

启用 DEX 布局优化

实验性属性 android.experimental.r8.dex-startup-optimization 支持 DEX 布局优化。

Kotlin

android {
    // ...
    experimentalProperties["android.experimental.r8.dex-startup-optimization"] = true
}

Groovy

android {
    // ...
    experimentalProperties["android.experimental.r8.dex-startup-optimization"] = true
}

如需构建具有 DEX 布局优化功能的 APK,您可以使用以下代码:

./gradlew :app:assembleRelease