Skip to content

PackageDexOptimizer 逻辑

解释 Android 17 中 PackageDexOptimizer 职责下沉后的参数、快照、ART 调用与结果处理。

AndroidPMSDexOptART

PackageDexOptimizer 逻辑 ​

计划中的 PackageDexOptimizer 是旧架构名称。Android 17 的 PMS 源码中,安装 dexopt 的执行入口已经是 DexOptHelper,实际编译由 ART Service 的 ArtManagerLocal 完成;PMS 不再自己组装 dex2oat 命令,也没有一个可直接调用的 PackageDexOptimizer 类。

1. 架构迁移 ​

历史职责Android 17 owner
选择安装编译 reasonDexOptHelper / InstallScenarioHelper
组装 dexopt 参数DexOptHelper.getDexoptParamsByInstallRequest
遍历 dex 容器并编译ART Service
生成 oat/vdex/artART Service / artd
返回每文件结果DexoptResult
安装请求记录状态InstallRequest.onDexoptFinished

2. 安装入口 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java

java
CompletableFuture<Void> dexoptFuture =
        mPm.getDexOptHelper()
                .performDexoptIfNeededAsync(request);

安装包扫描完成后,InstallPackageHelper 把 InstallRequest 交给 DexOptHelper。返回 Future 是安装流程的同步点:是否等待它由调用方的安装编排决定,但 dexopt 本身在专用 executor 中执行。

3. 参数组装 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/DexOptHelper.java

java
private DexoptParams getDexoptParamsByInstallRequest(
        InstallRequest installRequest) {
    String compilationReason = mInstallScenarioHelper
            .getCompilationReasonForInstallScenario(
                    installRequest.getInstallScenario());
    var builder = new DexoptParams.Builder(compilationReason);
    if (installRequest.getInstallReason()
            == INSTALL_REASON_DEVICE_RESTORE
            || installRequest.getInstallReason()
            == INSTALL_REASON_DEVICE_SETUP) {
        builder.setPriorityClass(
                ArtFlags.PRIORITY_INTERACTIVE_FAST);
    }
    if (installRequest.getDexoptCompilerFilter() != null) {
        builder.setCompilerFilter(
                installRequest.getDexoptCompilerFilter());
    } else if (shouldSkipDexopt(installRequest)) {
        builder.setCompilerFilter(
                DexoptParams.COMPILER_FILTER_NOOP);
    }
    if ((installRequest.getInstallFlags()
            & PackageManager.INSTALL_IGNORE_DEXOPT_PROFILE) != 0) {
        builder.setFlags(
                ArtFlags.FLAG_IGNORE_PROFILE,
                ArtFlags.FLAG_IGNORE_PROFILE);
    }
    return builder.build();
}

PMS 只组装 reason、priority、compiler filter 和 profile flag。真正的 filter 调整、dex 文件遍历、ABI 选择和产物写入属于 ART Service。

4. 安装场景 reason ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/InstallScenarioHelper.java

java
public String getCompilationReasonForInstallScenario(
        int installScenario) {
    switch (installScenario) {
        case PackageManager.INSTALL_SCENARIO_DEFAULT:
            return ReasonMapping.REASON_INSTALL;
        case PackageManager.INSTALL_SCENARIO_FAST:
            return ReasonMapping.REASON_INSTALL_FAST;
        case PackageManager.INSTALL_SCENARIO_BULK:
            return shouldDowngradeBulkInstall()
                    ? ReasonMapping.REASON_INSTALL_BULK_DOWNGRADED
                    : ReasonMapping.REASON_INSTALL_BULK;
        case PackageManager.INSTALL_SCENARIO_BULK_SECONDARY:
            return shouldDowngradeBulkInstall()
                    ? ReasonMapping.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED
                    : ReasonMapping.REASON_INSTALL_BULK_SECONDARY;
        default:
            return ReasonMapping.REASON_INSTALL;
    }
}

reason 不是日志文本,而是 ART Service 的策略输入。bulk 场景还会根据电量/热状态选择 downgraded reason,影响 ART 后续编译强度。

5. ART 调用条件 ​

java
private static boolean shouldCallArtService(
        InstallRequest installRequest) {
    final boolean isApex =
            (installRequest.getScanFlags() & SCAN_AS_APEX) != 0;
    final boolean instantApp =
            (installRequest.getScanFlags()
                    & SCAN_AS_INSTANT_APP) != 0;
    final PackageSetting ps =
            installRequest.getScannedPackageSetting();
    final AndroidPackage pkg = ps.getPkg();
    final boolean performDexOptForRollback =
            !(installRequest.isRollback()
            && installRequest.getInstallSource()
                    .mInitiatingPackageName.equals("android"));
    return !instantApp && pkg != null
            && !isApex && performDexOptForRollback;
}

APEX、Instant App、没有已扫描 AndroidPackage、system 发起 rollback 不调用 ART Service。这个判断发生在异步任务提交前,返回 completed Future。

6. NOOP 边界 ​

java
private static boolean shouldSkipDexopt(
        InstallRequest installRequest) {
    PackageSetting ps =
            installRequest.getScannedPackageSetting();
    AndroidPackage pkg = ps.getPkg();
    boolean onIncremental =
            isIncrementalPath(ps.getPathString());
    return pkg == null || pkg.isDebuggable() || onIncremental;
}

