Android AMS 攻略

117 阅读12分钟

攻略大全

1. 粘贴攻略

2. 造火箭攻略

3. 拧螺丝攻略

3.1 Android8.0的AMS家族

在Activity的启动过程中会调用Instrumentation的execStartActivity方法,如下所示:

image.png

ActivityManager的getService方法,如下所示:

image.png

getService方法调用了IActivityManagerSingleton的get方法,IActivityManagerSingleton是一个Singleton类。

在注释1处得到名为“activity”的Service引用(Context.ACTIVITY_SERVICE的值为“activity”),也就是IBinder类型的AMS的引用。

接着在注释2处将它转换成IActivityManager类型的对象,这段代码采用的是AIDL,IActivityManager.java类是由AIDL工具在编译时自动生成的,IActivityManager.aidl的文件路径为frameworks/base/core/java/android/app/IActivityManager.aidl。

我们回到Instrumentation的execStartActivity方法,在注释1处实际上调用的是AMS的execStartActivity方法。

Android 8.0的AMS家族,如图所示。

image.png

3.2 AMS的启动过程

AMS的启动是在SystemServer进程中启动的,如下所示:

image.png

main方法只调用了SystemServer的run方法,如下所示:

image.png

在注释1处加载了动态库libandroid_servers.so。

接下来在注释2处创建SystemServiceManager,它会对系统的服务进行创建、启动和生命周期管理。

在注释3处的startBootstrapServices方法中用SystemServiceManager启动了ActivityManagerService、PowerManagerService、PackageManagerService 等服务。

在注释4处的startCoreServices 方法中则启动了DropBoxManagerService、BatteryService、UsageStatsService和WebViewUpdateService。

在注释5处的startOtherServices 方法中启动了CameraService、AlarmManagerService、VrManagerService等服务。

这些服务的父类均为SystemService。从注释3、注释4、注释5处的方法可以看出,官方把系统服务分为了3种类型,分别是引导服务、核心服务和其他服务,其中其他服务是一些非紧要和不需要立即启动的服务。

我们主要来查看引导服务AMS是如何启动的,注释3处的startBootstrapServices方法如下所示:

image.png 在注释1处调用了SystemServiceManager的startService方法,该方法的参数是ActivityManagerService.Lifecycle.class:

image.png 传入的SystemService类型的service对象的值为ActivityManagerService.Lifecycle.class。

在注释1处将service对象添加到ArrayList类型的mServices中来完成注册。

在注释2处调用service的onStart方法来启动service对象,这个service对象具体指的是什么呢?我们接着往下看,Lifecycle是AMS的内部类,代码如下所示:

image.png

上面的代码需要结合SystemServiceManager的startService方法来分析。

注释1处,在Lifecycle的构造方法中创建了AMS实例。

当调用SystemService类型的service的onStart方法时,实际上是调用了注释2处AMS的start方法。

注释3处的Lifecycle的getService方法返回AMS实例,

这样我们就知道SystemServer的startBootstrapServices方法的注释1处mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService()实际得到的就是AMS实例,AMS的启动过程就讲到这里。

3.3 AMS与应用程序进程

要启动一个应用程序,首先要保证这个应用程序所需要的应用程序进程已经存在。在启动应用程序时AMS会检查这个应用程序需要的应用程序进程是否存在,不存在就会请求Zygote进程创建需要的应用程序进程。

这里以Service的启动过程为例,来分析AMS与应用程序进程的关系。Service在启动过程中会调用ActiveServices的bringUpServiceLocked方法,如下所示:

image.png

在注释1处得到ServiceRecord的processName的值并赋值给procName,其中processName用来描述Service想要在哪个进程运行,默认是当前进程,我们也可以在AndroidManifest文件中设置android:process属性来新开启一个进程运行Service。

在注释2处将procName和Service的uid传入到AMS的getProcessRecordLocked方法中,来查询是否存在一个与Service对应的ProcessRecord类型的对象app,ProcessRecord主要用来描述运行的应用程序进程的信息。

在注释5处判断Service对应的app为null则说明用来运行Service的应用程序进程不存在,则调用注释6处的AMS的startProcessLocked方法来创建对应的应用程序进程。

在注释3处判断如果用来运行Service的应用程序进程存在,则调用注释4处的realStartServiceLocked方法来启动Service。

总结一下,AMS与应用程序进程的关系主要有以下两点:

  • 启动应用程序时AMS会检查这个应用程序需要的应用程序进程是否存在。
  • 如果需要的应用程序进程不存在,AMS就会请求Zygote进程创建需要的应用程序进程。

3.4 AMS重要的数据结构

3.4.1 解析ActivityRecord

ActivityRecord的内部记录了Activity的所有信息,因此它用来描述一个Activity,它是在启动Activity 时被创建的,具体是在ActivityStarter 的startActivity方法中被创建的。

关于ActivityRecord的部分重要成员变量:

image.png

从上表可以看出ActivityRecord的作用,其内部存储了Activity的所有信息,包括AMS的引用、AndroidManifes节点信息、Activity状态、Activity资源信息和Activity进程相关信息等。

