Skip to content

Application.onCreate

追踪 LoadedApk 创建 Application、attachBaseContext、Provider 先行、Instrumentation 回调和 AMS 完成通知。

基于android-17.0.0_r1
AndroidApplicationLoadedApkInstrumentation源码阅读

Application.onCreate ​

Application.onCreate() 不是应用进程的第一段应用代码。LoadedApk.makeApplicationInner() 先确定当前 process 对应的 Application 类、建立 classloader 和 ContextImpl,通过 Instrumentation/AppComponentFactory 实例化对象并调用 attachBaseContext();ActivityThread 随后先安装 ContentProvider,再执行 Instrumentation.onCreate,最后才调用 Application.onCreate()。

1. 类选择 ​

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

java
String processName = Process.myProcessName();
String appClass = mApplicationInfo
        .getCustomApplicationClassNameForProcess(
                processName);
if (forceDefaultAppClass || appClass == null) {
    appClass = "android.app.Application";
}

Android 17 支持按 process 选择自定义 Application 类;restricted backup 等路径可以强制基础 android.app.Application。选择发生在 classloader 创建前,错误类名会在实例化阶段暴露。

2. LoadedApk缓存 ​

java
if (mApplication != null) {
    return mApplication;
}

synchronized (sApplications) {
    Application cached =
            sApplications.get(mPackageName);
    if (cached != null && !allowDuplicateInstances) {
        mApplication = cached;
        return cached;
    }
}

LoadedApk 保存 mApplication,进程级 sApplications 又按 package name 缓存实例。framework 内部 makeApplicationInner 默认拒绝重复实例;隐藏 API 的兼容路径可能允许重复。system_server 的 android package 有特殊历史情况,源码只对非 android 包记录重复 WTF。

3. 类加载与资源 ​

java
ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
    initializeJavaContextClassLoader();
}

SparseArray<String> packageIdentifiers =
        getAssets().getAssignedPackageIdentifiers(
                false, false);
for (...) {
    rewriteRValues(cl, packageName, id);
}

应用 classloader 和线程 context classloader 在实例化前准备;共享库 APK 的 R 常量按运行时 package id 重写。rewriteRValues 找不到 R 类或 callback 时可以跳过,反射调用错误才会影响应用创建。

4. Context绑定 ​

源码文件:frameworks/base/core/java/android/app/LoadedApk.java、frameworks/base/core/java/android/app/Instrumentation.java、frameworks/base/core/java/android/app/Application.java

java
ContextImpl appContext = ContextImpl.createAppContext(
        mActivityThread, this);
NetworkSecurityConfigProvider
        .handleNewApplication(appContext);

Application app = mActivityThread.mInstrumentation
        .newApplication(cl, appClass, appContext);
appContext.setOuterContext(app);

Instrumentation 的 newApplication() 继续把 classloader、类名和 Context 交给 AppComponentFactory;返回 Application 后,attachBaseContext() 才有机会运行。

java
public Application newApplication(
        ClassLoader cl, String className,
        Context context) throws Exception {
    Application app = getFactory(
            context.getPackageName())
            .instantiateApplication(cl, className);
    app.attach(context);
    return app;
}

newApplication() 返回前已经完成 framework 内部 attach;Application 的 attach 实现再把开发者可见的 base context 与 LoadedApk 关联起来。

java
final void attach(Context context) {
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

Application.attach() 完成上下文绑定后,LoadedApk 才会登记 Application 实例:

AppComponentFactory/Instrumentation 负责实例化,随后 Application.attach() 调用开发者可覆盖的 attachBaseContext(),再保存 LoadedApk。此时 Application 对象已存在,但 onCreate() 尚未调用。

5. 实例登记 ​

java
mActivityThread.addApplication(app);
mApplication = app;
if (!allowDuplicateInstances) {
    synchronized (sApplications) {
        sApplications.put(mPackageName, app);
    }
}

Application 加入 ActivityThread 和 LoadedApk 缓存后,其他 framework 代码可以通过进程/包状态取到它。登记完成并不表示 Provider 或 onCreate 已完成。

6. Provider时序 ​

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

java
Application app = data.info.makeApplicationInner(
        data.restrictedBackupMode, null);
mInitialApplication = app;

if (!data.restrictedBackupMode
        && !ArrayUtils.isEmpty(data.providers)) {
    installContentProviders(app, data.providers);
}

mInstrumentation.onCreate(
        data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);

Provider 在 Application.onCreate 前安装。原因是系统需要在进程绑定期间发布 provider Binder/本地对象,Provider 自身可能依赖 Application context,但不能假设 Application.onCreate 已运行。restricted backup 路径跳过 Provider,避免自定义 Application/provider 副作用。

7. onCreate调用 ​

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

java
public void callApplicationOnCreate(
        Application app) {
    app.onCreate();
}

默认 Instrumentation 直接调用 Application.onCreate;测试 Instrumentation 可在调用前后插入逻辑。ActivityThread 捕获异常并调用 mInstrumentation.onException(app, e);返回 false 时包装为“Unable to create application”并终止绑定,返回 true 表示 Instrumentation 已处理异常。

8. AMS完成边界 ​

Application.onCreate 返回后,ActivityThread 才执行字体预加载等收尾并调用:

java
mgr.finishAttachApplication(
        mStartSeq,
        timestampApplicationOnCreateNs);

因此 AMS 看到 attachApplication 不代表 Application ready;finishAttachApplication 才带着 onCreate timestamp 标记绑定完成。Application.onCreate 后进程可能仍未启动首个 Activity/Service/Receiver。

9. 失败与性能边界 ​

  • attachBaseContext 异常:Application 尚未登记;
  • AppComponentFactory/classloader 异常:实例化失败;
  • Provider onCreate 卡住:Application.onCreate 尚未执行;
  • Instrumentation.onCreate 异常:Application 已创建、Provider 可能已安装;
  • Application.onCreate 异常:由 Instrumentation.onException 决定是否继续;
  • onCreate 很慢:阻塞 finishAttachApplication 和组件启动;
  • 第三方 SDK 放在 onCreate:会增加所有使用该进程的冷启动关键路径。

10. 导航与后续 ​

bash
# LoadedApk 的 Application 类、缓存、Context 和 Instrumentation 实例化。
rg -n "makeApplicationInner|getCustomApplicationClassNameForProcess|getClassLoader|rewriteRValues|createAppContext|newApplication|sApplications" \
  frameworks/base/core/java/android/app/LoadedApk.java

# attachBaseContext 和 onCreate 调用。
rg -n "newApplication|callApplicationOnCreate|attachBaseContext|final void attach" \
  frameworks/base/core/java/android/app/Instrumentation.java \
  frameworks/base/core/java/android/app/Application.java

# Provider/Application/finishAttach 的真实顺序。
rg -n "makeApplicationInner|installContentProviders|Instrumentation.onCreate|callApplicationOnCreate|finishAttachApplication" \
  frameworks/base/core/java/android/app/ActivityThread.java

下一篇将进入进程 specialization,分析 uid/gid、mount namespace、SELinux、seccomp 和 runtime flags 如何在进入 ActivityThread 前生效;不会重复 Application 生命周期。