深入安卓
PackageManagerService
它是Android系统中最常用的服务之一。它负责系统中Package的管理,应用程序的安装、卸载、信息查询等。
它的一家老小:
分析上图:
1. IPackageManager接口类中定义了服务端和客户端通信的业务函数,还定义了内部类Stub,该类从Binder派生并实现了IPackageManager接口。
2. PackageManagerService继承自IPackageManager.Stub类,由于Stub类从Binder派生,因此PackageManagerService将作为服务端参与Binder通信。
3. Stub类中定义了一个内部类Proxy,该类有一个IBinder类型(实际类型为BinderProxy)的成员变量mRemote,mRemote用于和服务端PackageManagerService通信。
4. IPackageManager接口类中定义了许多业务函数,但是出于安全等方面的考虑,Android对外(即SDK)提供的只是一个子集,该子集被封装在抽象类PackageManager中。客户端一般通过Context的getPackageManager函数返回一个类型为PackageManager的对象,该对象的实际类型是PackageManager的子类ApplicationPackageManager。这种基于接口编程的方式,虽然极大降低了模块之间的耦合性,却给代码分析带来了不小的麻烦。
5. ApplicationPackageManager类继承自PackageManager类。它并没有直接参与Binder通信,而是通过mPM成员变量指向一个IPackageManager.Stub.Proxy类型的对象。
PKMS构造函数的主要功能是,扫描Android系统中几个目标文件夹中的APK,从而建立合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。抽象地看,PKMS像一个加工厂,它解析实际的物理文件(APK文件)以生成符合自己要求的产品。
PKMS工作流程
PKMS构造函数的工作流程大体可分三个阶段:
· 扫描目标文件夹之前的准备工作。
· 扫描目标文件夹。
· 扫描之后的工作。
该函数涉及到的知识点较多,代码段也较长,因此我们将通过分段讨论的方法,集中解决相关的重点问题。
扫描目标文件夹之前的准备工作
设置setting
进入PKMS构造函数,就会遇到第一个较为复杂的数据结构Setting及它的addSharedUserLPw函数。Setting的作用是管理Android系统运行过程中的一些设置信息,包括:字符串“android.uid.system“,UID(用户ID,),用于标识系统Package的FLAG_SYSTEM标志。
扫描文件夹并解析xml文件
创建一个Installer对象,同时并解析对应的xml文件。包括:权限,包信息等。
PKMS将扫描以下几个目录。
1. /system/frameworks:该目录中的文件都是系统库,例如framework.jar、services.jar、framework-res.apk。不过scanDirLI只扫描APK文件,所以framework-res.apk是该目录中唯一“受宠”的文件。
2. /system/app:该目录下全是默认的系统应用,例如Browser.apk、SettingsProvider.apk等。
3. /vendor/app:该目录中的文件由厂商提供,即厂商特定的APK文件,不过目前市面上的厂商都把自己的应用放在/system/app目录下。
下面总结一下Package扫描的流程:
scanDirLI用于对指定目录下的APK文件进行扫描。
扫描完APK文件后,Package的私有财产就充公了。PKMS提供了好几个重要数据结构来保存这些财产:
构造函数分析之扫尾工作
这部分任务比较简单,就是将第二阶段收集的信息再集中整理一次,比如汇总并更新和Permission相关的信息,将信息写到package.xml、package.list及package-stopped.xml文件中。
PKM的install
故事从adbinstall开始。
adb install分析
找到apk的目录位置,把相关信息发送给指定的Verification程序(另外一个APK),由它对要安装的APK进行检查(Verify)。
然后开始调用pm_command开始后续工作。
调用pm_command进行安装
在编译system.image时,Android.mk中会将该脚本复制到system/bin目录下。从pm脚本的内容来看,它就是通过app_process执行pm.jar包的main函数。app_process是一个Native进程,它通过创建虚拟机启动了Zygote,从而转变为一个Java进程。实际上,app_process还可以通过类似的方法(即先创建Dalvik虚拟机,然后执行某个类的main函数)来转变成其他Java程序。
Pm解析参数后,最终通过PKMS的Binder客户端调用installPackageWithVerification以完成后续的安装工作。
installPackageWithVerification函数倒是蛮清闲,检查下权限,然后简简单单创建几个对象,发送INIT_COPY消息给mHandler,就甩手退出了。
在mHandler中APK的安装居然需要使用另外一个APK提供的服务,该服务就是DefaultContainerService,由DefaultCotainerService.apk提供。
相关类的一家子:
HandlerParams和InstallArgs均为抽象类。
HandlerParams有三个子类,分别是InstallParams、MoveParams和MeasureParams。其中,InstallParams用于处理APK的安装,MoveParams用于处理某个已安装APK的搬家请求(例如从内部存储移动到SD卡上),MeasureParams用于查询某个已安装的APK占据存储空间的大小(例如在设置程序中得到的某个APK使用的缓存文件的大小)。
对于InstallParams来说,它还有两个伴儿,即InstallArgs的派生类FileInstallArgs和SdInstallArgs。其中,FileInstallArgs针对的是安装在内部存储的APK,而SdInstallArgs针对的是那些安装在SD卡上的APK。
在mhandler中处理请求:
1. 调用DCS的getMinimalPackageInfo函数,将得到一个PackageLite对象,该对象是一个轻量级的用于描述APK的结构(相比PackageParser.Package来说)。在这段代码逻辑中,主要想取得其recommendedInstallLocation的值。此值表示该APK推荐的安装路径。
具体步骤:通过用户在Settings数据库中设置的安装位置。检查外部存储或内部存储是否有足够空间。
2. 调用installLocationPolicy检查推荐的安装路径。例如系统Package不允许安装在SD卡上。
3. createInstallArgs将根据安装位置创建不同的InstallArgs。如果是内部存储,则返回FileInstallArgs,否则为SdInstallArgs。
4. 在正式安装前,应先对该APK进行必要的检查。
5. 调用InstallArgs的copyApk。
调用PKMS的installPackageLI函数进行APK安装,该函数内部将调用InstallArgs的doRename对临时文件进行改名。另外,还需要扫描此APK文件。
该APK已经安装完成(不论失败还是成功),继续向mHandler抛送一个POST_INSTALL消息,该消息携带一个token,通过它可从mRunningInstalls数组中取得一个PostInstallData对象
在接收到POST_INSTALL消息之后,发送PACKAGE_ADDED广播。
APK 安装流程总结
APK的安装流程竟然如此复杂,其目的无非是让APK中的私人财产公有化。
1. 安装APK到内部存储空间这一工作流程涉及的主要对象包括:PKMS、DCS、InstallParams和FileInstallArgs。
2. 此工作流程中每个对象涉及到的关键函数。
3. 对象之间的调用通过虚线表达,调用顺序通过①②③等标明。
ActivityManagerService
AMS是Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似,因此它在Android中非常重要。
AMS比较复杂,本章将带领读者按五条不同的线来分析它:
1. 第一条线:同其他服务一样,将分析SystemServer中AMS的调用轨迹。
2. 第二条线:以am命令启动一个Activity为例,分析应用进程的创建、Activity的启动,以及它们和AMS之间的交互等知识。
3. 第三条线和第四条线:分别以Broadcast和Service为例,分析AMS中Broadcast和Service的相关处理流程。
4. 第五条线:以一个Crash的应用进程为出发点,分析AMS如何打理该应用进程的身后事。
AMS的家族图谱:
AMS由ActivityManagerNative(以后简称AMN)类派生,并实现Watchdog.Monitor和BatteryStatsImpl.BatteryCallback接口。而AMN由Binder派生,实现了IActivityManager接口。
客户端使用ActivityManager类。由于AMS是系统核心服务,很多API不能开放供客户端使用,所以设计者没有让ActivityManager直接加入AMS家族。在ActivityManager类内部通过调用AMN的getDefault函数得到一个ActivityManagerProxy对象,通过它可与AMS通信。
AMS的调用轨迹
AMS由SystemServer的ServerThread线程创建,它的调用轨:
1. 调用main函数,得到一个Context对象
2. 将SystemServer进程可加到AMS中,并被它管理
3. 将ActivityManagerService的SettingsProvider放到SystemServer进程中来运行。
4. 在内部保存WindowManagerService(以后简称WMS)
Main中的调用
1. 创建AThread线程。
2. ActivityThread.systemMain函数。初始化ActivityThread对象。
3. ActivityThread.getSystemContext函数。用于获取一个Context对象,从函数名上看,该Context代表了System的上下文环境。
4. AMS的startRunning函数。
步骤1:创建AThread线程
虽然AMS的main函数由ServerThread线程调用,但是AMS自己的工作并没有放在ServerThread中去做,而是新创建了一个线程,即AThread线程。其主要工作就是创建AMS对象,然后通知AMS的main函数。
AMS构造函数的工作:
创建BSS、USS、mProcessStats (ProcessStats类型)、mProcessStatsThread线程,这些都与系统运行状况统计相关。
创建/data/system目录,为mCompatModePackages(CompatModePackages类型)和mConfiguration(Configuration类型)等成员变量赋值。
步骤2:ActivityThread.systemMain函数。初始化ActivityThread对象
它代表一个应用进程的主线程(对于应用进程来说,ActivityThread的main函数确实是由该进程的主线程执行),其职责就是调度及执行在该线程中运行的四大组件。
应用进程指那些运行APK的进程,它们由Zyote 派生(fork)而来,上面运行了dalvik虚拟机。与应用进程相对的就是系统进程(包括Zygote和SystemServer)。
前面所说的ActivityThread代表应用进程(其上运行了APK)的主线程,而SystemServer并非一个应用进程,那么为什么此处也需要ActivityThread呢?
还记得在PackageManagerService分析中提到的framework-res.apk吗?这个APK除了包含资源文件外,还包含一些Activity(如关机对话框),这些Activity实际上运行在SystemServer进程中。从这个角度看,SystemServer是一个特殊的应用进程。
通过ActivityThread可以把Android系统提供的组件之间的交互机制和交互接口(如利用Context提供的API)也拓展到SystemServer中使用。
调用systemMain函数结束后:
1. 得到一个ActivityThread对象,它代表应用进程的主线程。
2. 得到一个Context对象,它背后所指向的Application环境与framework-res.apk有关。
systemMain函数将为SystemServer进程搭建一个和应用进程一样的Android运行环境。
步骤3:ActivityThread.getSystemContext函数。用于获取一个Context对象,从函数名上看,该Context代表了System的上下文环境。
调用该函数后,将得到一个代表系统进程的Context对象。
步骤4:AMS的startRunning函数。
就是调用startRunning
总结:
AMS的main函数的目的有两个:
1. 首先也是最容易想到的目的是创建AMS对象。
2. 另外一个目的比较隐晦,但是非常重要,那就是创建一个供SystemServer进程使用的Android运行环境。
AMS的setSystemProcess
调用ActivityThread的installSystemApplicationInfo函数
installSystemApplicationInfo函数的参数为一个ApplicationInfo对象,该对象由AMS通过Context查询PKMS中一个名为“android”的package得来,目的仅仅是为了创建一个Android运行环境。
由于framework-res.apk是一个APK文件,和其他APK文件一样,它应该运行在一个进程中。而AMS是专门用于进程管理和调度的,所以运行APK的进程应该在AMS中有对应的管理结构。因此AMS下一步工作就是将这个运行环境和一个进程管理结构对应起来并交由AMS统一管理。
AMS对进程的管理
AMS中的进程管理结构是ProcessRecord。
由上图可知:
1. ApplicationThreadNative实现了IApplicationThread接口。从该接口定义的函数可知,AMS通过它可以和应用进程进行交互,例如,AMS启动一个Activity的时候会调用该接口的scheduleLaunchActivity函数。
2. ActivityThread通过成员变量mAppThread指向它的内部类ApplicationThread,而ApplicationThread从ApplicationThreadNative派生。
当AMS想要停止(stop)一个Activity时,会调用对应进程IApplicationThread Binder客户端的scheduleStopActivity函数。该函数服务端实现的就是向ActivityThread所在线程发送一个消息。在应用进程中,ActivityThread运行在主线程中,所以这个消息最终在主线程被处理。
ProcessRecord除保存和应用进程通信的IApplicationThread对象外,还保存了进程名、不同状态对应的Oom_adj值及一个ApplicationInfo。一个进程虽然可运行多个Application,但是ProcessRecord一般保存该进程中先运行的那个Application的ApplicationInfo。
保存该ProcessRecord对象
AMS中有两个成员变量用于保存ProcessRecord,一个是mProcessNames,另一个是mPidsSelfLocked,如下图所示为这两个成员变量的数据结构示意图。
AMS的setSystemProcess总结:
现在来总结回顾setSystemProcess的工作:
1. 注册AMS、meminfo、gfxinfo等服务到ServiceManager中。
2. 根据PKMS返回的ApplicationInfo初始化Android运行环境,并创建一个代表SystemServer进程的ProcessRecord,从此,SystemServer进程也并入AMS的管理范围内。
AMS的installSystemProviders
SystemServer中很多Service都需要向settings数据库查询配置信息。为此,Android提供了一个SettingsProvider来帮助开发者。该Provider在SettingsProvider.apk中,installSystemProviders就会加载该APK并把SettingsProvider放到SystemServer进程中来运行。
这里AMS向PKMS查询满足要求的ProviderInfo,最重要的查询条件包括:进程名和进程uid。同时AMS对ContentProvider进行管理(这也是查询ProviderInfo的原因)。
ASM的systemReady
可以分为三个阶段的工作:
第一阶段:
发送并处理与PRE_BOOT_COMPLETED广播相关的事情。该广播接收者的工作似乎和系统升级有关。
第二阶段:
1. 杀死那些竟然在AMS还未启动完毕就先启动的应用进程。注意,这些应用进程一定是APK所在的Java进程,因为只有应用进程才会向AMS注册,而一般Native(例如mediaserver)进程是不会向AMS注册的。
2. 从Settings数据库中获取配置信息,目前只取4个配置参数,分别是:”debug_app”(设置需要debug的app的名称)、”wait_for_debugger”(如果为1,则等待调试器,否则正常启动debug_app)、”always_finish_activities”(当一个activity不再有地方使用时,是否立即对它执行destroy)、”font_scale”(用于控制字体放大倍数,这是Android 4.0新增的功能)。以上配置项由Settings数据库的System表提供。
第三阶段:
1. 调用systemReady设置的回调对象goingCallback的run函数。
在run中,调用一些服务的systemReady函数和启动Watchdog。
2. 启动那些声明了persistent的APK。
3. 启动桌面,在Home启动成功后,AMS才发送ACTION_BOOT_COMPLETED广播。
ActivityManagerService总结
1. AMS的main函数:创建AMS实例,其中最重要的工作是创建Android运行环境,得到一个ActivityThread和一个Context对象。
2. AMS的setSystemProcess函数:该函数注册AMS和meminfo等服务到ServiceManager中。另外,它为SystemServer创建了一个ProcessRecord对象。由于AMS是Java世界的进程管理及调度中心,要做到对Java进程一视同仁,尽管SystemServer贵为系统进程,此时也不得不将其并入AMS的管理范围内。
3. AMS的installSystemProviders:为SystemServer加载SettingsProvider。
4. AMS的systemReady:做系统启动完毕前最后一些扫尾工作。该函数调用完毕后,HomeActivity将呈现在用户面前。
am命令启动一个Activity
am和pm一样,也是一个脚本,它用来和AMS交互,如启动Activity、启动Service、发送广播等。其核心文件在Am.java中。
AMS的startActivityAndWait函数分析
Task、Back Stack、ActivityStack及Launch mode
一个Acitivity的启动是由一个应用进程发起的,IApplicationThread是应用进程和AMS交互的通道,也可算是调用进程的标示。
mMainStack为AMS的成员变量,类型为ActivityStack。他通过startActivityAndWait开始启动activity。
对多Task的情况来说,系统只支持一个处于前台的Task,即用户当前看到的Activity所属的Task,其余的Task均处于后台,这些后台Task内部的Activity保持顺序不变。用户可以一次将整个Task挪到后台或者置为前台。
Task内部Activity的组织方式如下:
Android通过先入后出的方式来组织Activity。数据结构中的Stack即以这种方式工作。
为了应对多个Task的组织及管理方式,Android设计了一个ActivityStack类来负责上述工作。
Activity由ActivityRecord表示,Task由TaskRecord表示。ActivityRecord的task成员指向该Activity所在的Task。state变量用于表示该Activity所处的状态(包括INITIALIZING、RESUMED、PAUSED等状态)。
ActivityStack用mHistory这个ArrayList保存ActivityRecord。令人大跌眼镜的是,该mHistory保存了系统中所有Task的ActivityRecord,而不是针对某个Task进行保存。
ActivityStack的mMainStack成员比较有意思,它代表此ActivityStack是否为主ActivityStack。有主必然有从,但是目前系统中只有一个ActivityStack,并且它的mMainStack为true。从ActivityStack的命名可推测,Android在开发之初也想用ActivityStack来管理单个Task中的ActivityRecord(在ActivityStack.java的注释中说过,该类为“State and management of asingle stack ofactivities”),但不知何故,在现在的代码实现将所有Task的ActivityRecord都放到mHistory中了,并且依然保留mMainStack。
ActivityStack采用数组的方式保存所有Task的ActivityRecord,并且没有成员保存TaskRecord。这种实现方式少了TaskRecord一级的管理,直接以ActivityRecord为管理单元。这种做法能降低管理方面的开销。但是 缺点是弱化了Task的概念,结构不够清晰。
启动模式:分别是standard、singleTop、singleTask和singleInstance。描述的是activity之间的关系。
标志:FLAG_ACTIVITY_NEW_TASK,FLAG_ACTIVITY_CLEAR_TASK,FLAG_ACTIVITY_CLEAR_TOP。描述的是Activity和Task关系的。
startActivityAndWait
该函数的目标是启动com.dfp.test.TestActivity,假设系统之前没有启动过该Activity,则
1. 由于在am中设置了FLAG_ACTIVITY_NEW_TASK标志,因此除了会创建一个新的ActivityRecord外,还会新创建一个TaskRecord。
2. 还需要启动一个新的应用进程以加载并运行com.dfp.test.TestActivity的一个实例。
3. 如果TestActivity不是Home,还需要停止当前正在显示的Activity。
具体步骤:
1. 首先需要通过PKMS查找匹配该Intent的ActivityInfo。
2. 处理FLAG_CANT_SAVE_STATE的情况,但系统目前不支持此情况。
3. 另外,获取调用者的pid和uid。由于本例的caller为null,故所得到的pid和uid均为am所在进程的uid和pid。
4. 启动Activity的核心函数是startActivityLocked。
5. 根据返回值做一些处理,因为目标Activity要运行在一个新的应用进程中,就必须等待那个应用进程正常启动并处理相关请求
startActivityLocked
主要工作:
1. 处理sourceRecord及resultRecord。其中,sourceRecord表示发起本次请求的Activity,resultRecord表示接收处理结果的Activity(启动一个Activity肯定需要它完成某项事情,当目标Activity将事情成后,就需要告知请求者该事情的处理结果)。在一般情况下,sourceRecord和resultRecord应指向同一个Activity。
2. 处理app Switch。如果AMS当前禁止appswitch,则只能把本次启动请求保存起来,以待允许app switch时再处理。从代码中可知,AMS在处理本次请求前,会先调用doPendingActivityLaunchesLocked函数,在该函数内部将启动之前因系统禁止appswitch而保存的Pending请求。
3. 调用startActivityUncheckedLocked处理本次Activity启动请求,为新创建的ActivityRecord找到一个合适的Task。
startActivityUncheckedLocked的分析:
步骤1:确定是否需要为新的Activity创建一个Task,即是否设置FLAG_ACTIVITY_NEW_TASK标志。
步骤2:找到一个合适的Task,然后对应做一些处理。
步骤3:根据条件判断使用原有的TaskRecord还是新建一个,并调用startActivityLocked函数进行处理。
步骤4:进行Activity之间的动画切换。
总结:首先创建ActivityRecord和TaskRecord并将ActivityRecord添加到mHistory末尾,然后调用resumeTopActivityLocked启动它。
resumeTopActivityLocked分析
在当中mResumedActivity指向上一次启动的Activity,也就是当前界面显示的这个Activity,如果mHistory中没有要启动的Activity,则启动Home。
(接startActivityUncheckedLocked的分析)如果该ActivityRecord已有对应的进程存在,则只需要重启Activity。此进程还不存在,所以要先创建一个应用进程,通过startProcessLocked。
startProcessLocked分析
通过发送消息给Zygote以派生一个应用进程(应用进程)。
应用进程的创建及初始化
应用进程的入口是ActivityThread的main函数,它是在主线程中执行的。
1、在main函数内部将创建一个消息循环Loop,接着调用ActivityThread的attach函数,最终将主线程加入消息循环。
2、AMS创建一个应用进程后,会设置一个超时时间(一般是10秒)。如果超过这个时间,应用进程还没有和AMS交互,则断定该进程创建失败。所以,应用进程启动后,需要尽快和AMS交互,即调用AMS的attachApplication函数。在该函数内部将调用attachApplicationLocked。
attachApplicationLocked分析
第一步:
设置代表该应用进程的ProcessRecrod对象的一些成员变量,例如用于和应用进程交互的thread对象、进程调度优先级及oom_adj的值等。
从消息队列中撤销PROC_START_TIMEOUT_MSG。
至此,该进程启动成功。
第二步:
在generateApplicationProvidersLocked函数内部查询(根据进程名,uid确定)PKMS以获取需运行在该进程中的ContentProvider,为调用ApplicationThread的bindApplication做准备。
刚创建的这个进程并不知道自己的历史使命是什么,甚至连自己的进程名都不知道,只能设为”<pre-initialized>”。其实,Android应用进程的历史使命是AMS在其启动后才赋予它的,这一点和我们理解的一般意义上的进程不太一样。根据之前的介绍, Android的组件应该运行在Android运行环境中。创建应用进程这一步只是创建了一个能运行Android运行环境的容器。
bindApplication的功能就是创建并初始化位于该进程中的Android运行环境。
第三步:
应用进程已经准备好了Android运行环境,接着将获取ActivityStack中一个需要运行的ActivityRecord并启动,最后通知应用进程启动Activity和Service等组件,其中用于启动Activity的函数是ActivityStack.realStartActivityLocked。
ActivityStack的realStartActivityLocked分析
它里面有两个关键函数,分别是:scheduleLaunchActivity和completeResumeLocked。
scheduleLaunchActivity用于和应用进程交互,通知它启动目标Activity。
completeResumeLocked将继续AMS的处理流程。
scheduleLaunchActivity
它保存AMS发送过来的参数信息,向主线程发送消息,该消息的处理在handleLaunchActivity中进行。在其中根据ApplicationInfo得到对应的PackageInfo。
通过Java反射机制创建目标Activity,将在内部完成Activity生命周期的前两步,即调用其onCreate和onStart函数。我们的目标com.dfp.test.TestActivity创建完毕。
调用handleResumeActivity,会在其内部调用目标Activity的onResume函数。
completeResumeLocked
AMS给了应用进程10秒的时间,希望它在10秒内调用activityIdle函数。这个时间不算长,和前面AMS等待应用进程启动的超时时间一样。
在activityIdle中设置了请求超时处理。并调用activityIdleInternal函数,处理被暂停的Activity。
如果被暂停的Activity处于finishing状态(例如Activity在其onStop中调用了finish函数),则调用finishCurrentActivityLocked。否则,要调用stopActivityLocked处理暂停的Activity。
ApplicationThread的bindApplication分析
该函数将为应用进程绑定一个Application。
ApplicationThread接收到来自AMS的指令后,均会将指令中的参数封装到一个数据结构中,然后通过发送消息的方式转交给主线程去处理。BIND_APPLICATION最终将由handleBindApplication函数处理。
bindApplication函数将设置一些初始化参数,其中最重要的有:
1. 为之前的无名进程设置进程名,并初始化参数
2. 创建一个Application对象,该对象是本进程中运行的第一个Application。
3. 如果该Application有ContentProvider,则应安装它们。
总结:
在应用进程启动后,需要尽快调用AMS的attachApplication函数,该函数是这个刚呱呱坠地的应用进程第一次和AMS交互。此时的它还默默“无名”,连一个确定的进程名都没有。不过没关系,attachApplication函数将根据创建该应用进程之前所保存的ProcessRecord为其准备一切“手续”。
attachApplication准备好一切后,将调用应用进程的bindApplication函数,在该函数内部将发消息给主线程,最终该消息由handleBindApplication处理。handleBindApplication将为该进程设置进程名,初始化一些策略和参数信息等。另外,它还创建一个Application对象。同时,如果该Application声明了ContentProvider,还需要为该进程安装ContentProvider。
startActivity总结
1. 行程的起点是am。am是Android中很重要的程序。我们利用amstart命令,发起本次目标Activity的启动请求。
2. 接下来进入ActivityManagerService和ActivityStack这两个核心类。对于启动Activity来说,这段行程又可分细分为两个阶段:第一阶段的主要工作就是根据启动模式和启动标志找到或创建ActivityRecord及对应的TaskRecord;第二阶段工作就是处理Activity启动或切换相关的工作。
3. 首先AMS直接创建目标进程并运行Activity的流程,其中涉及目标进程的创建,在目标进程中Android运行环境的初始化,目标Activity的创建以及触发onCreate、onStart及onResume等其生命周期中重要函数调用等相关知识点。
4. 接着AMS先pause当前Activity,然后再创建目标进程并运行Activity的流程。其中牵扯到两个应用进程和AMS的交互,其难度之大可见一斑。