Android 8.0 Activity启动流程分析

Activity启动过程中需要注意的一些类:

  • Instrumentation     完成对Application和Activity初始化和生命周期调用的工具类。用来监控系统与应用的交互。
  • ActivityThread     管理应用进程的主线程的执行。
  • ApplicationThread     用来实现ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService管理应用进程中的Activity时,通过ApplicationThread的代理对象与ActivityThread通讯。(继承IApplicationThread.Stub)
  • ActivityClientRecord     在应用程序进程中启动的每一个Activity组件都使用一个ActivityClientRecord对象来描述。并且保存在ActivityThread类的成员变量mActivities中。
  • ActivityRecord     在AMS进程中,一个ActivityRecord对应一个Activity,保存了一个Activity的所有信息。这些ActivityRecord对象对应于App进程中的ActivityClientRecord。
  • TaskRecord   任务栈,每一个TaskRecord都可能存在一个或多个ActivityRecord,栈顶的ActivityRecord表示当前可见的界面 。
  • ActivityStack    一个栈式管理结构,每一个ActivityStack都可能存在一个或多个TaskRecord,栈顶的TaskRecord表示当前可见的任务。
  • ActivityStackSupervisor     管理着多个ActivityStack,但当前只会有一个获取焦点(Focused)ActivityStack。 ProcessRecord     记录着属于一个进程的所有ActivityRecord,运行在不同TaskRecord中的ActivityRecord可能是属于同一个 ProcessRecord。
  • ActivityManagerService     AMS主要负责系统中四大组件的启动、切换、及进程的管理和调度等工作,Android8.0中AMS继承IActivityManager.Stub。

Activity启动,从Launcher到AMS

Activity类的成员变量mMainThread的类型为ActivityThread,用来描述一个应用程序进程。系统每当启动一个应用程序进程时,都会在它里面加载一个ActivityThread实例,并且会将这个ActivityThread类实例保存在每一个在该进程中启动的Activity组件的父类Activity的成员变量mMainThread中。(该进程中每一个启动的Activity都会保存一个ActivityThread实例)

ActivityThread类的成员函数getApplicationThread()用来获取它内部的一个类型为ApplicationThread的BInder本地对象。

将Luncher组件所运行在的应用程序进程的ApplicationThread对象作为参数传递给成员变量mInstrumentation的成员函数execStartActivity,以便可以将它传递给ActivityManageService,这样ActivityManageService 可以通知Launcher组件进入Pause状态。

Activity类的成员变量mToken的类型是IBinder,它是一个Binder代理对象,指向了ActivityManageService 中一个类型为 ActivityRecord的Binder本地对象,用来维护对应的Activity组件的运行状态以及信息。(并且这个mToken对象是在Activity的attach方法中赋值的)

Launcher组件的成员变量mToken作为参数传递给成员变量mInstrumentation的成员函数execStartActivity, 以便可以将其传递给ActivityManagerService,这样ActivityManagerService接下来就可以获得Launcher组件的详细信息了。

  • ApplicationThread和mToken(IBinder)

这两个参数比较重要,ApplicationThread参数最终会交给ActivityManagerService,ActivityManagerService会通过ApplicationThread来通知Launcher组件等状态变化,比如进入Paused状态。

mToken是IBinder类型,他是一个Binder代理对象,这个mToken最终会交给ActivityManagerService,通过mToken获取Launcher组件的详细信息。(这个mToken中封装了ActivityRecord对象)。

  • ActivityManager.getService()获取ActivityManagerService对象

Activity类的成员变量mToken的类型是IBinder,它是一个Binder代理对象,指向了ActivityManageService 中一个类型为 ActivityRecord的Binder本地对象,用来维护对应的Activity组件的运行状态以及信息。(并且这个mToken对象是在Activity的attach方法中赋值的)。

(每一个已经启动的Activity组件在ActivityManagerService中都有一个对应的ActivityRecord对象,用来维护对应的Activity组件的运行状态和信息)。

通过单例模式获取ActivityManagerService到代理。

  public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }

AMS通知Laucher组件进入pause状态

