Android O Framework架构分析(一):以AMS视角看Activity启动过程

来源:互联网 发布:万国数据员工工资高吗 编辑:程序博客网 时间:2024/06/06 07:18

        在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进程):


        上面的时序图其实仅仅描述了在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
0ProfilerInfo profilerInfo
nullBundle 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的生命周期



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


        这里的步骤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的生命周期:


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

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


        这种情况为待启动的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


        这种情况是启动一个已存在的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
原创粉丝点击