Android9.0 ActivityManagerService源码之启动Activity开篇

1,876 阅读11分钟

一、引言

  Activity启动流程系列文章都是基于Android9.0源码的,所以会和其他Android版本源码代码存在一定的偏差,不过Activity启动的大体流程是一致的这就ok了。因为启动Activity的过程比较复杂,所以Activity启动系列文章总共分为了三篇分别是开篇、中篇和尾篇,开篇主要是对Activity启动过程中的一些类、数据结构、启动模式以及Intent中Flag进行讲解;中篇主要是Activity在应用进程和ActivityManagerService(后续称为AMS)进程中启动的源码进行讲解;尾篇则主要是对Activity生命周期源码进行讲解。在正式讲解源码之前首先放两张Activity启动时序图。

Activity启动时序图 图1

Activity进入pause状态时序图 图2

  图1是上层应用调用startActivity之后,如果要启动的Activity所在进程不存在则创建进程的时序图;图2是在启动某一个Activity之前上一个Activity进入到Pause状态的时序图,当然还有Activity从onCreate状态到onResume状态的时序图,因为和进入到puase状态的时序图类似所以就没有画出来,后续会对其源码进行讲解。那么接下来就开始我们的正文部分了。

二、正文

  在正式开始之前,这里先提一下面试过程中可能会出现的一个问题,用户点击Launcher之后启动应用的大致流程是什么?这里简单的说一下。

(1)当用户点击桌面某一个应用图标之后,Launcher会根据要启动应用的首页Activity信息构造Intent,然后调用Launcer中的startActivitySafely方法,然后通过调用Activity的startActivity方法来启动Activity;

(2)在Instrumentation中通过Binder的方式调用到AMS中;

(3)在AMS中首先会去PackageManagerService(后续称PMS)中查找要启动Activity的基本信息;

(4)判断该Activity是否存在如果存在再判断是否有权限启动要该Activity;

(5)构造ActivityRecord存储要启动Activity基本信息,该类在AMS中是存储Activity的基本单位,后续会进行讲解;

(6)根据启动模式和Intent中的Flags值判断是否可以复用已经存在的Activity或者栈,否则新建栈;

(7)将ActivityRecord添加到栈中;

(6)通过Binder的方式通知Launcher界面进入到Pause状态;

(8)判断要启动Activity所在进程是否存在如果存在则通过Binder的方式调用到ActivityThread中执行生命周期方法;

(9)如果不存在则通过Zygote fork一个子进程出来并创建ActivityThread对象启动一个UI线程,然后在ActivityThread的attach方法中通过Binder的方式调用到AMS中,然后在AMS中重新查找当前需要被启动的Activity,最后通过Binder的方式调用到ActivityThread中开始Activity的生命周期;

(10)Activity生命周期执行完之后,又通过Binder的方式调用到AMS中执行上一个Activity的stop方法。至此一个Activity才算真正启动完成。

  这里了解一下Activity启动的大致流程,对后续的源码理解会有很大的帮助作用。

1、LaunchMode

1.1 启动模式

  只要是Android开发,我想对Android中Activity的启动模式都不会陌生,不过这里还是得提一下,对后续的源码理解有一定的帮忙。Android中启动模式有四种,并且无论哪一种启动模式Activity都会位于栈顶。四种启动模式分别是:

(1)stansard:不管是否已经启动了Activity,都会在栈中重新生成Activity实例并压入到栈顶;

(2)singleTop:如果栈顶存在和要启动的Activity相同的Activity实例,则会复用栈顶的Activity实例对象;

(3)singleTask:如果栈中存在和要启动Activity相同的Activity实例对象,则会复用栈中的Activity实例对象并将Activity上面的Activity元素清除掉;

(4)singleInstance:新建一个Task存放Activity,并且该Task中只会有这一个Activity,即使存在其他Activity和当前任务栈亲和性一致。如果已经存在Task中有该Activity实例对象,则将直接复用该Activity实例对象。

1.2 亲和性(TaskAffinity)

  默认情况下,在一个 app 中的所有 Activity 都有一样的 taskAffinity,当然也可以在配置文件中单独指定某一个Activity的亲和性。如果某一个Activity的亲和性和当前应用栈的亲和性不一致,则不同的启动模式会导致不同的结果。某一个栈的亲和性和其root Activity的亲和性一致。

