Android_Application启动梳理


Application 分析

Application主要作用:

  • 保存应用进程内的全局变量
  • 初始化操作,application的创建排在四大组件之前,并且存活的时间长,有多少个进程就有多少个application
  • 提供应用上下文

Application 源码分析

  1. 首次先我们先给出方法调用的大概流程,下面我们要根据这个对Application的生命周期进行简单的分析:
-->ActivityThread.main()
  -->ActivityThread.atttach()
    -->ActivityManagerService.attachApplication()
      -->ActivityManagerService.attachApplicationLocked()
        -->ActivityThread.bindApplication()
          -->ActivityThread.sendMessage(H.BIND_APPLICATION, data)
          -->ActivityThread.handleBindApplication()
            -->LoadApk.makeApplication(true, null);
              -->Instrumentation.newApplication()
            -->mInstrumentation.callApplicationOnCreate(app);==>(app.onCreate())

我们从ActivityThread的入口方法看起,(注意:源代码比较多,下面贴出来的只是摘下来的主要代码,要对照源码具体分析)

public static void main(String[] args) {
    ...
    // 准备好主线程的消息循环
    Looper.prepareMainLooper();
    ....
    ActivityThread thread = new ActivityThread();
    // 通过attach()函数向AMS打报告 
    thread.attach(false, startSeq);
    ...
    // 主线程循环开始
    Looper.loop();
}

上面主要代码做了什么?主要是准备好主线程的消息循环,然后向AMS打报告,这attach()就是应用程序向AMS报告的,我们接下来看attach()方法做了些什么

private void attach(boolean system, long startSeq) {
    ...
    final IActivityManager mgr = ActivityManager.getService();
    try {
        mgr.attachApplication(mAppThread, startSeq);
    } catch (RemoteException ex) {
        throw ex.rethrowFromSystemServer();
    }
}

这里面有Binder调用,在attach()中先 获取AMS的远程代理对象。然后调用ams的attachApplication方法,我们看看在Ams中是怎么处理的:

    @Override
    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            ...
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

我们可以看到,attachApplication里面调用了attachApplicationLocked(),

private final boolean attachApplicationLocked(IApplicationThread thread,
    int pid, int callingUid, long startSeq) {
    ...
    thread.bindApplication(processName, appInfo,...);
    ...

}

在这里Binder又绕了一圈,调用应用程序中的binderAppliacation(),这个thread,就是通过传进来的应用进程的ApplicationThread的binder对象,下面我们又回到应用进程,我们看看在应用进程中做了些什么:

public final void bindApplication(String processName, 
    ApplicationInfo appInfo,...){
    ...
    AppBindData data = new AppBindData();
    data.processName = processName;
    data.appInfo = appInfo;
    data.providers = providers;
    ....
    sendMessage(H.BIND_APPLICATION, data);
}

在这里我们看到bindApplication()发送了个消息,其中H继承自Handler,data封装了应用的一些信息。接下来我们看看应用怎么收到消息后怎么处理:

public void handleMessage(Message msg) {
    ...
    switch (msg.what) {
        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;
        case EXIT_APPLICATION:
            ...
        case RECEIVER:
            ...
        case CREATE_SERVICE:
            ...
}

处理消息时,首先判断要需要处理的类型是什么,有BIND_APPLICATION,EXIT_APPLICATIO,RECRIVER,CREATE_SERVICE等等,之前我们发送的是H.BIND_APPLICATION。(H是ActivityThread的一个私有内部类,继承了Handler,其作用很简单,与我们平时开发中使用Handler的作用一样,处理消息以及将消息压入队列)接下来我们就看看在handleMessage()里面如何处理:可以看到调用了 handleBindApplication()方法,我们就跳转到handleBindApplication()中,看看到底做了什么:

private void handleBindApplication(AppBindData data) {
    ...
    // 调用getPackageInfoNoCheck()方法获取一个对象,用来安装包信息,
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    ...
    // makeApplication来创建Application对象
    app = data.info.makeApplication(data.restrictedBackupMode, null);
    // 调用callApplicationOnCreate,就是就是application的生命周期的回调函数app.onCreate()
    mInstrumentation.callApplicationOnCreate(app);
    ...
}

首先是调用getPackageInfoNoCheck()方法,获取一个对象(loadAkp对象),用来描述安装信息,然后调用其makeApplication()方法,创建一个Application对象,接着调用callApplicationOnCreate()方法,这个方法最后就是回调了application生命周期的onCreate()方法。

接下来,我们看看上面的makeApplication()方法是怎么来创建Application对象的:

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }
    ...
    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
    app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
    ...
    return app;
}

在makeApplication()方法中,一开始就先判断mApplication是否存在,如果存在则直接返回,避免application多次创建。否者就需要创建新的Application对象,在创建新的Application对象前,需要先给它创建一个Context。然后在创建新的Application时传入这个Context.

我们已经找到在哪创建Application对象了,那继续看看他是怎么被创建出来的。接着看:

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

在newApplication()方法中,先通过getFactory()获取一个App的一个工厂类对象,然后调用他的instanceApplication()方法来创建Application对象。现在已经创建好了Application对象,再看看接下来做了什么?接下来调用Application的attach()方法参数还是之前创建的那个context对象,这是干嘛的呢,我们顺着这个attach()方法看看:

final void attach(Context context) {
        attachBaseContext(context);
        ...
    }

我们知道Application继承ContextWrapper(ContextWrapper是对Context的封装),这里的attach()里最终将传进来的context赋值给Context的对象mBase,以后对Context其实都是对mBase的操作。

2.到此,我们已经简单的对Application 的初始化流程做了简单的梳理。

从new Application()    --->  application.attach(Context)  ---> application.onCreate()

这里我们可以看出初始化的先后顺序,Context是在Application构造方法之后设置的,所以不能在Application的构造方法中使用Context做一下初始化的操作。

发布了41 篇原创文章 · 获赞 35 · 访问量 4337

猜你喜欢

转载自blog.csdn.net/weixin_38140931/article/details/101222645