需要注意的是其中含有该ActivityRecord所在的TaskRecord,这就将ActivityRecord和TaskRecord关联在一起,它们是Activity任务栈模型的重要成员,我们接着来查看TaskRecord。

3.4.2 解析TaskRecord

TaskRecord 用来描述一个Activity任务栈,其内部也有很多的成员变量,这里挑出一些重要的成员变量进行介绍,如下表所示。

image.png

从上表可以发现TaskRecord的作用,其内部存储了任务栈的所有信息,包括任务栈的唯一标识符、任务栈的倾向性、任务栈中的Activity记录和AMS的引用等。

需要注意的是其中含有ActivityStack,也就是当前Activity任务栈所归属的ActivityStack,我们接着来查看ActivityStack。

3.4.3 解析ActivityStack

ActivityStack是一个管理类,用来管理系统所有Activity,其内部维护了Activity的所有状态、特殊状态的Activity以及和Activity 相关的列表等数据。

ActivityStack 是由ActivityStackSupervisor来进行管理的,而ActivityStackSupervisor在AMS的构造方法中被创建,如下所示:

image.png

3.4.3.1 ActivityStack的实例类型

在ActivityStackSupervisor中有多种ActivityStack实例,如下所示:

image.png

mHomeStack用来存储Launcher App的所有Activity,mFocusedStack表示当前正在接收输入或启动下一个Activity的所有Activity。mLastFocusedStack表示此前接收输入的所有Activity。

通过ActivityStackSupervisor提供了获取上述ActivityStack 的方法,比如要获取mFocusedStack,只需要调用ActivityStackSupervisor的getFocusedStack方法就可以了:

image.png

3.4.3.2 ActivityState

在ActivityStack中通过枚举存储了Activity的所有的状态,如下所示:

image.png

通过名称我们可以很轻易知道这些状态所代表的意义。应用ActivityState 的场景会有很多,比如下面的代码:

image.png

overridePendingTransition 方法用于设置Activity的切换动画,在注释1处可以看到只有ActivityState 为RESUMED状态或者PAUSING状态时才会调用WMS类型的mWindowManager对象的overridePendingAppTransition方法来切换动画。

3.4.3.3 特殊状态的Activity

在ActivityStack中定义了一些特殊状态的Activity,如下所示:

image.png

这些特殊的状态都是ActivityRecord类型的,ActivityRecord用来记录一个Activity的所有信息。

3.4.3.4 维护的ArrayList

在ActivityStack 中维护了很多ArrayList,这些ArrayList中的元素类型主要有ActivityRecord和TaskRecord,如下表所示。

image.png

ActivityStack维护了元素类型为TaskRecord的列表,这样ActivityStack和TaskRecord就有了关联,Activity 任务栈存储在ActivityStack 中。

3.5 Activity栈管理

3.5.1 Activity任务栈模型

image.png

ActivityRecord 用来记录一个Activity 的所有信息,TaskRecord 中包含了一个或多个ActivityRecord,TaskRecord用来表示Activity的任务栈,用来管理栈中的ActivityRecord,ActivityStack又包含了一个或多个TaskRecord,它是TaskRecord的管理者。

Activity栈管理就是建立在Activity任务栈模型之上的,有了栈管理,我们可以对应用程序进行操作,应用可以复用自身应用中以及其他应用的Activity,节省了资源。

比如我们使用一款社交应用,这个应用的联系人详情界面提供了联系人的邮箱,当我们点击邮箱时会跳到发送邮件的界面,如图所示。

image.png

社交应用和系统E-mail中的Activity是处于不同应用程序进程的,而有了栈管理,就可以把发送邮件界面放到社交应用中详情界面所在栈的栈顶,来做到跨进程操作。为了更灵活地进行栈管理,Android系统提供了很多配置,包括Launch Mode、Intent的FLAG和taskAffinity等。

3.5.2 LaunchMode

LaunchMode用于设定Activity的启动方式,无论是哪种启动方式,所启动的Activity都会位于Activity栈的栈顶,主要有以下4种Launch Mode。

  • standerd:默认模式,每次启动Activity都会创建一个新的Activity实例。

  • singleTop:如果要启动的Activity 已经在栈顶,则不会重新创建Activity,同时该Activity的onNewIntent方法会被调用。如果要启动的Activity不在栈顶,则会重新创建该Activity的实例。

  • singleTask:如果要启动的Activity已经存在于它想要归属的栈中,那么不会创建该Activity实例,将栈中位于该Activity上的所有的Activity出栈,同时该Activity的onNewIntent方法会被调用。如果要启动的Activity不存在于它想要归属的栈中,并且该栈存在,则会重新创建该Activity 的实例。如果要启动的Activity 想要归属的栈不存在,则首先要创建一个新栈,然后创建该Activity实例并压入到新栈中。

  • singleInstance:和singleTask基本类似,不同的是启动Activity时,首先要创建一个新栈,然后创建该Activity实例并压入新栈中,新栈中只会存在这一个Activity实例。

