android ams 架构,Android O Framework架构分析:以AMS视角看Activity启动过程

在Android系统中,Activity的启动是一个非常频繁发生的过程,在Framework层中,这个过程牵涉到的模块也非常多。本文将基于Android 8.0源码,以ActivityManagerService模块(以下简称AMS)的视角来分析其过程中主要发生的行为。

一. AMS中层次结构

AMS模块中涉及Activity的数据结构主要有三个:ActivityRecord,TaskRecord,ActivityStack. 其中ActivityRecord抽象地表示了每一个Activity,这个数据结构记录、管理了Activity的各种信息、属性、状态等。TaskRecord抽象地表示了任务的概念,任务是由一系列Activity以栈的形式组成的,一般情况下启动Activity都会在同一个任务中启动,添加了特殊的flag(FLAG_ACTIVITY_NEW_TASK)或者特殊的启动模式则会在新任务中启动一个Activity. 任务和进程并无限制关系,同一任务中也可存在其它进程的Activity,同一进程的Activity也可以存在与不同任务中。具象来看的话,系统中的最近任务界面显示的任务就和AMS里的TaskRecord描述的是一样的概念。ActivityStack则是用来管理TaskRecord的结构,是由一系列TaskRecord以栈的形式组成的。它是一个抽象的概念,在系统中无法具象地看到它。从6.0开始只有两个ActivityStack(桌面所在的TaskRecord在单独的ActivityStack中,其他TaskRecord在另一个),到8.0中已经有八个(为分屏,最近任务,画中画,自由模式等创建的),ActivityStack随着Android大版本升级越来越多。

二. Activity启动的主要流程

Activity启动时,客户端通过Binder向system server端进行通讯,通知AMS进行相应地处理,其时序图为(红色代表app进程,蓝色代表system server进程):

dc5849b2c124e61b87c65b4240c43a6b.png

上面的时序图其实仅仅描述了在Activity启动时,AMS端的一些通用逻辑,绝大多数的情况下,在Activity启动时首先都会经历上述的流程。在上面时序图最后,也就是第10步的调用,会根据不同的情况进入不同的分支,后面会具体分析。

客户端的Instrumentation类会通过Binder call调用到AMS端的startActivity(上图步骤4),其参数列表为:

参数

解释

IApplicationThread caller

调用者的IApplicationThread对象

String callingPackage

调用者的包名

Intent intent

客户端进程传递过来的Intent对象

String resolvedType

ContentResolver相关

IBinder resultTo

调用者的token

String resultWho

调用者Activity的mEmbeddedID字段

int requestCode

客户端传过来的,为startActivityForResult使用的请求码

int startFlags

0

ProfilerInfo profilerInfo

null

Bundle bOptions

客户端传过来的ActivityOptions参数

接下来进入到system server进程,从上图步骤4 - 10则为AMS中的行为,下面我们简单分析下在这一系列调用栈中,AMS所发生的一些主要行为:

ActivityStarter.startActivityMayWait (步骤6):

1. 解析intent(ActivityStackSupervisor.resolveIntent,最终会通过PackageManagerService解析),获得ResolveInfo对象。

2. 通过Intent以及刚刚解析出来的ResolveInfo对象去获取ActivityInfo对象(ActivityStackSupervisor.resolveActivity)。

3. 即将启动的activity是否处于heavy-weight进程中,如果是会进行相关处理。

ActivityStarter.startActivityLocked -> startActivity (步骤7 - 8):

1. 检查调用者进程是否为空。

2. 获取调用者(sourceRecord)的ActivityRecord对象,根据launch flags计算activity result需要发送回的ActivityRecord对象。

3. 对传递进来的参数进行检查,如果存在非法值则返回。

4. 创建待启动的ActivityRecord对象。

5. 检查这次启动是否需要加入PendingActivity的列表中,需要则加入后返回,不需要则启动之前PendingActivity列表中的所有activity

ActivityStarter.startActivity -> startActivityUnChecked (步骤9 - 10):

1. setInitialState:为一些全局变量进行赋值,以及一些简单的初始化工作。

2. computeLaunchingTaskFlags:根据要启动的task,更新mLaunchFlags,和Activity的启动模式相关。

3. getReusableIntentActivity:获取可复用的ActivityRecord对象。如果存在可复用的ActivityRecord对象,则获取其task,并根据一些条件通知客户端进程进行一些处理(如回调onNewIntent)。接下来会为其设置对应的Stack,并将其移动至前台。即:如果启动的Activity已经存在,在此处则会进入ActivityStack.moveTaskToFrontLocked流程。

4. 如果未发现可复用的Activity时(首次启动Activity),则需要根据条件创建/复用Task和Stack。此时会通过ActivityStack.startActivityLocked做一些Stack相关的处理。

5. 无论是否找到可复用的Activity,接下来AMS都会通知客户端进程去paused前一Activity,至此通过客户端进程调用的startActivity触发的AMS行为结束。当前一Activity的进程paused结束后,会再次通知AMS,从而会触发新一轮的行为。

上面提到,在启动过程中会检查待启动的Activity是否存在可复用的Activity(通常情况下可复用指的是启动一个在后台的Activity,如回桌面时,由于桌面的Activity不会被销毁,所以每次启动时都可以找到可复用的Activity),下面分析一下这两种情况的不同的处理流程:

