从应用侧分析Activity启动流程与生命周期

1,129 阅读7分钟

我们知道,ActivityManagerService是Activity的管理者,处于系统进程中,以Binder机制与应用侧通信。可是为什么要有这个Manager呢?这是因为对于Android系统来说,APP中界面的直接体现者Activity,在整个APP的构成中,Activity相对独立,界面与界面之间的联系也相对松散。例如,我们可以在自身应用打开其他应用的界面,即使对于一个应用内的组件,同样也可以位于不同进程内,而这种能力一定是需要APP外的系统来提供支持的。这种额外的功能提供同样意味着额外的监管,例如对组件生命周期的调配,对组件的启动权限的校验,或者某些情况下会强制杀死组件。这些都意味着要有一个系统管理者,而它就是ActivityManagerService,虽然叫AMS,可它除了Activity外,同样参与其他组件的管理。另外AMS也只是系统中组件管理的一个入口,除了AMS外,还有其他大量的类涉及到组件的管理,可以说是十分复杂。

这里,我们着重分析其与组件Activity的联系,从应用侧(Client侧,或者说应用进程)来分析Activity启动流程与生命周期的细节,而不去深究繁杂到容易迷失自我且与日常开发距离较远的系统侧(SystemSever侧)源码。但即使如此,同样能够对Activity启动流程与生命周期有更深入的理解。对于Activity启动流程与生命周期的源码,不同的Android版本往往会存在很多变化,这里我们以目前最新的API 30(Android 11)为例。对于文章中出现的调用栈与源码片段,如果能随文章跟踪源码,会更容易理解。

启动流程的应用侧调用

首先看startActivity是如何传递给AMS的。向下跟踪其调用,整个调用栈如下:

Activity.startActivity(Intent intent)
    
//所有的startActivity最都会调用startActivityForResult
Activity.startActivityForResult(Intent intent, int requestCode, Bundle options)

//Instrumentation注释说该类功能为 监控APP与系统交互
//(monitor all of theinteraction the system has with the application)
//可以认为与AMS交互的指令从这里发出
Instrumentation.execStartActivity(...)

ActivityTaskManager.getService().startActivity(...)

ActivityTaskManager.getService()获取的是IActivityTaskManager,即AIDL的接口,调用至AMS侧。接下来需要到ActivityManagerService.startActivity(...)跟踪系统侧调用。

简单介绍启动流程的系统侧

我们不再逐步跟踪方法调用栈,只需要对系统侧其大概流程有所认识。ActivityManagerService会处理与Activity启动流程中与进程相关的功能,比如Activity若是通过点击Launcher的图标启动的应用首个Activity,这时就需要额外处理进程相关的功能,并处理Application,将其存储为ApplicationInfo。

真正启动Activity的任务会交给ActivityStarter,ActivityStarter将解析Intent,查找目的Activity,处理Intent的flag,并将Activity关联到Task和Stack,Activity被存储为ActivityRecord。对于Stack,有ActivityStack类进行专门存储和管理。并有ActivityStackSupervisor来继续处理Activity的启动以及Activity生命周期相关信息,查看ActivityStackSupervisor注释,有这样一句话:“This class has become a dumping ground. ”,这个类已经成了个垃圾场,可见对于启动流程的任务划分与处理,Android源码目前依然相当混乱,类的职责并不明确,实际上,每个版本这些类都会有很多变化,并且源码注释明确表示ActivityStackSupervisor未来会被拆分重构。

最终,ActivityStackSupervisor会调用ClientLifecycleManager.scheduleTransaction(ClientTransaction transaction)方法,我们从这里继续开始逐步跟踪。从方法名可以看出,已经处理到生命周期相关内容了。实际上,源码到这里,无论是启动Activity还是调度Activity的生命周期,两部分代码流程已经被共用,准备转向应用侧。scheduleTransaction方法会调用ClientTransaction.schedule()。ClientTransaction是包装了需要Client侧执行的动作的事务。其源码如下:

public class ClientTransaction implements Parcelable, ObjectPoolItem {
    private List<ClientTransactionItem> mActivityCallbacks;
    private ActivityLifecycleItem mLifecycleStateRequest;
    private IApplicationThread mClient;
    public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
    }
    ...
}

mActivityCallbacks与mLifecycleStateRequest是被包装的需要Client侧执行的动作,ActivityLifecycleItem继承ClientTransactionItem,其子类有:LaunchActivityItem,StartActivityItem,ResumeActivityItem,PauseActivityItem,StopActivityItem,DestroyActivityItem等,表示Activity此时需要执行到生命周期的那个阶段。mClient是与应用侧通信的接口,对应的是应用侧ActivityThread类中的ApplicationThread。

至此启动流程回归至Client侧,我们可以发现Activity启动流程与生命周期流程在此处是一致的。

启动流程与生命周期返回应用侧

返回后,应用侧调用栈如下:

//ApplicationThread负责与SystemSever侧通信,其本身是ActivityThread内部类
ApplicationThread.scheduleTransaction(ClientTransaction transaction)

//该方法会发送ActivityThread.H.EXECUTE_TRANSACTION的Message,至此Activity启动流程与生命周期就纳入了
//Android消息循环机制,并切换到了主线程(H是主线程Handler)
//ClientTransactionHandler是ActivityThread的父类
ClientTransactionHandler.scheduleTransaction(ClientTransaction transaction)//1

