Android源码系列(25) -- Application创建

July 23, 2019

一、简介

1.1 简介

Application 在Android应用占据重要地位,继承自 Context 父类可直接当 Context 使用。每个进程只有一个实例,肩负起众多功能。

application_uml

1.2 启动优化

应用第三方依赖库的 初始化定义全局配置缓存建立 操作都在 onCreate() 执行。当依赖库日渐增多而 Application 初始化又在主线程进行,初始化任务越多,应用冷启动时间越长。因此,可把不依赖主线程的依赖库,放在子线程进行初始化。

为了令整个初始化流程更早结束,还要注意子线程数量、子线程最长执行时长,和子线程抢夺主线程时间片等问题。线程创建操作也是耗时操作,且用完的子线程要考虑是否有必要复用。

个人建议直接创建最多两个不复用的子线程用于初始化操作,或在 AsyncTask 内并行执行。

1
AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Param)

1.3 类声明

没有自定义 ApplicationAndroidManifest 如下:

1
2
3
4
5
6
7
8
9
10
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.phantomvk.messagekit">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/AppTheme">
    </application>
</manifest>

自定义 Application 按需执行第三方依赖库初始化操作。

1
2
3
4
5
6
7
8
9
10
package com.phantomvk.messagekit

import android.app.Application

class Application : Application() {
    override fun onCreate() {
        super.onCreate()
        // Init here.
    }
}

没有自定义 Application 的全路径名默认为 android.app.Application

然后在 AndroidManifest 内声明自定义的 Application。由下面 packagename 组合可知自定义 Application 全路径为 com.phantomvk.messagekit.Application,后面会用到这个全路径名。

1
2
3
4
5
6
7
8
9
10
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.phantomvk.messagekit">

    <application
        android:name=".Application"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/AppTheme">
    </application>
</manifest>

二、启动流程

2.1 注册ApplicationThread

流程概括:

  1. ApplicationThreadActivityThread 的内部类;
  2. 应用启动包含注册 ApplicationThread 实例到AMS过程;
  3. 注册成功AMS调用 ApplicationThread.bindApplication() 发出 H.BIND_APPLICATION 消息;
  4. 消息体包含 AppBindData 实例作为后续初始化所需数据;
  5. H 类处理 BIND_APPLICATION 消息,委托 LoadApk 初始化 Application
  6. LoadApk 又把初始化 Application 的工作委托给 Instrumentation
  7. 创建完成后把 Context 保存到 Application,并调用 Application.onCreate()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private class ApplicationThread extends IApplicationThread.Stub { 
    // 此方法由AMS调用
    public final void bindApplication(String processName, ApplicationInfo appInfo,
            List<ProviderInfo> providers, ComponentName instrumentationName,
            ProfilerInfo profilerInfo, Bundle instrumentationArgs,
            IInstrumentationWatcher instrumentationWatcher,
            IUiAutomationConnection instrumentationUiConnection, int debugMode,
            boolean enableBinderTracking, boolean trackAllocation,
            boolean isRestrictedBackupMode, boolean persistent, Configuration config,
            CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
            String buildSerial, boolean autofillCompatibilityEnabled) {
        .....

        AppBindData data = new AppBindData();
        data.processName = processName;
        data.appInfo = appInfo;
        data.providers = providers;
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.instrumentationUiAutomationConnection = instrumentationUiConnection;
        data.debugMode = debugMode;
        data.enableBinderTracking = enableBinderTracking;
        data.trackAllocation = trackAllocation;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfilerInfo = profilerInfo;
        data.buildSerial = buildSerial;
        data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
        // 发出H.BIND_APPLICATION消息
        sendMessage(H.BIND_APPLICATION, data);
    }
}

2.2 执行消息

主线程收到 H.BIND_APPLICATION 消息交给 Handler 实现类 H 处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
class H extends Handler {
    public static final int BIND_APPLICATION = 110;

    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BIND_APPLICATION:
                AppBindData data = (AppBindData)msg.obj;
                // 调用handleBindApplication()
                handleBindApplication(data);
                break;
        }
    }
}

2.3 初始化

开始调用 handleBindApplication(AppBindData data)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
private void handleBindApplication(AppBindData data) {
    .....

    Application app;
    try {
        // 如果为了备份和恢复而启动应用,在该受限制的环境下强制用基础Application类
        // data.info类型为LoadedApk,LoadedApk通过反射创建Application实例
        app = data.info.makeApplication(data.restrictedBackupMode, null);

        // Propagate autofill compat state
        app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);

        // 把Application引用保存在ActivityThread.mInitialApplication
        mInitialApplication = app;

        // 约束环境不启动providers,因为这些providers可能依赖自定义的Application类
        if (!data.restrictedBackupMode) {
            if (!ArrayUtils.isEmpty(data.providers)) {
                installContentProviders(app, data.providers);
                // For process that contains content providers, we want to
                // ensure that the JIT is enabled "at some point".
                mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
            }
        }

        // Do this after providers, since instrumentation tests generally start their
        // test thread at this point, and we don't want that racing.
        try {
            // 设置Handler(Looper.getMainLooper())
            mInstrumentation.onCreate(data.instrumentationArgs);
        } catch (Exception e) {
            throw new RuntimeException(
                "Exception thrown in onCreate() of "
                + data.instrumentationName + ": " + e.toString(), e);
        }
        try {
            // 创建完成的Application实例,触发onCreate()调用开始内部初始化
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                  "Unable to create application " + app.getClass().getName()
                  + ": " + e.toString(), e);
            }
        }
    } finally {
    }
}