(1)standard和singleTop:这两种模式启动的Activity,如果是在singleInstance的Activity应用栈中启动这两种模式的Activity,首先会去查找是否存在亲和性和要启动的Activity相同的应用栈,如果存在则会将该Activity压入到该应用栈中,如果不存在则会重新创建应用栈进行存储。其他情况应用栈中启动这两种模式的Activity,那么会将该Activity压入到当前应用栈中。

(2)singleTask:如果存在要启动的Activity亲和性和应用栈的亲和性相同,那么该Activity首先会到具有相同taskAffinity的应用栈中查看是否存在该Activity实例,如果存在则销毁在该Activity以上的Activity并调用onNewIntent。如果没有任何任务栈则新建任务栈并将Activity压入到栈中,否则直接将亲和性相同的任务栈移到前台并将Activity添加到任务栈中。

(3)singleInstance:该启动模式的Activity所在应用栈只会存在一个Activity实例,即使其他Activity和该应用栈亲和性相同,如果在该应用栈中Activity启动其他Activity首先也会去查找是否存在相同亲和性的应用栈,如果没有则重新创建一个应用栈。

2、Intent中Flags

  Android中如果在AndroidManifest中设置了Activity的启动模式与Intent中设置的Flags发生了冲突,那么以AndroidManifest中的启动模式为准。这里将几种常用的以及在阅读源码过程中会出现的部分Flag进行说明:

(1)FLAG_ACTIVITY_NEW_TASK:如果单独使用该flag首先会去查找是否存在和被启动的Activity具有相同的亲和性的任务栈(即taskAffinity,注意同一个应用程序中的activity的亲和性一般一样,除非给Activity单独设置亲和性),如果有,则直接把这个栈整体移动到前台,并保持栈中的状态不变,即栈中的activity顺序不变,然后把启动的Activity压入栈中,注意这里和singleTask的区别。如果没有,则新建一个栈来存放被启动的activity。和4联合使用首先清除原来已经存在栈中所有的Activity并将要启动的Activity添加到该栈中,可以达到singleInstance效果。和3联合使用可以达到singleTask效果。如果在Intent中设置了该Flag,那么通过startActivityForResult方法启动的Activity会接收到一个取消的返回结果;

(2)FLAG_ACTIVITY_SINGLE_TOP:和singleTop作用一样,栈顶如果已经存在要启动Activity的实例,则直接复用栈顶Activity实例对象;

(3)FLAG_ACTIVITY_CLEAR_TOP:要启动的Activity如果在当前应用栈中已经存在对象实例,并且要启动的Activity的LaunchMode是standard则会将当前实例对象以及实例对象上面的Activity清除掉然后新建实例对象否则复用存在的实例对象,注意是当前栈;

(4)FLAG_ACTIVITY_CLEAR_TASK:清除任务栈,只能和FLAG_ACTIVITY_NEW_TASK联合使用才会有效果;

(5)FLAG_ACTIVITY_NO_HISTORY:Activity一旦退出,或者在Activity中启动了其他Activity就不会存在于栈。同样也可以在AndroidManifest.xml中设置“android:noHistory”;

(6)FLAG_ACTIVITY_MULTIPLE_TASK:总是和FLAG_ACTIVITY_NEW_DOCUMENT以及FLAG_ACTIVITY_NEW_TASK联合使用,用于重新创建一个Task存放Activity;

(7)FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:Activity不会被放入到最近启动的Activity列表中;

(8)FLAG_ACTIVITY_BROUGHT_TO_FRONT:这个标志位通常不是由应用程序中的代码设置的,而是Launch Mode为singleTask时,由系统自动加上的;

(9)FLAG_ACTIVITY_LAUNCH_ADJACENT:用于分屏多窗口模式下使用,新活动会显示在就活动旁边。本flag只能跟FLAG_ACTIVITY_NEW_TASK联合使用;

(10)FLAG_ACTIVITY_FORWARD_RESULT:用于结果透传,比如A启动B,B启动C,然后C的结果要返回到A。那么就需要在B的Intent中添加这个Flag,并且不能使用startActivityForResult方法进行启动。

(11)FLAG_ACTIVITY_REORDER_TO_FRONT:该Flag会让已经在任务栈中启动的Activity直接被移到前台。比如在一个任务栈中存在A B C D 四个Activity,如果在D中启动B,那么任务栈就变为了A C D B。该Flag的优先级低于FLAG_ACTIVITY_CLEAR_TOP。

3、存储Activity数据结构类

