关于AMS中Activity调度基础请参看Activity调度分析一
目录
ActivityManagerService中Activity调度分析二
1 简介
1.1范围
1.2 目的
2 APP启动分析
2.1 App启动
2.2 AMS管理过程
3 Activity调度分析
3.1 进程内Activty启动
3.2 进程内Activity回退
基于Android4.4平台,分析首次启动第三方App关键流程,重点关注AMS在这个过程中,是如何组建Stack,Task及ActivityRecord的。在此基础上通过分析三方进程内Activity启动,来理解AMS多场景的管理能力。
通过分析AMS的核心流程来认识AMS的本质,本文接着AMS第一篇分析,在上文中通过AMS中Launcher启动分析,已经了解了AMS框架管理的关键类及基本的调度逻辑,这篇文章在此基础上,通过第三方APP启动及调度分析,来理解AMS对多Stack及Activity场景处理。另外对于单Activity的启动模式,如何基于AMS管理框架对Activity施加影响也会涉及到。
这里将介绍三方APP启动流程,重点围绕在全过程的流程梳理,在分析过程中将忽略第一篇介绍内容,着重凸显AMS统一的管理过程
首先通过下图来看下,App启动的全链路过程,结合第一篇文章中对Launcher启动分析,可以初步看到Ams在Actvity管理中固定的一些流程。
区别于Launcher启动,首次Activity启动,其ActivityInfo的构造依赖于入参Intent,而不同于Launcher中Intent全局搜索。其次是在ActivityStack通过resumeTopActivityLocked方法启动Activity时,流程的差异。下面主要来看第二点,也就是resumeTopActivityLocked中启动Activity流程的差异。
此时的AMS场景是,Launcher已经启动,首次启动第三方进程Activity。第一阶段首先进入resumeTopActivityLocked方法分析
这里next对象即马上要启动的三方进程Activity,明显部位空,继续分析
这个场景下,焦点栈刚新建,此时prev对象为空,这个逻辑块不会进去,按序分析
在维护的stop及其它状态LIST中移除nest对象
这里注意下,mResumedActivity对象为空,另执行完pauseBackStacks后返回pausing状态为true,所以直接在这里返回。
第二阶段重点来看下pauseBackStacks方法
很明显,此时homeStack中mResumedActivity不为空,且此时homeStack不是焦点栈,因此要对非焦点栈执行pause动作,进入来分析
如上图代码显示,首先是对HomeStack中特殊Activity状态维护。同时又代码:
prev.state = ActivityState.PAUSING; prev.task.touchActiveTime(); |
这里将prev(Launcher)的状态设置为PAUSING,达到对AMS中ActivityRecord的状态维护。一般而言在对应的用户进程中有对应对象,其状态也需要维护,后续会涉及
继续分析,这里通过prev对象持有的app属性成员,调用schedulePauseActivity方法,实现IPC通信。同步的这里要注意,通过mStackSupervisor.acquireLaunchWakelock()来申请wake锁,防止在Activity切换时,设备误进入休眠(earlySuspend)状态。
其中prev对象的appToken为IApplicationToken.Stub类型,是三方进程的Binder句柄。
通过上图可以看到prev.app.thread对象是IApplicationThread的proexy代理,其本体实现在三方进程内的ActivityThread(这里特制Launcher进程)。
最后一个阶段来看下此时ActivityThread内的交互
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges) {
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? 1 : 0),
configChanges);
}
如上面代码,在Activity中直接通过Handler来分发处理信息,此时的MsgID为PAUSE_ACTIVITY,继续来看下是如何处理此信息的
这里通过handlePauseActivity来处理,其中逻辑分为两步:
这里还需要关注下ActivityClientRecord类,这个类类似于AMS中ActivityRecord,在客户端进程内维护Activity信息。下面首先来看下在客户端进程(Launcher)如何暂停Activity,进入performPauseActivity方法:
这里通过mInstrumentation执行Activity的生命周期方法onPause().,同时维护ActivityClientRecord对象状态:
把paused属性变量设置为True,代表此Activity处于暂停状态。此时回到handlePauseActivity函数,通过
try {
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
}
activityPaused方法通知AMS,暂停Ativity结束,这里回到AMS来看下如何处理
根据这里分析的场景,此时Stack是HomeStack,此时通过stack的方法activityPausedLocked来通知对应Activity暂停结束,它通过调用completePauseLocked方法,完成通知,这里来看下completePauseLocked方法:
这里可以看到,首先找到topStack焦点栈,然后调用resumeTopActivitiesLocked开启二次寻租,此时的场景对应状态为,Launcher已经完成Pause,新开启的Activity只需启动了。
至此为止,已经分析完了首次启动普通客户端Activity与启动Launcher 流程间差异,下面基于此来总结下AMS在整个过程中的管理方式。
通过2.1的分析结合第一篇对AMS分析,这里来看下在首次启动Launcher及Activity过程中AMS的数据流。
在上面数据流图中,每个加工的TAG有:
AMS: ActivityManagerService
ASS: ActivityStackSupervisor
AS: ActivityStack
通过此数据流图,可以看到下面三点
基于第三方进程内Activity的启动,及回退流程,区别2.2节数据流图展示的统一流程,通过分析AS及ASS对Activity控制来展示差异化细节,更加全面的理解AMS的调度流程及细节。
继续基于第二节分析,这里的用户场景是已经启动Launcher,及三方用户程序,且当前界面是三方进程内MainActivity。
此时在MainActivity内点击启动二级界面HelloWorld。基于2.2数据流图,重点关注 AS中的resumeTopActivityLocked的逻辑,在这之前的控制流程,参考日志:
开始分析之前,来看下下图的逻辑流程
同理,在启动二级Activity时,AMS通过两次resumeTopActivity来完成Activity的调度,这里忽略第一次resumeTopActivity逻辑,从第二次开始分析。进入resumeTopActivity有
这里prev是三方进程的一级Activity,此时非空,继续分析
这里mResumedActivity是空,通过第一轮的resumeTopActivity一级Activity完成了暂停,此时的mResumedActivity为空。
接下来判断prev不为空:
将prev对象添加到AMS中全局mWaitingVisibleActivities对象中,供后续逻辑处理,继续往下分析
此时next的app属性还是空,直接调用startSpecificActivityLocked来继续逻辑
mStackSupervisor.startSpecificActivityLocked(next, true, true); |
进入startSpecificActivityLocked方法继续分析
已知此时一级界面已经启动完成,所以app对象非空,直接调用realStartActivityLocked来处理,在此方法中主要处理有
这里重点来分析第三点,进入realStartActivityLocked方法
此时通过Binder,由ActivityThread执行具体逻辑,进入ActivityThread来看
这个方法主要是依赖AMS传递过来的入参,在客户端进程中构建对应的ActivityClientRecord对象,之后发送Handler信息。
这里来看下如何处理LAUNCH_ACTIVITY信息
进入handleLaunchActivity方法来继续分析
这个函数主要做了两件事
先来简单分析下performLaunchActivity方法
通过ClassLoader做入参,新建一个Activity对象,接下来通过attach来绑定对象新建窗口Window对象,这个后面会介绍到。
在handleResumeActivity方法,顾名思义,会执行Activity的onResume方法,然后通过下面代码将此二级Activity对应的Window绑定到系统服务WindowManagerService,以便于后期此二级界面接受输入事件
可以看到这里通过WindowManager来完成绑定,这里不展开,感兴趣可以自己查看相关代码。
此时基本完成了realStartActivityLocked中启动Activity逻辑分析,回到此函数,可以看到在完成上面动作后,有:
这两个函数基于AMS的管理框架,完成一些状态维护,这里由于篇幅所限不展开。
至此,基本简要分析完了二级Actiity的启动过程,AMS在Activity调度中基本依赖2.2描述的数据流图来管控,但是针对多场景Activity现状,AMS的控制会不同,细节聚焦在具体函数中,但万变不离其宗。
基于3.1节场景,现在来分析下二级Activity界面的回退流程,此时AMS中栈状态为:
以上述AMS静态状态,Activity回退依赖于2.2分析的数据流图,这里从ActivityStackSupervisor类的startActivityUncheckedLocked方法做入口,此时已经依赖intent解析并新建ActivityRecord对象,入口如下:
同步对应的打印日志如下:
在上面的分析中,startActivityUncheckedLocked主要负责入参ActivtyRecord对应的stack及task的适配,这里在回退流程中有:
这里targetStack,根据当前AMS静态状态,其实就是当前的焦点Stack。然后将此task设置到入参activtyRecord中
继续分析,调用ActivityStack的startActivityLock方法,其中逻辑有:
在这里将ActivityRecord添加到task中,此时可以看到普通模式穹启动Activity,针对相同activty会新建ActivityRecord插入到task中,其后续启动模式已经类似二次启动Activity了。
对应到ActivityStack中的resumeTopActivityLocked方法,核心逻辑可以看到
在这里,pause此stack的resumeActivity,这个场景下就是HelloWorldActivity了。可以看到数据走向归属于AMS的数据流,逻辑走向类似二次启动Activity。
至此结束了Activity调度分析,通过AMS管理框架的类信息分析,AMS中Activity几个核心流程调度分析以及AMS数据流图分析,初步对AMS是如何管理Activity类信息,Activity生命周期流转有了基本的了解,对具体场景分析,有兴趣的可以在此基础上深入代码。