源码分析之application启动流程

今天看了一下application的启动流程的源代码,避免忘记,先写文章备份下,防止忘记。另外第一次看有可能某些部分不完整或者理解的不正确,以后再补上。


其实一个应用启动运行过程中最核心的类就是ActivityThead了。

首先先了解一下AcitivityThread中的一些成员变量,当然这里只选择一部分我认为是重要的来解释,这些对下文的描述是有帮助的。


private ContextImpl mSystemContext;//系统的context
final Looper mLooper = Looper.myLooper();//looper,既然是activityThread,那么必然有一个looper来对应
final H mH = new H();//对looper对应的handler,继承自handler,只是多了一些成员变量的定义。application的创建等msg都是由这个handler发出的
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();//记录
final ArrayMap<IBinder, Service> mServices = new ArrayMap<>();//
Application mInitialApplication;//
final ArrayList<Application> mAllApplications = new ArrayList<Application>();//
Instrumentation mInstrumentation;//
final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<String, WeakReference<LoadedApk>>();//
final ArrayMap<String, WeakReference<LoadedApk>> mResourcePackages = new ArrayMap<String, WeakReference<LoadedApk>>();//


一、




一、构建创建Application的Message并发送

首先会构建Message对象,这个Message中包含AppBindData,该对象含有生成Application的所有数据,用于构建Application。(该部分代码还未看,后续补上)

1.1 AppBindData类

static final class AppBindData {
    LoadedApk info;
    String processName;
    ApplicationInfo appInfo;
    List<ProviderInfo> providers;
    ComponentName instrumentationName;
    Bundle instrumentationArgs;
    IInstrumentationWatcher instrumentationWatcher;
    IUiAutomationConnection instrumentationUiAutomationConnection;
    int debugMode;
    boolean enableOpenGlTrace;
    boolean restrictedBackupMode;
    boolean persistent;
    Configuration config;
    CompatibilityInfo compatInfo;

    /** Initial values for {@link Profiler}. */
    ProfilerInfo initProfilerInfo;

    public String toString() {
        return "AppBindData{appInfo=" + appInfo + "}";
    }
}




二、接收Message对象并分发

会通过Handler发送Message,android系统会委托ActivityThread对象的handleMessage(Message msg)方法来处理。

1.首先判断类型,接收AppBindData对象,调用handleBindApplication(data)方法来处理。

case BIND_APPLICATION:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
    AppBindData data = (AppBindData)msg.obj;
    handleBindApplication(data);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;

三、handleBindApplication方法

本文重点分析的就是handleBindApplication方法中做了些什么。源码分析start:

2.首先调用getPackageInfoNoCheck方法生成LoaderApk对象。ActivityThread中存在一个

final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<String, WeakReference<LoadedApk>>();

保存所有的应用和应用对应的LoadedApk。如果存在已经存在LoadedApk对象的话直接返回,否则生成新的。

3.判断是否需要设置应用分辨率密度。(PS:看完之后才知道原来android可以支持对应不同的应用设置不同的分辨率密度)

/**
 * Switch this process to density compatibility mode if needed.
 */
if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
        == 0) {
    mDensityCompatMode = true;
    Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
}
updateDefaultDensity();

4.创建appContext,这是application生成流程中生成的第一个ContextImpl。这个appContext作用感觉主要是作为一种工具类获取生成其他对象所需要的信息。

这里有一个比较大的流程,是用于生成Instrumentation对象的。至于这个对象的作用我大体搜了一下,解释如下:

Android测试环境的核心是一个Instrumentation框架,在这个框架下,你的测试应用程序可以精确控制应用程序。使用Instrumentation,你可以在主程序启动之前,创建模拟的系统对象,如Context;控制应用程序的多个生命周期;发送UI事件给应用程序;在执行期间检查程序状态。Instrumentation框架通过将主程序和测试程序运行在同一个进程来实现这些功能。 

大体理解了,由于不涉及到我们的核心内容那个,所以只是粗略看下,不做深入了解。


5.继续往下走,利用appContext获取PackageManager对象,继而获取InstrumentationInfo信息。最后利用InstrumentationInfo给ApplicationInfo赋值。

6.1有了ApplicationInfo instrApp对象之后,获取对应的LoaderApk。方法是

LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,appContext.getClassLoader(), false, true, false);
这个方法内部还是逻辑内容还是蛮多的。

方法内有一个

final ArrayMap<String, WeakReference<LoadedApk>> mPackages = new ArrayMap<String, WeakReference<LoadedApk>>();

对象,保存所有的应用和LoadedApk的对应关系。如果存在对应的LoadedApk,则直接使用。否则生成新的。

6.2.利用获取到的LoadedApk对象生成ContextImpl instrContext,这个Context是和当前的Application绑定的,而上面个的appContext绑定的LoadedApk则不是。

6.3.通过反射生成Instrumentation对象。

生成Instrumentation对象的流程结束。

7.继续往下走

if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
    dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
} else {
    // Small heap, clamp to the current growth limit and let the heap release
    // pages after the growth limit to the non growth limit capacity. b/18387825
    dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
}
判断application的标记位是否需要高耗内存,如果是需要,则清除虚拟机对内存增长上限的限制。

8.最重要的部分来了,生成Application对象。

Application app = data.info.makeApplication(data.restrictedBackupMode, null);
info为LoadedApk类。这个方法我们具体看一下。

8.1.获取appClass
8.2.获取ClassLoader,getClassLoader方法中,如果不是android系统的package,则去先加载apk的dex文件,然后在返回classLoader.
否则直接返回SystemClassLoader。

mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, lib,mBaseClassLoader);

这里最终返回的是PathClassLoader对象。

ApplicationLoaders中存在一个ArrayMap mLoaders,一个appir和mSplitAppDirs共同作为key对应一个classLoader,其实就是一个application下的apk文件对应一个classLoader。
8.3.如果manifest文件中设置shareUserid或者设置了已经存在的进程名,那么会共享一个classLoader,
这个classLoader为WarningContextClassLoader();返回的都是parentClassLoader。
8.4.再次创建ContextImpl,作为参数传入newApplication的方法中,成为application的context。反射生成application。
8.5.mActivityThread.mAllApplications.add(app);
8.6.重新给apks中的assets资源文件赋值。


有点乱,第二遍看这些代码的时候再处理。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

失落夏天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值