详解安卓从图表icon点击到APP启动界面加载流程

时间:2021-01-02 16:45:48
首先要明确一点:在Android系统中,应用程序是由Launcher启动起来的,其实,Launcher本身也是一个应用程序,其它的应用程序安装后,就会Launcher的界面上出现一个相应的图标,

点击这个图标时,Launcher就会对应的应用程序启动起来。

1.用户在手机桌面点击要启动的软件的icon,此时我们的上下文是Launcher的进程,对于Launcher.java,继承了Activity,在其点击事件中,调用了

startActivitySafely(intent, tag);

   startActivity(intent);

startActivityForResult(intent, -1); 显然这里会通过ActivityManagerService的远程接口,即ActivityManagerProxy接口,调用Binder驱动


class ActivityManagerProxy implements IActivityManager
{

......

public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
IBinder resultTo, String resultWho,
int requestCode, boolean onlyIfNeeded,
boolean debug) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeTypedArray(grantedUriPermi
......

Note:下文对于Binder通讯不在附加代码

这样通过AMS的远程服务代理,通知AMS,你现在给我准备我要启动某个软件的主Activity了

2.AMS通过Launcher传的IApplicationThread caller这个Binder告诉Launcher进程,我准备好了,你要进入Paused态了

3.Launcher通过Binder告诉AMS已经进入Paused态

4.AMS为即将运行的APP创建新进程,这个新进程会导入ActivityThread实例并运行其Main方法(同时说明,每个APP都有一个专属Process,都自带一个独有的ActivityThread主线程实例)

至此要启动APP的进程被创建

     ActivityThread.java中的 main这个函数

ActivityThread thread = new ActivityThread();//在进程中创建一个ActivityThread实例,

thread.attach(false); // 然后调用它的attach函数,接着就进入主线程消息循环了,直到最后进程退出。

Note:函数attach最终调用了ActivityManagerService的远程接口ActivityManagerProxy的attachApplication函数,传入的参数是mAppThread,这是一个ApplicationThread类型的Binder对象,它的作用是用来进行进程间通信的。

5.在ActivityThread的main方法中,再次通过AMS远程服务代理进行Binder通讯,讲自己的ApplicationThread这个Binder传给AMS,以供AMS后续与APP的通讯

6.AMS经过一系列处理,调用ApplicationThread(app.thread.scheduleLaunchActivity)通知APP进程,一切就绪,可以执行真正的MainActiviy启动了

7.ApplicationThread通过Handler发消息给主线程ActivityThread,主线程调用 handleLaunchActivity(r, null);
8. handleLaunchActivity(r, null);调用 performLaunchActivity(r, customIntent);
9. 收集要启动Activity的相关信息,主要package和component信息:
10. ClassLoader将xxx(包名).MainActivity类加载进来

               activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);

Instrumentation的newActivity方法内部实现是 return (Activity)cl.loadClass(className).newInstance();

至此要启动的activity被创建
11. 接下来是 makeApplication 创建Application对象,这是根据AndroidManifest.xml配置文件中的Application标签的信息来创建的

        java.lang.ClassLoader cl = getClassLoader();

if (!mPackageName.equals("android")) {
initializeJavaContextClassLoader();
}

a. ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);

b. app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext); //通过类加载器创建Application

c. instrumentation.callApplicationOnCreate(app);通过 instrumentation调用application实例的onCreate方法


至此要启动APP的Application的Context以及Application示例被创建,并且Application的onCreate被调用

12.为Acticity创建上下文信息,并且将刚刚创建的ContextImpl通过Activity的attach赋值给Activity类的 继承自ContextWrapper的base成员(这样亦可以认为其属于activity类),

            Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);

activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.voiceInteractor);

Note:
这里,通过Activity的attach方法,ContextImpl与Activity建立的关联,同时在attach中还会完APP的Window创建并建立Activity与Window的关联,
这样,以后当Window收到外部输入事件就会传递给Activity
ContextWrapper具体实现即ContextImpl,Context的大部分功能都是ContextImpl实现的,比如context的抽像startActivty方法,具体实现在ContextImpl。

13. 最后在 performLaunchActivity中调用 mInstrumentation.callActivityOnCreate(activity, r.state);

14.handleLaunchActivity中 mInstrumentation.callActivityOnResume(this);这里调用了activity的onResume,并且通过Binder告诉AMS,已经resume了

总结:

    1. APP应用的进程创建由AMS进行,新的进程会导入android.app.ActivityThread类,并且执行它的main函数

2. 可见,应用中的每个activity都对应一个context,因此每个app的总context数 == activity个数+service的个数 + 1 (application个数)

3. app的入口activity的创建在application之前,但是其oncreate调用却在application

4. activity生命周期的回调,最后都是通过mInstrumentation.callActivityOnXXX ,mInstrumentation在这里的作用是监控Activity与系统的交互操作,相当于是系统运行日志。