debuggable 或 Incremental FS 只触发 NOOP compiler filter,不等于完全跳过 ART Service。这样 ART 仍能接收统一请求、记录结果,并由自身决定是否有可执行的优化动作。

7. Snapshot 交接 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/DexOptHelper.java

java
private DexoptResult dexoptPackageUsingArtService(
        InstallRequest installRequest) {
    final PackageSetting ps =
            installRequest.getScannedPackageSetting();
    PackageManagerLocal packageManagerLocal =
            LocalManagerRegistry.getManager(
                    PackageManagerLocal.class);
    try (PackageManagerLocal.FilteredSnapshot snapshot =
            PackageManagerLocalImpl.withFilteredSnapshot(
                    packageManagerLocal, ps)) {
        DexoptParams params =
                getDexoptParamsByInstallRequest(installRequest);
        return getArtManagerLocal().dexoptPackage(
                snapshot, ps.getPackageName(), params);
    }
}

PMS 以目标 PackageSetting 创建 filtered snapshot,再把包名和参数交给 ART。快照是跨模块契约:ART 可以读取编译所需包、代码路径和依赖,但不应直接访问 PMS 的可变全局状态。

8. 异步失败语义 ​

java
CompletableFuture.runAsync(() -> {
    try {
        Trace.traceBegin(
                TRACE_TAG_PACKAGE_MANAGER, "dexopt");
        DexoptResult result =
                dexoptPackageUsingArtService(installRequest);
        installRequest.onDexoptFinished(result);
    } finally {
        Trace.traceEnd(
                TRACE_TAG_PACKAGE_MANAGER);
    }
}, sDexoptExecutor).exceptionally(t -> {
    Slog.wtf(TAG,
            "Dexopt encountered a fatal error", t);
    return null;
});

正常编译失败应作为 DexoptResult.DEXOPT_FAILED 返回;只有未预期异常才进入 exceptionally。普通 APK 安装不因 dexopt 失败而失败,运行时可以解释执行,后续后台 dexopt 再尝试。

9. 结果结构 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/InstallRequest.java

java
public void onDexoptFinished(
        DexoptResult dexoptResult) {
    for (PackageDexoptResult packageResult :
            dexoptResult.getPackageDexoptResults()) {
        for (DexContainerFileDexoptResult fileResult :
                packageResult.getDexContainerFileDexoptResults()) {
            if (fileResult.getStatus()
                    == DexoptResult.DEXOPT_FAILED) {
                addWarning(
                        "Error occurred during dexopt when "
                                + "processing external profiles");
            }
        }
    }
    mDexoptStatus = dexoptResult.getFinalStatus();
}

InstallRequest 记录最终状态和 warning;它不重新执行编译,也不把单个 dex 容器失败改写为安装失败。调试时应继续查看每个 dex container 的实际 filter 和 status。

10. dump 与人工验证 ​

源码文件:frameworks/base/services/core/java/com/android/server/pm/DexOptHelper.java

java
public static void dumpDexoptState(
        @NonNull IndentingPrintWriter ipw,
        @NonNull PackageDataSnapshot computer,
        @Nullable String packageName) {
    try (PackageManagerLocal.FilteredSnapshot snapshot =
            getPackageManagerLocal()
                    .withUnownedFilteredSnapshot(computer)) {
        if (packageName != null) {
            getArtManagerLocal().dumpPackage(
                    ipw, snapshot, packageName);
        } else {
            getArtManagerLocal().dump(ipw, snapshot);
        }
    }
}

dumpsys package 的 dexopt 状态由 ART manager 输出。单包 dump 遇到并发删除可能抛 IllegalArgumentException;这反映的是快照与当前包集合的竞态,不代表编译器一定失败。

11. 排查清单 ​

  1. 先确认安装请求是否真正进入 performDexoptIfNeededAsync。
  2. shouldCallArtService=false 时检查 APEX、Instant App、pkg 为空和 system rollback。
  3. ART 被调用但无产物时检查 NOOP、Incremental FS、compiler filter 和 ART Service 状态。
  4. 查看 DexoptResult 的 package/dex container 明细,不只看安装结果码。
  5. 检查 filtered snapshot 是否包含目标包和代码路径。
  6. 用 dumpDexoptState 对照实际 reason、filter、status 和 artifacts。

12. 源码阅读路线 ​

  1. InstallPackageHelper:确认安装流程何时提交 dexopt。
  2. DexOptHelper.getDexoptParamsByInstallRequest:参数来源和优先级。
  3. shouldCallArtService/shouldSkipDexopt:调用与 NOOP 边界。
  4. dexoptPackageUsingArtService:filtered snapshot 和 ART 交接。
  5. InstallRequest.onDexoptFinished:状态、warning 和安装继续语义。
  6. ART Service 的 ArtManagerLocal.dexoptPackage:继续阅读实际编译执行。

Android 17 的 PackageDexOptimizer 职责已经拆分:PMS 负责调度和上下文,ART Service 负责优化决策与执行,InstallRequest 负责接收结果。理解这个边界,比继续寻找一个不存在的 PMS 内部 PackageDexOptimizer 类更接近当前源码。