ActivityManagerService#startActivity 

1.参数caller指向Launcher组件所运行的应用程序进程的Application对象。

2.参数intent包含了即将要启动的MainActivity的组件信息。

3.参数resultTo指向ActivityManagerService内部的一个ActivityRecord对象,它里面保存了Launcher组件的详细信息。

ActivityStarter#startActivityMayWait

1.通过mSupervisor.resolveIntent(intent, resolvedType, userId)获取即将启动Activity组件的更多信息,(PackageManagerServcie解析参数intent的内容)。

2.通过ProcessRecord callerApp = mService.getRecordForAppLocked(caller);

在ActivityManagerService中,每一个应用程序都使用一个ProcessRecord对象来描述,并且保存在ActivityManagerService内部。

3.ActivityStarter类的成员变量mService指向了ActivityManagerService,通过getRecordForAppLocked来获得caller对应的一个ProcessRecord对象callerApp。参数caller指向的是Launcher组件所运行的应用程序进程的一个ApplicationThread对象。

Launcher组件的onPause流程

在handlePauseActivity方法中,会将Message对象msg的成员变量obj转换后的SomeArgs中的arg1强制转换成一个IBinder接口。第一件事就是调用成员函数performUserLeavingActivity向Launcher组件发送一个用户离开事件通知,即调用它的成员函数onUserLeaveHint。第二件事就是调用成员函数performPauseActivity向Launcher组件发送一个中止事件通知,即调用它的成员函数onPause。调用QueuedWork类的静态成员函数waitToFinish等待完成前面的一些数据写入操作,例如,将数据写入磁盘的操作。由于现在Launcher组件即将要进入Paused状态了,因此要保证它前面所有数据写入操作都处理完成;否则等它重新进入Resume状态时,就无法恢复之前保存的数据。最后通过ActivityManagerService给它发送的中止Launcher组件的进程间通信请求。

Launcher组件pause状态到新进程启动:

 

ActivityStack#activityPausedLocked

在这个方法中会调用函数completePauseLocked来执行启动MainActivity组件的操作。并将这个ActivityRecord对象的成员变量state的值设置为ActivityState.PAUSED,表示Launcher组件已经进入了Pause状态了。

ActivityStackSupervisor#startSpecificActivityLocked

检查与ActivityRecord对象r对应的Actiivty组件所需要的应用程序进程是否已经存在。如果存在直接调用realStartActivityLocked函数来启动Actiivty组件。否则先以这个用户ID和进程名称来创建一个应用程序进程,然后再通知这个应用程序进程将Activity组件启动起来。

在ActivityManagerService中,每一个Activity组件都有一个用户ID和一个进程的名称,其中用户ID是在安装Activity组件时由PackageManagerService分配的,而进程名称则是由该Activity组件的android:process属性来决定的。ActivityManagerService在启动一个Activity组件时,首先会以它用户ID和进程名称来检查系统中是否存在一个对应的应用程序进程。如果存在,则会直接通知这个应用程序将该Activity组件启动起来。否则,就会先以这个用户ID和进程名称来创建一个应用程序进程,然后再通知这个应用程序进程将Activity组件启动起来。

新进程启动 

 

ActivityManagerService#startProcessLocked

该方法中依然会检查请求创建的应用程序是否已经存在了,如果不存在。会根据指定的名称以及用于ID来创建一个ProcessRecordLocked对象,同时将其保存到ActivityManagerService类的成员变量mProcessNames。

 ActivityManagerServcie#startProcessLocked

得到要创建的应用程序进程的用户ID和用户组ID。调用Process类的静态成员函数start来启动一个新的应用程序进程新的应用程序进程创建成功之后,当前进程会得到一个大于0的进程ID,保存在ProcessStartResult中。调用Process类的静态成员函数start启动一个新的应用程序时,通过entryPoint指定该进程的入口函数为"android.app.ActivityThread"类的静态成员函数main。