3.1 ActivityRecord

  它是管理Activity的最小单元,Activity的基本信息都存储在该数据结构类中,包括包名、ActivityInfo、启动时间、所属进程以及TaskRecord等。每次启动一个新的Activity都会新建一个ActivityRecord对象来存储Activity的基本信息。

3.2 TaskRecord

  它是用于存储ActivityRecord的栈式结构,也就是平时所说的任务栈,栈顶元素是当前可见的Activity。通过ArrayList来对ActivityRecord进行存储。其中有两个很重要的成员变量:

//存储当前任务栈的所有ActivityRecord
final ArrayList<ActivityRecord> mActivities;
//标识当前任务栈处于哪一个ActivityStack中
private ActivityStack mStack;

3.3 ActivityStack

3.3.1 定义

  ActivityStack的职责是管理多个任务栈(TaskRecord),它是一个栈式结构,栈中的元素是TaskRecord。 每个Activity在特定的时刻都会有一个状态,譬如显示、销毁等, 在应用进程看来,这些状态的变化就是在执行Activity的生命周期函数;并且这些状态的变化都需要经过ActivityStack来驱动。 它会在新建TaskRecord之前判断是否需要新建,如果需要则通过ActivityDisPlay进行创建,然后再将该Stack移到前台过程中添加到ActivityDisPlay的mStacks中;

3.3.2 状态

  Activity的状态是通过ActivityState这个枚举类来定义的:

enum ActivityState {
     INITIALIZING,
     RESUMED,
     PAUSING,
     PAUSED,
     STOPPING,
     STOPPED,
     FINISHING,
     DESTROYING,
     DESTROYED
}

3.3.3 部分成员变量

ArrayList<TaskRecord> mTaskHistory:记录回退栈中所有的Activity,有可能Activity还在运行状态,存储的是TaskRecord对象;
ArrayList<TaskRecord> mLRUActivities:按最近最少使用(LRU)排序当前ActivityStack中所有的Activity,列表中第一个元素是最新活动的Activity;
ActivityRecord mPausingActivity:正在pause的Activity;
ActivityRecord mLastPausedActivity:这是最近进入到pause状态的Activity;
ActivityRecord mResumedActivity:当前处于Resume状态的Activity,也就是正在和用户交互的Activity;
ActivityRecord mLastNoHistoryActivity:该Activity不会被添加到mTaskHistory列表中,一旦离开该界面就会被销毁;
ActivityStackSupervisor mStackSupervisor:表示当前ActivityStack是在哪一个ActivityStackSupervisor中;

3.4 ActivityStackSupervisor

  该类用于管理多个ActivityDisPlay对象,并通过ActivityDisPlay对象间接管理多个ActivityStack对象,该类只会在AMS中调用createStackSupervisor进行初始化,并且也只会在AMS的构造方法中调用该方法进行初始化,所以在AMS进程中该类只会存在一个实例对象。

ActivityStack mHomeStack:用于存储和桌面相关的Activity;
ActivityStack mFocusedStack:用于存储当前获取焦点的ActivityStack,也就是里面存储的Activity可能正在和用户交互;
ActivityStack mLastFocusedStack:如果该变量和mFocusedStack变量对象相同,则说明mFocusedStack栈顶的Activity已经启动成功并且可以和用户交互;如果mFocusedStack发生了变化,那么该变量则是发生变化前的mFocusedStack,如果新的mFocusedStack启动成功,那么该变量则会被赋值为新的mFocusedStack;
SparseArray<ActivityDisplay> mActivityDisplays:记录ActivityDisPlay;

3.5 ActivityDisplay

  在ActivityStackSupervisor中通过ActivityDidplay间接管理所有的ActivityStack。每一个ActivityDisPlay对应到一个显示设备,默认的显示设备是手机屏幕。 ActivityStackSupervisor间接通过ActivityDisplay来维护多个ActivityStack的状态。 在ActivityDisPlay中有一个成员变量用来管理所有的ActivityStack:

//当前显示设备上所有的ActivityStack对象
ArrayList<ActivityStack> mStacks = new ArrayList<>()

3.6 ProcessRecord

  记录属于一个进程的所有ActivityRecord,运行在不同TaskRecord中的ActivityRecord可能是属于同一个ProcessRecord。

3.7 对应关系

  存储Activity数据结构对应关系:

Activity存储数据结构对应关系图

4、总结

  写这个开篇的目的主要是为了能够对其中所涉及到的启动模式、Intent中Flags以及Activity的存储方式有一个大致的了解,以增强后续对源码的理解。当然上述很多东西都是个人理解,如果有错误的地方还望指正出来。