Skip to content

Process.start

追踪 ProcessList 参数准备、WebView/App/普通 Zygote 分流、Process.start backend 选择和 ProcessStartResult。

基于android-17.0.0_r1
AndroidProcessZygoteAMS源码阅读

Process.start ​

Process.start() 不是进程创建策略的 owner。真正的参数决策发生在 AMS 的 ProcessList:它根据 ProcessRecord、HostingRecord、ABI、存储隔离、compat changes、top-app 和 zygote policy 选择 WebView Zygote、App Zygote 或普通 Zygote。android.os.Process.start() 只选择 Java/native Zygote backend 并完整透传参数,返回 pid 和 wrapper 状态。

1. ProcessList入口 ​

源码文件:frameworks/base/services/core/java/com/android/server/am/ProcessList.java

java
final Process.ProcessStartResult startResult;
boolean regularZygote = false;
long forkTimeNs = SystemClock.uptimeNanos();
final boolean useDeliQueue =
        mPlatformCompat.getUseDeliQueue(app.info);

if (hostingRecord.usesWebviewZygote()) {
    startResult = startWebView(...);
} else if (hostingRecord.usesAppZygote()) {
    AppZygote appZygote =
            createAppZygoteForProcessIfNeeded(app);
    startResult = appZygote.startProcess(...);
} else {
    regularZygote = true;
    startResult = Process.start(...);
    app.mProcessGroupCreated = true;
}

HostingRecord 决定父 Zygote 类型;compat 决定 deli queue 等运行参数。只有普通 Zygote 路径直接调用 Process.start(),WebView/App Zygote 使用专用 wrapper。返回后,ProcessList 记录 fork timestamp 并继续创建/确认进程组。

2. 存储隔离参数 ​

java
StorageManagerInternal storage =
        LocalServices.getService(
                StorageManagerInternal.class);
if (needsStorageDataIsolation(storage, app)) {
    if (pkgDataInfoMap != null
            && storage.isFuseMounted(userId)) {
        bindMountAppStorageDirs = true;
    } else {
        app.setBindMountPending(true);
        bindMountAppStorageDirs = false;
    }
}

if (app.isolated) {
    pkgDataInfoMap = null;
    allowlistedAppDataInfoMap = null;
}

ProcessList 在 fork 前计算 CE/DE、Android/data/obb 和 FUSE mount 参数。isolated process 不应挂载自身 app data,因此清空 data info map。Fuse 未就绪时标记 bind mount pending,让后续解锁/恢复路径处理,而不是阻塞当前 fork。

3. 启动参数 ​

源码文件:frameworks/base/core/java/android/os/Process.java

java
public static ProcessStartResult start(
        String processClass, String niceName,
        int uid, int gid, int[] gids,
        int runtimeFlags, int mountExternal,
        int targetSdkVersion, String seInfo,
        String abi, String instructionSet,
        String appDataDir, String invokeWith,
        String packageName, int zygotePolicyFlags,
        boolean isTopApp,
        long[] disabledCompatChanges,
        long[] enabledCompatChanges,
        boolean useDeliQueue,
        Map<String, Pair<String, Long>> pkgDataInfoMap,
        Map<String, Pair<String, Long>> allowlistedDataInfoMap,
        boolean bindMountAppsData,
        boolean bindMountAppStorageDirs,
        boolean bindMountSystemOverrides,
        long startSeq, String[] zygoteArgs) {
    ...
}

参数分成五类:Java 入口与进程名;uid/gid/groups/SELinux;runtime/SDK/compat;ABI/instruction set;数据目录、mount、top-app、policy、start sequence。startSeq 用于 AMS 把返回 pid 与当前启动请求关联,防止旧进程启动结果覆盖新请求。

4. Backend选择 ​

java
boolean isNative = android.os.Flags.nativeFrameworkPrototype()
        && (zygotePolicyFlags
            & ZYGOTE_POLICY_FLAG_NATIVE_PROCESS) != 0;
IZygoteProcess process = isNative
        ? NATIVE_ZYGOTE_PROCESS
        : ZYGOTE_PROCESS;

return process.start(
        processClass, niceName, uid, gid, gids,
        runtimeFlags, mountExternal,
        targetSdkVersion, seInfo, abi,
        instructionSet, appDataDir, invokeWith,
        packageName, zygotePolicyFlags, isTopApp,
        disabledCompatChanges, enabledCompatChanges,
        useDeliQueue, pkgDataInfoMap,
        allowlistedDataInfoMap, bindMountAppsData,
        bindMountAppStorageDirs,
        bindMountSystemOverrides, startSeq, zygoteArgs);

native framework prototype flag 与 policy bit 同时满足时选择 NativeZygoteProcess,否则选择普通 ZygoteProcess。Backend 选择不改变参数 owner;两者都实现 IZygoteProcess.start() 契约。

5. 返回结果 ​

java
public static final class ProcessStartResult {
    public int pid;
    public boolean usingWrapper;
}

成功结果只包含新 pid 和是否使用 wrapper;失败不会返回负 pid,而是抛异常。ProcessList 随后根据路径处理进程组:普通 Zygote 已负责创建组,WebView/App Zygote 可能由 SystemServer 额外调用 Process.createProcessGroup()。

6. fork后的存储准备 ​

java
if (bindMountAppStorageDirs) {
    storageManagerInternal.prepareStorageDirs(
            userId, pkgDataInfoMap.keySet(),
            app.processName);
}
checkSlow(startTime,
        "startProcess: returned from zygote!");
return startResult;

prepareStorageDirs() 被刻意放在 Process.start() 返回后,源码注释说明目录未缓存时会拖慢进程启动;先触发 fork,再异步/后置准备目录,可以让 Zygote 使用缓存而不等待。该优化不改变 mount 决策,失败仍需在存储恢复路径处理。

7. 失败与状态边界 ​

  • 参数准备失败:ProcessList 尚未调用 Zygote;
  • ABI/parent Zygote 选择失败:ZygoteProcess 抛异常,ProcessStartResult 不存在;
  • native fork 失败:通过 Zygote 协议错误返回并转异常;
  • pid 返回后进程立即死亡:ProcessStartResult.pid 曾有效,但后续 attach 超时/死亡路径清理;
  • 进程组创建失败:WebView/App Zygote 路径可能在 fork 成功后再失败;
  • storage bind pending:进程可先启动,但数据挂载状态尚未完成。

8. 导航与后续 ​

bash
# AMS/ProcessList 参数准备、Zygote 分流和返回处理。
rg -n "usesWebviewZygote|usesAppZygote|Process.start\(|bindMountAppStorageDirs|ProcessStartResult|createProcessGroup" \
  frameworks/base/services/core/java/com/android/server/am/ProcessList.java

# Process.start 参数契约、backend 选择和返回类型。
rg -n "ProcessStartResult start\(|NATIVE_ZYGOTE_PROCESS|ZYGOTE_PROCESS|nativeFrameworkPrototype|class ProcessStartResult" \
  frameworks/base/core/java/android/os/Process.java

下一篇将展开 ZygoteProcess.start() 如何把这些字段编码成文本命令、选择 ABI socket、发送并读取 pid;不会重复 ProcessList 的策略计算。