启动persistent应用
在Android系统中,有一种永久性应用。它们对应的AndroidManifest.xml文件里,会将persistent属性设为true,比如:
1 | <application android:name="PhoneApp" |
在系统启动之时,AMS的systemReady()会加载所有persistent为true的应用。
1 | public void systemReady(final Runnable goingCallback) |
1 | private void startPersistentApps(int matchFlags) { |
其中的STOCK_PM_FLAGS的定义如下:
1 | // The flags that are set for all calls we make to the package manager. |
上面代码中的getPersistentApplications()函数的定义如下:
\frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java
1 | @Override |
在PMS中,有一个记录所有的程序包信息的哈希表(mPackages),每个表项中含有ApplicationInfo信息,该信息的flags(int型)数据中有一个专门的bit用于表示persistent。getPersistentApplications()函数会遍历这张表,找出所有persistent包,并返回ArrayList
从代码里可以看出,带persistent标志的系统应用(即flags中设置了FLAG_SYSTEM)是一定会被选上的,但如果不是系统应用的话,则要进一步判断当前是否处于“安全模式”,一旦处于安全模式,那么就算应用设置了persistent属性,也不会被选中。
随后systemReady()开始遍历选中的ApplicationInfo,并对包名不为“android”的结点执行addAppLocked()。
1 | private void startPersistentApps(int matchFlags) { |
1 | final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated, |
在AMS中,所谓的“add App”主要是指“添加一个与App进程对应的ProcessRecord节点”。当然,如果该节点已经添加过了,那么是不会重复添加的。在添加节点的动作完成以后,addAppLocked()还会检查App进程是否已经启动好了,如果尚未开始启动,此时就会调用startProcessLocked()启动这个进程。既然addAppLocked()试图确认App“正在正常运作”或者“将被正常启动”,那么其对应的package就不可能处于stopped状态,这就是上面代码调用setPackageStoppedState(false)的意思。
现在,我们就清楚了,那些persistent属性为true的应用,基本上都是在系统启动伊始就启动起来的。
因为启动进程的过程是异步的,所以我们需要一个缓冲列表(即上面代码中的mPersistentStartingProcesses列表)来记录那些“正处于启动状态,而又没有启动完毕的”ProcessRecord结点。一旦目标进程启动完毕后,目标进程会attach系统,于是走到AMS的attachApplicationLocked(),在这个函数里,会把目标进程对应的ProcessRecord结点从mPersistentStartingProcesses缓冲列表里删除。
如何保证应用的持久性(persistent)
我们知道,persistent一词的意思是“持久”,那么persistent应用的意思又是什么呢?简单地说,这种应用会顽固地运行于系统之中,从系统一启动,一直到系统关机。
为了保证这种持久性,persistent应用必须能够在异常出现时,自动重新启动。在Android里是这样实现的。每个ActivityThread中会有一个专门和AMS通信的binder实体——final ApplicationThread mAppThread。这个实体在AMS中对应的代理接口为IApplicationThread。
当AMS执行到attachApplicationLocked()时,会针对目标用户进程的IApplicationThread接口,注册一个binder监听器,一旦日后用户进程意外挂掉,AMS就能在第一时间感知到,并采取相应的措施。如果AMS发现意外挂掉的应用是persistent的,它会尝试重新启动这个应用。
注册监听器的代码如下:
1 | private final boolean attachApplicationLocked(IApplicationThread thread,int pid) { |
其中的thread就是IApplicationThread代理。
AppDeathRecipient的定义如下:
1 | private final class AppDeathRecipient implements IBinder.DeathRecipient { |
当其监听的binder实体死亡时,系统会回调AppDeathRecipient的binderDied()。这个回调函数会辗转重启persistent应用,调用关系如下:

一般情况下,当一个应用进程挂掉后,AMS当然会清理掉其对应的ProcessRecord,这就是cleanUpApplicationRecordLocked()的主要工作。然而,对于persistent应用cleanUpApplicationRecordLocked()会尝试再次启动对应的应用进程。
现在我们可以画一张关于“启动persistent应用”的示意图:

补充知识点
persistent应用可以在系统未准备好时启动
在AMS中,有一个isAllowedWhileBooting()函数,其代码如下:
1 | boolean isAllowedWhileBooting(ApplicationInfo ai) { |
从这个函数可以看到,将persistent属性设为true的应用,是允许在boot的过程中启动的。
我们可以查看前文提到的startProcessLocked()函数:
1 | final ProcessRecord startProcessLocked(String processName, |
其中的最后几句可以改写为以下更易理解的形式:
1 | if (mProcessesReady || isAllowedWhileBooting(info) || allowWhileBooting) |
也就是说,当系统已经处于以下几种情况时,多参数的startProcessLocked()会进一步调用另一个只有三个参数的startProcessLocked():
- 系统已经处于ready状态;
- 想要启动persistent应用;
- 参数中明确指定可以在boot过程中启动应用。
补充说一下,一般情况下,当AMS调用startProcessLocked()时,传入的allowWhileBooting参数都为false。比如说,当系统需要启动“某个content provider或者某个service或者某个特定activity”时,此时传给startProcessLocked()的allowWhileBooting参数是写死为false的。只有一种特殊情况下会在该参数中传入true,那就是当系统发出的广播intent中携带有Intent.FLAG_RECEIVER_BOOT_UPGRADE标记时,此时允许在系统未ready时,启动接受广播的目标进程。