1. 非首次启动,调用栈:ActivityStarter.startActivityUnchecked(上面时序图步骤10) -> ActivityStarter.setTargetStackAndMoveToFrontIfNeeded -> ActivityStack.moveTaskToFrontLocked,看这个调用栈的名字可以发现,如果要启动的Activity已经存在,会把其对应的任务移动至前台。其主要行为:

(1) insertTaskAtTop:更新mTaskToReturnTo字段,调整目标TaskRecord在ActivityStack中的位置。通知WMS TaskRecord的位置变化:StackWindowController.positionChildAtTop

(2) ActivityStackSupervisor.moveFocusableActivityStackToFrontLocked:将ActivityRecord移动到顶部,将当前ActivityStack设置为mFocusedStack,即当前具有焦点的ActivityStack

(3) updateTransitLocked:通知WMS设置过渡动画类型。

(4) ActivityStackSupervisor.resumeFocusedStackTopActivityLocked

2. 首次启动,调用栈:ActivityStarter.startActivityUnchecked(上面时序图步骤10) ->ActivityStack.startActivityLocked,其主要行为:

(1) 查看首次启动的ActivityRecord是否以New Task形式启动,如果是,则通过insertTaskAtTop将TaskRecord移动至栈顶;否则,找到当前TaskRecord在全局中的位置。如果WMS端没有对应的WindowContainer,则通知其创建一个(用于和WMS通讯)。

(2) 检查是否需要创建一个新进程(ProcessRecord)。

(3) 通知WMS设置过渡动画类型。

(4) ActivityStackSupervisor.resumeFocusedStackTopActivityLocked

无论是否首次启动,最终都会进入ActivityStackSupervisor.resumeFocusedStackTopActivityLocked中,接下来会进行一些生命周期相关的处理。下面我们简单分析一下Activity的生命周期是如何调度的。

三. Activity的生命周期

cbd67125fc7a52f16a64a7c9eb3477ea.png

当一个Activity启动时,一般情况下会涉及两个Activity生命周期的变化。根据前文所述,当startActivity被调用时,AMS最终都会触发到ActivityStackSupervisor.resumeFocusedStackTopActivityLocked方法中去,这个方法逻辑非常多,首先会检查当前是否有需要进入paused状态的Activity,如果有,则通知其对应的客户端进程进行相关处理,其时序图如下:

58545e929a7983391b538026ea2dc055.png

这里的步骤1就是上面startActivity在AMS中都会最终进入的逻辑,这里会检查是否有需要进入paused状态的Activity,如果有,则通知客户端进程,AMS端的startActivity流程结束。客户端进程由ActivityThread接收到AMS端发来的通知,进行相关处理。此时旧的Activity将进入paused状态,其onPause回调被执行(步骤12)。当客户端paused相关调度执行完后,仍然会通知AMS,AMS会进行相关处理。接下来主要分为3种情况,针对这3种情况AMS会进行不同的处理:

1. 前一个Activity进入paused状态后通知AMS,新创建的Activity启动,如果新创建的Activity已经存在对应进程,则进入onCreate -> onStart -> onResume的生命周期:

805b6357c03dc4b87b891da8b4c0d6f2.png

这种情况为在已存在的进程下启动一个新的Activity,比如同一个app中启动一个新的Activity,可以看到Activity中一些关于生命周期的回调被执行,其顺序也符合我们贴的那张官方提供的生命周期的图:onCreate (步骤15)-> onStart (步骤18)-> onResume (步骤23)。

2. 如果新创建的Activity还没有已经存在的进程,则AMS端的处理会有些不同:

40146d5b42c4af9d6fe76c44f241836b.png

这种情况为待启动的Activity还没有对应的进程,比如从桌面启动一个从未启动过的app,其AMS端的处理会完全不同。发起点(步骤1)还是一样,仍需要等待客户端进程通知AMS旧Activity已经进入paused状态了,不同的是AMS需要首先为其创建一个进程,如步骤8所示,这个过程比较复杂,在本文中不做分析。进程创建完后,新创建的进程会通知AMS(步骤10),接下来AMS会在一系列处理后通知该进程(步骤13),对生命周期进行处理。scheduleLaunchActivity在客户端进程所产生的行为与上面情况1一致,即新Activity都会进入onCreate -> onStart -> onResume的生命周期中。

3. 如果启动一个已存在的Activity,则会进入onRestart(如果之前是stopped状态,则执行onRestart;否则,从onStart开始执行) -> onStart -> onResume

b406f4b663664f71f8c5392f001f5d97.png

这种情况是启动一个已存在的Activity(之前处于paused或stopped状态,取决于其可不可见),比如从app回到桌面时,桌面的Activity经历的生命周期为onRestart(若桌面之前不可见,步骤13)-> onStart(步骤16)-> onResume(步骤18)。

至此,Activity启动过程基本完成。简单梳理一下其过程,可以将其主要逻辑概括为:

1. 客户端进程调用startActivity,通过Binder调用到system server进程中AMS模块;

2. AMS模块首先进行一些处理,其中包括:检查传递的参数是否合法,根据参数创建其对应的ActivityRecord对象,为其寻找/创建对应的TaskRecord和ActivityStack,并将其移动到前台,通知WMS模块进行相关处理等等。

3. 之后会对生命周期进行管理,首先会旧Activity会进入paused状态,AMS通过Binder通知对应客户端进程。客户端paused行为处理完后会再次通知AMS,AMS会根据新启动的Activity的不同情况(是否是可复用的Activity,是否已存在进程等)进行不同的处理。最终新的Activity都将进入resumed状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值