一、标识persistent=”true”的app启动过程 在源码/frameworks/base/core/res/res/values/attrs_manifest.xml中这样描述:
1 2 3 4 <!-- Flag to control special persistent mode of an application. This should not normally be used by applications; it requires that the system keep your application running at all times. --> <attr name="persistent" format="boolean" />
配置该属性的app有如下特点:
* 在android系统启动的时候会自动启动;
* app被强制杀掉后,系统会重新启动app,app必须安装在/system/app路径下。
app在安装或者系统启动的时候解析androidmanifest.xml文件中的persistent属性,解析源码在/frameworks/base/core/java/com/android/content/pm/PackageParser.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private boolean parseBaseApplication(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException, IOException { // ............ if ((flags&PARSE_IS_SYSTEM) != 0) { if (sa.getBoolean( com.android.internal .R.styleable.AndroidManifestApplication_persistent, false)) { ai.flags |= ApplicationInfo.FLAG_PERSISTENT; } } // ............ }
系统启动,在systemReady()加载所有persistent=true的应用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public void systemReady(final Runnable goingCallback) { // ............ try { List apps = AppGlobals.getPackageManager() .getPersistentApplications(STOCK_PM_FLAGS); if (apps != null) { int N = apps.size(); int i; for (i=0; i<N; i++) { ApplicationInfo info = (ApplicationInfo)apps.get(i); if (info != null && !info.packageName.equals("android")) { addAppLocked(info, false); } } } } catch (RemoteException ex) { // pm is in same process, this will never happen. } }
其中 getPersistentApplications()函数的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public List<ApplicationInfo> getPersistentApplications(int flags) { final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>(); // reader synchronized (mPackages) { final Iterator<PackageParser.Package> i = mPackages.values().iterator(); final int userId = UserId.getCallingUserId(); while (i.hasNext()) { final PackageParser.Package p = i.next(); if (p.applicationInfo != null && (p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p))) { PackageSetting ps = mSettings .mPackages.get(p.packageName); finalList.add(PackageParser.generateApplicationInfo(p, flags, ps != null ? ps.getStopped(userId) : false, ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, userId)); } } } return finalList; }
在PKMS中,有一个记录所有的程序包信息的哈希表(mPackages),每个表项中含有ApplicationInfo信息,该信息的flags(int型)数据中有一个专门的bit用于表示persistent。getPersistentApplications()函数会遍历这张表,找出所有persistent包,如果选中的persistent包是系统应用,或者当前系统处于非安全模式,则将persistent包添加到ArrayList。
随后systemReady()开始遍历选中的ApplicationInfo,并对包名不为“android”的结点执行addAppLocked()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(info.processName, info.uid); } else { app = null; } if (app == null) { app = newProcessRecordLocked(null, info, null, isolated); mProcessNames.put(info.processName, app.uid, app); if (isolated) { mIsolatedProcesses.put(app.uid, app); } updateLruProcessLocked(app, true, true); } // This package really, really can not be stopped. try { AppGlobals .getPackageManager() .setPackageStoppedState( info.packageName, false, UserId.getUserId(app.uid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " + info.packageName + ": " + e); } if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) { app.persistent = true; app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ; } if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); startProcessLocked(app, "added application", app.processName); } return app; }
在AMS中,所谓的“add App”主要是指“添加一个与App进程对应的ProcessRecord节点”。在添加节点的动作完成以后,addAppLocked()还会检查App进程是否已经启动好了,如果尚未开始启动,此时就会调用startProcessLocked()启动这个进程。既然addAppLocked()试图确认App“正在正常运作”或者“将被正常启动”,那么其对应的package就不可能处于stopped状态。
自此,我们已知设置了persistent=”true”的应用是随着系统启动就即时启动了。
二、如何保持应用的持久性(persistent) 本身persistent一词翻译过来即持久、固执的意思。在android系统内,persistent应用会随着系统启动而启动,一直持续到系统关机。 为了保证这种持久性,persistent应用必须能够在异常出现时,自动重新启动。在Android里是这样实现的。每个ActivityThread中会有一个专门和AMS通信的binder实体——final ApplicationThread mAppThread。这个实体在AMS中对应的代理接口为IApplicationThread。 当AMS执行到attachApplicationLocked()时,会针对目标用户进程的IApplicationThread接口,注册一个binder讣告监听器,一旦日后用户进程意外挂掉,AMS就能在第一时间感知到,并采取相应的措施。如果AMS发现意外挂掉的应用是persistent的,它会尝试重新启动这个应用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private final class AppDeathRecipient implements IBinder.DeathRecipient { final ProcessRecord mApp; final int mPid; final IApplicationThread mAppThread; AppDeathRecipient(ProcessRecord app, int pid, IApplicationThread thread) { if (localLOGV) Slog.v(TAG, "New death recipient " + this + " for thread " + thread.asBinder()); mApp = app; mPid = pid; mAppThread = thread; } public void binderDied() { if (localLOGV) Slog.v(TAG, "Death received in " + this + " for thread " + mAppThread.asBinder()); synchronized(ActivityManagerService.this) { appDiedLocked(mApp, mPid, mAppThread); } } }
当其监听的binder实体死亡时,系统会回调AppDeathRecipient的binderDied()。
image
一般情况下,当一个应用进程挂掉后,AMS当然会清理掉其对应的ProcessRecord,这就是cleanUpApplicationRecordLocked()的主要工作。然而,对于persistent应用,cleanUpApplicationRecordLocked()会尝试再次启动对应的应用进程。