对EXECUTE_TRANSACTION这个Message的处理调用栈如下:

TransactionExecutor.execute(ClientTransaction transaction)

public class TransactionExecutor {
    public void execute(ClientTransaction transaction) {
        ...
        executeCallbacks(transaction);
        executeLifecycleState(transaction);//2
    }
    ...
}

生命周期

可以看出,对于每个通过Binder从系统侧传递的ClientTransaction,会执行其中封装的List<ClientTransactionItem>ActivityLifecycleItem,从而触发Activity的生命周期或其他回调。我们在(1)的内部设置一个断点,观察应用侧接收达到的ClientTransaction。以两种常见场景为例:

  • 从父Activity中启动子Activity
ListActivityLifecycleItem
1TopResumedActivityChangeItem{onTop=false}null
2size = 0PauseActivityItem{finished=false}
3WindowVisibilityItem{showWindow=true}null
4LaunchActivityItemResumeActivityItem
5TopResumedActivityChangeItem{onTop=true}null
6size = 0StopActivityItem{showWindow=false}
  • 从子Activity返回父Activity
ListActivityLifecycleItem
1TopResumedActivityChangeItem{onTop=false}null
2size = 0PauseActivityItem{finished=true}
3TopResumedActivityChangeItem{onTop=true}null
4ActivityResultItemResumeActivityItem
5size = 0DestroyActivityItem{finished=true}

通过观察ClientTransaction中mActivityCallbacks和mLifecycleStateRequest属性内容,可以发现如下几个特点:

  1. 父Activity与子Activity的生命周期及其他回调的触发是交替的,统一在此处纳入Android事件循环机制
  2. List中包含了除生命周期的其他回调,而ActivityLifecycleItem对应了Activity生命周期回调
  3. 并非Activity中每个生命周期方法都对应一次系统侧发送的ClientTransaction,例如上述ClientTransaction中ActivityLifecycleItem仅部分对应于完整的生命周期,而缺失的那些生命周期需要应用侧自行调用(可以理解为AMS发送的ClientTransactionItem代表Activity当前应处的生命周期的最终状态)
  4. 失去焦点的Activity的PauseActivityItem(即onPause)总是出现在获取焦点的Activity的所有生命周期之前。

对于注释(2)处,内部调用栈如下:

TransactionExecutor.cycleToPath(...)

TransactionExecutor.performLifecycleSequence(ActivityClientRecord r, IntArray path, ClientTransaction transaction)

cycleToPath方法会根据当前Activity所处的生命周期为起始,获取到的ClientTransaction中ActivityLifecycleItem所对应的生命周期为终止,生成一个需要执行的舍命周期序列,交给performLifecycleSequence使用,如此方能补全缺失的方法。无论是补全的生命周期,还是ActivityLifecycleItem本身代表的生命周期的execute方法,都将执行ActivityThread的handle系列方法(比如handleResumeActivity),分发Activity生命周期,以Resume为例,调用栈如下:

ResumeActivityItem.execute(IBinder token, ...)

ActivityThread.handleResumeActivity(IBinder token, ...)

ActivityThread.performResumeActivity(IBinder token, ...)

Activity.performResume(...)

//再次回到了Instrumentation
Instrumentation.callActivityOnResume(Activity activity)

Activity.onResume()

由此整个流程从ActivityThread转移到了Activity并调用生命周期方法。上面我们说不同的Activity的生命周期流程是交织在一起的,那么如何确定该调用应用中哪个Activity的生命周期呢?可以看到上述方法都携带一个token,而token其实是与Activity一 一对应的,可以用token顺利找到目标Activity,下方会具体介绍。

启动流程

以上分析了Activity的生命周期从ApplicationThread接收AIDL调用到Activity回调方法最终执行的逻辑流转。但还有Activity的启动部分没有完全分析到,在刚才我们提到的ActivityLifecycleItem中,实际上并不存在CreateActivityItem来表示CREATE这个生命周期,而是通过LaunchActivityItem来表示Activity的启动流程。

Launch的调用栈如下:

//其中构造了ActivityClientRecord,内含token
LaunchActivityItem.execute(IBinder token, ...)

ActivityThread.handleLaunchActivity(ActivityClientRecord r, ...)

//该方法是Activity启动流程中非常重要的方法
//保留关键代码如下
ActivityThread.performLaunchActivity(ActivityClientRecord r, ...) {
	//创建Context
	ContextImpl appContext = createBaseContextForActivity(r);
    //反射创建Activity
	java.lang.ClassLoader cl = appContext.getClassLoader();
	activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    //如果Application不存在,则反射创建Application
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    //用attach方法初始化activity中大量成员变量
    activity.attach(...);
    //调用OnCreate
    mInstrumentation.callActivityOnCreate(activity, ...);
    //向Map中添加token和ActivityClientRecord键值对,
    //也就是我们上面说的用token可以查找找到目标Activity的原因
    r.activity = activity;
    mActivities.put(r.token, r);
    ... 
}

Instrumentation.callActivityOnCreate(Activity activity, Bundle icicle)

Activity.performCreate(Bundle icicle)                    
                    
Activity.onCreate(Bundle savedInstanceState)()

以上也就分析了Activity的启动流程,至此我们完全理清了在应用侧Activity启动流程与生命周期是如何流转的。