Skip to content

RuntimeInit.applicationInit

追踪 applicationInit 的退出策略、target SDK、compat callbacks、参数解析和 ActivityThread.main 反射入口。

基于android-17.0.0_r1
AndroidRuntimeInitActivityThread源码阅读

RuntimeInit.applicationInit ​

fork/specialization 完成后,子进程仍停留在 Zygote 的 Java 调用栈。RuntimeInit.applicationInit() 把进程切换到目标应用运行语义:禁用通用 shutdown hooks,设置 target SDK 和 compat changes,解析目标类与参数,反射检查 public static main(String[]),返回 MethodAndArgsCaller。对普通应用,目标类是 android.app.ActivityThread;其 main 再解析 start sequence/deli queue、准备 Looper并向 AMS attach。

1. 退出策略 ​

源码文件:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

java
protected static Runnable applicationInit(
        int targetSdkVersion,
        long[] disabledCompatChanges,
        long[] enabledCompatChanges,
        String[] argv,
        ClassLoader classLoader) {
    nativeSetExitWithoutCleanup(true);
    ...
}

Android 应用调用 System.exit() 时直接终止,不执行会关闭 Binder driver 的通用 runtime shutdown hooks。否则残留线程可能在进程尚未完全退出时访问已经关闭的 Binder 状态。这个开关在任何应用静态初始化前生效。

2. SDK与兼容状态 ​

java
VMRuntime.getRuntime().setTargetSdkVersion(
        targetSdkVersion);
VMRuntime.getRuntime().setDisabledCompatChanges(
        disabledCompatChanges);

if (disabledCompatChanges != null
        || enabledCompatChanges != null) {
    AppCompatCallbacks.install(
            disabledCompatChanges,
            enabledCompatChanges,
            null, false, targetSdkVersion);
}

target SDK 与 compat callbacks 在 Class.forName() 前安装,确保 ActivityThread 和应用类的静态初始化也按目标应用兼容规则运行。ActivityThread 后续 bind application 时会用更完整数据重新安装,但这里提供最早期基线。

3. Arguments解析 ​

java
static class Arguments {
    String startClass;
    String[] startArgs;

    private void parseArgs(String[] args) {
        int curArg = 0;
        for (; curArg < args.length; curArg++) {
            String arg = args[curArg];
            if (arg.equals("--")) {
                curArg++;
                break;
            } else if (!arg.startsWith("--")) {
                break;
            }
        }
        if (curArg == args.length) {
            throw new IllegalArgumentException(
                    "Missing classname argument to RuntimeInit!");
        }
        startClass = args[curArg++];
        startArgs = Arrays.copyOfRange(
                args, curArg, args.length);
    }
}

Arguments 跳过 RuntimeInit option 或显式 --,第一个非 option 是目标类,其余完整保留给 main。ZygoteProcess 把 processClass 之后的 start sequence/deli queue 放入这部分,因此参数顺序错误会改变消费者。

4. 静态main查找 ​

java
Class<?> cl = Class.forName(
        className, true, classLoader);
Method m = cl.getMethod(
        "main", new Class[] { String[].class });
int modifiers = m.getModifiers();
if (!(Modifier.isStatic(modifiers)
        && Modifier.isPublic(modifiers))) {
    throw new RuntimeException(
            "Main method is not public and static on "
            + className);
}
return new MethodAndArgsCaller(m, argv);

类加载强制初始化,并使用传入 classloader;普通应用通常传 null 使用 boot classpath 找 ActivityThread。类缺失、main 缺失、安全异常、修饰符错误分别转换为 RuntimeException,使子进程退出而不是带着不完整入口继续运行。

5. Runnable清栈 ​

java
static class MethodAndArgsCaller implements Runnable {
    @Override
    public void run() {
        try {
            mMethod.invoke(null,
                    new Object[] { mArgs });
        } catch (InvocationTargetException ex) {
            Throwable cause = ex.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            }
            if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new RuntimeException(ex);
        }
    }
}

返回 Runnable 让 ZygoteInit 在退出进程准备栈后再执行 main。反射包装异常被拆回原始 RuntimeException/Error,ActivityThread.main 的真实崩溃不会被隐藏成通用 InvocationTargetException。

6. 应用主线程参数 ​

源码文件:frameworks/base/core/java/android/app/ActivityThread.java

java
long startSeq = 0;
for (int i = args.length - 1; i >= 0; --i) {
    if (args[i].startsWith(PROC_START_SEQ_IDENT)) {
        startSeq = Long.parseLong(
                args[i].substring(
                    PROC_START_SEQ_IDENT.length()));
    } else if (args[i].startsWith(
            "--use-deliqueue=")) {
        boolean useDeliQueue = Boolean.parseBoolean(
                args[i].substring(
                    args[i].indexOf('=') + 1));
        MessageQueue.setUseDeliQueue(useDeliQueue);
    }
}

Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
Looper.loop();

startSeq 把子进程 attach 与 AMS 当前 ProcessRecord 启动请求关联;deli queue 必须在 prepareMainLooper() 创建 MessageQueue 前设置。ActivityThread 创建后调用 attach(false, startSeq) 通过 Binder 向 AMS 报到,最后进入主 Looper。

7. 失败边界 ​

  • 缺少 startClass:RuntimeInit 参数错误,ActivityThread 未加载;
  • class/main 签名错误:反射入口失败,进程退出;
  • compat 安装错误:可能在应用静态初始化前终止;
  • startSeq 错误:AMS 可能拒绝/清理过期 attach;
  • attachApplication 失败:ActivityThread 已创建但未绑定 AMS;
  • Looper 退出:ActivityThread 抛致命 RuntimeException。

8. 导航与后续 ​

bash
# RuntimeInit 的退出策略、兼容状态、参数和反射入口。
rg -n "applicationInit|nativeSetExitWithoutCleanup|setTargetSdkVersion|AppCompatCallbacks|class Arguments|findStaticMain|MethodAndArgsCaller" \
  frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

# ActivityThread 的参数消费、Looper 和 AMS attach。
rg -n "public static void main|PROC_START_SEQ_IDENT|use-deliqueue|prepareMainLooper|attach\(false|Looper.loop" \
  frameworks/base/core/java/android/app/ActivityThread.java

下一篇将深入 ActivityThread.main() 和 attach(false) 的应用主线程建立;不会重复 RuntimeInit 的反射入口。