同时向ActivityManagerService所在的线程的消息队列中发送一个类型为PROC_START_TIMEOUT_MSG的消息,并且指定这个消息在PROC_START_TIMEOUT之后处理。新的应用程序进程必须在PROC_START_TIMEOUT毫秒之内完成启动工作,并且向ActivityManagerService发送一个完成的通知,以便ActivityManagerService可以在它里面启动一个Activity组件。否则认为超时,就不能将相应的Activity组件启动起来。

#ActivityThread的main方法到scheduleLauchActivity

新的应用程序在启动时,主要做两件事;

1.在进程中创建一个ActivityThread对象,并且调用它的成员函数attach向ActivityManagerService发送一个启动完成通知。

2.调用Looper类的静态成员函数prepareMainLooper创建一个消息循环,并且在向ActivityManagerService发送启动完成通知之后,使得当前进程进入到这个消息循环中。

主要关注新的应用程序是如何向ActivityManagerService发送一个启动完成通知的。在创建ActivityThread对象thread时,会同时在它内部创建一个ApplicationThread对象mAppThread。前面提到,ActivityThread对象内部的ApplicationThread对象是一个Binder本地对象,ActivityManagerService就是通过它来和应用程序进程通信的。

 

ActivityManagerService#attachApplicationLocked

参数pid指向了前面所创建是应用程序进程PID,在前面,ActivityManagerService以这个PID为关键字将一个ProcessRecord对象保存在了成员变量mPidsSelfLocked中。通过参数pid将这个ProcessRecord对象取回来,并且保存在变量app中。得到的ProcessRecord对象app就是用来描述新创建的应用程序进程的。初始化ProcessRecord对象app,就是用来描述新创建的应用程序进程的。最重要的就是初始化其thread成员变量,这个IApplicationThread类型的变量,就是ActivityManagerService通过其与新创建的应用程序进行通信的。

ActivityStackSupervisor#attachApplicationLocked

得到位于Activity组件顶端的一个ActivityRecord对象top,它对应的Activity组件就是即将要启动的MainActivity组件。检查这个Activity组价的用户ID和进程名称是否与ProcessRecord对象app所描述的应用程序的用户ID和进程名称一致。如果一致,那么说明ActivityRecord对象top所描述的Activity组件是应该在ProcessRecord对象app所描述的应用程序进程中启动的。

ActivityStackSupervisor#realStartActivityLocked

将该Activity组件添加到参数app所描述的应用程序进程的Activity组件列表中。通知前面创建的应用程序进程启动由参数r所描述的一个Activity组件,即MainActivity。

# 从ActivityThread的scheduleLaunchActivity到Activity的onCreate方法

将Messgae对象msg的成员变量obj转换成一个ActivityClientRecord对象r,接着调用getPackageInfoNoCheck方法获得一个LoadedApk对象,并且保存在ActivityClientRecord对象r的成员变量packageInfo中。

每一个Android应用程序都是打包在一个Apk文件中的。一个Apk文件包含了一个Android应用程序的所有资源,应用程序进程在启动一个Actiivty组件时,需要将它所属的Apk文件加载进来,以便可以访问它里面的资源。在ActivityThread类内部,就使用一个LoadedApk对象来描述一个已经加载的Apk文件。

 

ActivityThread#handleLaunchActivity

启动由ActivityClientRecord对象r所描述的一个Activity组件。

ActivityThread#performLaunchActivity

创建和初始化一个ContextImpl对象appContext,用来作为所创建的Activity对象activity的运行上下文环境,通过它就可以访问到特定的应用程序资源,以及启动其他的应用程序组件。使用ContextImpl对象appContext和ActiivtyClientRecord对象r来初始化Activity对象activity。最终调用成员变量mInstrumentation的函数callActivityOnCreate将Activity启动起来。

注意:

ActivityClientRecord对象r的成员变量token是一个Ibinder对象,它指向了AcitivityManagerService内部的一个ActivityRecord对象。这个ActivityRecord对象和ActivityClientRecord对象r一样,都是用来描述前面启动的Activity组件的,只不过前者都是在ActivityManagerService中使用,而后者在应用程序中使用。

发布了161 篇原创文章 · 获赞 154 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/zhangying1994/article/details/104029685