上述源码中 data.info 的类为 LoadedApk ,直接看 LoadedApk.makeApplication()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {

    // 如果已经初始化则LoadedApk.mApplication非空
    if (mApplication != null) {
        return mApplication;
    }

    Application app = null;

    // 从ApplicationInfo,即AndroidManifest获取Application名称
    // 从文初实例可知类型为: com.phantomvk.messagekit.Application
    String appClass = mApplicationInfo.className;

    // 若没有声明自定义类默认类名为: android.app.Application
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        // 类加载器用于Application类加载
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            initializeJavaContextClassLoader();
        }

        // 用ActivityThread、LoadedApk创建ContextImpl实例
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

        // 通过Application类名反射获得实例,并把appContext保存到实例
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);

        // ContextImpl和Application互相保存
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }

    // 把Application记录到ActivityThread中
    mActivityThread.mAllApplications.add(app);
    // 赋值给LoadedApk.mApplication
    mApplication = app;

    if (instrumentation != null) {
        try {
            // 调用Application.onCreate()
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!instrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    }

    // Rewrite the R 'constants' for all library apks.
    SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
    final int N = packageIdentifiers.size();
    for (int i = 0; i < N; i++) {
        final int id = packageIdentifiers.keyAt(i);
        if (id == 0x01 || id == 0x7f) {
            continue;
        }

        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
    }

    return app;
}

2.4 实例创建

展开上述源码中的 Application 反射创建流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// android.app.Instrumentation

public Application newApplication(ClassLoader cl, String className, Context context)
        throws InstantiationException, IllegalAccessException, 
        ClassNotFoundException {
    Application app = getFactory(context.getPackageName())
            .instantiateApplication(cl, className);
    // context设置到Applicaton实例父类,即Context的数据成员mBase;
    // attach()调用attachBaseContext(context),里面可初始化MultiDex组件
    app.attach(context);
    return app;
}

private AppComponentFactory getFactory(String pkg) {
    if (pkg == null) {
        Log.e(TAG, "No pkg specified, disabling AppComponentFactory");
        return AppComponentFactory.DEFAULT;
    }
    if (mThread == null) {
        Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation,"
                + " disabling AppComponentFactory", new Throwable());
        return AppComponentFactory.DEFAULT;
    }
    LoadedApk apk = mThread.peekPackageInfo(pkg, true);
    // This is in the case of starting up "android".
    if (apk == null) apk = mThread.getSystemContext().mPackageInfo;
    return apk.getAppFactory();
}

上文把名为 contextContextImpl 实例设置给 Application 的父类成员 mBase。每次把 ApplicationContext 使用时,操作通过 ContextWrapper 委托给 mBase 实例,即上文的 ContextImpl 实例。

而实例化 Application 和一般反射创建实例没有差别,直接通过类名 newInstance() 得到。

1
2
3
4
5
6
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
        @NonNull String className)
        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    // 从ClassLoader用默认构造方法反射建立实例
    return (Application) cl.loadClass(className).newInstance();
}

三、使用实例

看看如何从 Application 获取 applicationContext,前者继承自 ContextWrapper,功能在父类实现。

1
public class Application extends ContextWrapper implements ComponentCallbacks2

可知 application.getApplicationContext 取自 ContextWrapper.mBase

1
2
3
4
5
6
7
8
public class ContextWrapper extends Context {
    Context mBase;
  
    @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }
}

mBase 为实现抽象类 ContextContextImpl 实例,实例包含 ActivityThreadLoadedApk

1
2
3
4
5
6
7
8
9
class ContextImpl extends Context {
    final @NonNull LoadedApk mPackageInfo;

    @Override
    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
}

mPackageInfo.getApplication() 进入 LoadedApk 类。这个 mApplication 就是初始化时构建的 Application 实例。

1
2
3
4
5
6
7
public final class LoadedApk {
    private Application mApplication;

    Application getApplication() {
        return mApplication;
    }  
}

四、总结

简单流程总结:

  • ApplicationLoadedApk 构建,保存到 mApplication,引用返回给 ActivityThread
  • ActivityThreadLoadedApk 返回的对象保存到 mInitialApplication
  • 因此 LoadedApk.mApplicationActivityThread.mInitialApplication 指向相同对象;
  • 正常情况这两个对象也不可能为空。

Application 基本创建流程如上,如果对其他细节感兴趣,可以自行查看 LoadedApkContextImplInstrumentation 等类源码。