3.5.3 Intent的FLAG

在Intent中定义了很多FLAG,其中有几个FLAG也可以设定Activity的启动方式,如果LaunchMode和FLAG设定的Activity的启动方式有冲突,则以FLAG设定的为准。

· FLAG_ACTIVITY_SINGLE_TOP:和Launch Mode中的singleTop效果是一样的。· FLAG_ACTIVITY_NEW_TASK:和Launch Mode中的singleTask效果是一样的。· FLAG_ACTIVITY_CLEAR_TOP:在Launch Mode中没有与此对应的模式,如果要启动的Activity已经存在于栈中,则将所有位于它上面的Activity出栈。singleTask默认具有此标记位的效果。

  • FLAG_ACTIVITY_NO_HISTORY:Activity一旦退出,就不会存在于栈中。同样地,也可以在AndroidManifest.xml中设置android:noHistory。

  • FLAG_ACTIVITY_MULTIPLE_TASK:需要和FLAG_ACTIVITY_NEW_TASK一同使用才有效果,系统会启动一个新的栈来容纳新启动的Activity。

  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:Activity 不会被放入到“最近启动的Activity”列表中。

  • FLAG_ACTIVITY_BROUGHT_TO_FRON T:这个标志位通常不是由应用程序中的代码设置的,而是Launch Mode为singleTask时,由系统自动加上的。

  • FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY:这个标志位通常不是由应用程序中的代码设置的,而是从历史记录中启动的(长按Home键调出)。

  • FLAG_ACTIVITY_CLEAR_TASK:需要和FLAG_ACTIVITY_NEW_TASK 一同使用才有效果,用于清除与启动的Activity相关栈的所有其他Activity。

接下来通过系统源码来查看FLAG 的应用,查看ActivityStarter的startActivityUnchecked方法,如图所示:

image.png

image.png

image.png

在注释1处用于初始化启动Activity 的各种配置,在初始化前会重置各种配置再进行配置,这些配置包括ActivityRecord、Intent、TaskRecord和LaunchFlags(Activity 启动的FLAG)等。

注释2处的computeLaunchingTaskFlags方法用于计算出Activity启动的FLAG,并将计算的值赋值给mLaunchFlags。

在注释3处将mLaunchFlags设置给Intent,达到设定Activity的启动方式的目的。

接着来查看computeLaunchingTaskFlags方法:

image.png

计算启动的FLAG的逻辑比较复杂,这里只截取了一小部分,当注释1处的TaskRecord类型的mInTask为null时,说明Activity要加入的栈不存在,因此,这一小段代码主要解决的问题就是Activity 要加入的栈不存在时如何计算出启动的FLAG。

在注释2处,ActivityRecord类型的mSourceRecord用于描述“初始Activity”,什么是“初始Activity”呢?比如ActivityA启动了ActivityB,ActivityA就是初始Activity。

同时满足注释2和注释3的条件则需要创建一个新栈。

在注释4处,如果“初始Activity”所在的栈只允许有一个Activity实例,则也需要创建一个新栈。

在注释5处,如果LaunchMode设置了singleTask或singleInstance,则也要创建一个新栈。

3.5.4 taskAffinity

我们可以在AndroidManifest.xml中设置android:taskAffinity,用来指定Activity希望归属的栈,在默认情况下,同一个应用程序的所有的Activity 都有着相同的taskAffinity。

taskAffinity在下面两种情况时会产生效果。

  • (1)taskAffinity与FLAG_ACTIVITY_NEW_TASK或者singleTask配合。

    如果新启动Activity的taskAffinity和栈的taskAffinity相同则加入到该栈中;如果不同,就会创建新栈。

  • (2)taskAffinity与allowTaskReparenting配合。

    如果allowTaskReparenting为true,说明Activity 具有转移的能力。拿此前的邮件为例,当社交应用启动了发送邮件的Activity,此时发送邮件的Activity是和社交应用处于同一个栈中的,并且这个栈位于前台。如果发送邮件的Activity的allowTaskReparenting设置为true,此后E-mail应用所在的栈位于前台时,发送邮件的Activity 就会由社交应用的栈中转移到与它更亲近的邮件应用(taskAffinity相同)所在的栈中,如下图所示。

image.png

接着通过系统源码来查看taskAffinity的应用。ActivityStackSupervisor的findTaskLocked方法用于找到Activity最匹配的栈,最终会调用ActivityStack的findTaskLocked方法:

image.png

image.png

这个方法的逻辑比较复杂,这里截取了和taskAffinity 相关的部分。

在注释1处遍历mTaskHistory列表,列表的元素为TaskRecord,它用于存储没有被销毁的栈。

在注释2处得到某一个栈的信息。

在注释3处将栈的rootAffinity(初始的taskAffinity)和目标Activity的taskAffinity做对比,如果相同,则将FindTaskResult的matchedByRootAffinity 属性设置为true,说明找到了匹配的栈。

4. 复制攻略

4.1 《Android进阶解密》