Application创建过程

Posted by phantomVK on July 23, 2019

一、简介

1.1 简介

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

application_uml

1.2 启动优化

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

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

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

AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, Param)

1.3 类声明

没有自定义 ApplicationAndroidManifest 如下:

<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">

        <activity
            android:name=".view.MainActivity"
            android:theme="@style/AppTheme.Launcher">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

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

package com.phantomvk.messagekit

import android.app.Application

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

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

没有自定义 Application 则全路径名默认为 android.app.Application,即使编写自定义类也不会被调用。

<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 IPC注册

App启动时有注册 ApplicationThread 实例到AMS的步骤,注册成功后AMS通过IPC调用 ApplicationThread.bindApplication() 发出 H.BIND_APPLICATION 消息,消息体内附 AppBindData 作为后续初始化所需数据。

private class ApplicationThread extends IApplicationThread.Stub {
    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 处理:

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)

private void handleBindApplication(AppBindData data) {
    .....

    Application app;
    try {
        // If the app is being launched for full backup or restore, bring it up in
        // a restricted environment with the base application class.
        // 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;

        // don't bring up providers in restricted mode; they may depend on the
        // app's custom Application class
        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 {
            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()。方法内会检查 Application 是否重复创建。

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的引用创建ContextImpl实例
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // 然后通过Application类名反射获得实例,并把appContext保存到实例中
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        // ContextImpl和Application互相保存Context
        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 {
            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 反射创建流程。

// 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;
    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 和一般Java反射创建实例没有差别,直接通过类名 newInstance() 得到。

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

三、使用实例

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

public class Application extends ContextWrapper implements ComponentCallbacks2

可知 application.getApplicationContext 取自 ContextWrapper.mBase

public class ContextWrapper extends Context {
    Context mBase;
  
    @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }
}

mBase 为实现抽象类 ContextContextImpl 实例。

class ContextImpl extends Context {
    final @NonNull LoadedApk mPackageInfo;
  
    @Override
    public Context getApplicationContext() {
        return (mPackageInfo != null) ?
                mPackageInfo.getApplication() : mMainThread.getApplication();
    }
}

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

public final class LoadedApk {
    private Application mApplication;

    Application getApplication() {
        return mApplication;
    }  
}

四、总结

简单流程总结:

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

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