之前確實(shí)沒使用過這個(gè)屬性炉爆,前幾天在查找“怎么保證Service不被Kill”這個(gè)問題的答案時(shí),我看到有一條是“設(shè)置application的屬性persistent為true”刊头,由于不清楚它的作用和實(shí)現(xiàn)原理,于是有了這篇筆記昙篙。
在AndroidManifest.xml定義中惯殊,application有這么一個(gè)屬性android:persistent骤肛,根據(jù)字面意思來理解就是說該應(yīng)用是可持久的,也即是常駐的應(yīng)用窍蓝。其實(shí)就是這么個(gè)理解萌衬,被android:persistent修飾的應(yīng)用會在系統(tǒng)啟動之后被AMS啟動。
在系統(tǒng)啟動時(shí)它抱,ActivityManagerService會調(diào)用systemReady()方法來加載所有persistent屬性為true的應(yīng)用秕豫。
public void systemReady(final Runnable goingCallback) {
......
synchronized (this) {
// Only start up encryption-aware persistent apps; once user is
// unlocked we'll come back around and start unaware apps
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
......
}
}
private void startPersistentApps(int matchFlags) {
if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
synchronized (this) {
try {
final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"android".equals(app.packageName)) {
addAppLocked(app, false, null /* ABI override */);
}
}
} catch (RemoteException ex) {
}
}
}
上面的代碼中persistent應(yīng)用列表是通過PackageManagerService類的getPersistentApplications()方法來獲取的,方法實(shí)現(xiàn)如下:
@Override
public @NonNull ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) {
return new ParceledListSlice<>(getPersistentApplicationsInternal(flags));
}
private @NonNull List<ApplicationInfo> getPersistentApplicationsInternal(int flags) {
final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
// reader
synchronized (mPackages) {
final Iterator<PackageParser.Package> i = mPackages.values().iterator();
final int userId = UserHandle.getCallingUserId();
while (i.hasNext()) {
final PackageParser.Package p = i.next();
if (p.applicationInfo == null) continue;
final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
&& !p.applicationInfo.isDirectBootAware();
final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
&& p.applicationInfo.isDirectBootAware();
if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
&& (!mSafeMode || isSystemApp(p))
&& (matchesUnaware || matchesAware)) {
PackageSetting ps = mSettings.mPackages.get(p.packageName);
if (ps != null) {
ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
ps.readUserState(userId), userId);
if (ai != null) {
finalList.add(ai);
}
}
}
}
}
return finalList;
}
在PackageManagerService中观蓄,有一個(gè)記錄所有的程序包信息的哈希表(mPackages)混移,每個(gè)表項(xiàng)中含有ApplicationInfo信息,該信息的flags(int型)數(shù)據(jù)中有一個(gè)專門的bit用于表示persistent侮穿。getPersistentApplications()方法會遍歷這張表歌径,找出所有persistent包,并返回ArrayList<ApplicationInfo>亲茅。不過從代碼中我們看到回铛,除了有FLAG_PERSISTENT標(biāo)志的應(yīng)用,處于非安全模式或者是系統(tǒng)應(yīng)用克锣、直接啟動的應(yīng)用茵肃,滿足這些條件的應(yīng)用才會被加到persistent列表中。
接著systemReady方法會遍歷persistent列表中的ApplicationInfo袭祟,然后對包名不為“android”的ApplicationInfo執(zhí)行addAppLocked方法验残,看看addAppLocked的實(shí)現(xiàn):
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated, String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(info.processName, info.uid, true);
} else {
app = null;
}
if (app == null) {
app = newProcessRecordLocked(info, null, isolated, 0);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
// This package really, really can not be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
info.packageName, false, UserHandle.getUserId(app.uid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ info.packageName + ": " + e);
}
if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
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, abiOverride,
null /* entryPoint */, null /* entryPointArgs */);
}
return app;
}
這個(gè)方法的作用主要是添加一個(gè)與App進(jìn)程對應(yīng)的ProcessRecord節(jié)點(diǎn),如果這個(gè)節(jié)點(diǎn)已經(jīng)添加過了巾乳,那么是不會重復(fù)添加的您没。在添加節(jié)點(diǎn)的動作完成以后,addAppLocked()還會檢查App進(jìn)程是否已經(jīng)啟動好了胆绊,如果尚未開始啟動氨鹏,此時(shí)就會調(diào)用startProcessLocked()來啟動這個(gè)進(jìn)程。既然addAppLocked()試圖確認(rèn)App“正在正常運(yùn)作”或者“將被正常啟動”压状,那么其對應(yīng)的package就不可能處于stopped狀態(tài)仆抵,這就是上面代碼調(diào)用setPackageStoppedState(..., false,...)以及注釋“This package really, really can not be stopped.”的作用。
因?yàn)閱舆^程異步何缓,所以對于正在啟動但尚未啟動完成的ApplicationInfo肢础,AMS會把他們添加到一個(gè)緩沖列表中也就是mPersistentStartingProcesses這個(gè)變量中記錄,啟動一個(gè)進(jìn)程則是調(diào)用startProcessLocked方法碌廓,其中啟動代碼如下:
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
一旦啟動完成传轰,這個(gè)用戶進(jìn)程會被attach到系統(tǒng)中,這個(gè)我們看ActivityThread中的main方法就可知:
ActivityThread thread = new ActivityThread();
thread.attach(false);
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
......
} else {
......
}
......
}
attach方法中會判斷不是系統(tǒng)應(yīng)用就會調(diào)用AMS的attachApplication方法(AMS繼承自ActivityManagerNative)谷婆,在attach過程中慨蛙,ActivityThread會將對應(yīng)的application attach到AM中去辽聊,交給AM去管理,在這個(gè)方法中傳遞了一個(gè)變量mAppThread期贫,它是一個(gè)ApplicationThread對象跟匆,ApplicationThread是定義在ActivityThread類中的繼承ApplicationThreadNative的私有類,它繼承自Binder且實(shí)現(xiàn)了IApplicationThread接口通砍,所以在AMS中的關(guān)于ApplicationThread的參數(shù)都是IApplicationThread的形式玛臂,mAppThread可以看作是當(dāng)前進(jìn)程主線程的核心,它負(fù)責(zé)處理本進(jìn)程與其他進(jìn)程(主要是AM)之間的通信封孙,同時(shí)通過attachApplication將mAppThread的代理Binder傳遞給AM迹冤。接著ApplicationInfo走到attachApplicationLocked方法。
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
......
// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
final String processName = app.processName;
try {
// 注冊進(jìn)程死亡監(jiān)聽器
AppDeathRecipient adr = new AppDeathRecipient(app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
startProcessLocked(app, "link fail", processName);
return false;
}
......
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
// Remove this record from the list of starting applications.
mPersistentStartingProcesses.remove(app);
......
return true;
}
在attachApplicationLocked方法中AMS調(diào)用到了IPC通信調(diào)用mAppThread的bindApplication方法虎忌,然后將該P(yáng)rocessRecord節(jié)點(diǎn)在mPersistentStartingProcesses列表中移除泡徙。
這里又回調(diào)到了ApplicationThread類中的bindApplication方法:
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableBinderTracking = enableBinderTracking;
data.trackAllocation = trackAllocation;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
sendMessage(H.BIND_APPLICATION, data);
}
上述代碼中通過消息機(jī)制向ActivityThread自身維護(hù)的handler發(fā)送BIND_APPLICATION消息。ActivityThread自身維護(hù)的handler對消息BIND_APPLICATION的處理調(diào)用了handleBindApplication方法膜蠢,而這個(gè)方法中我們可以看到下面這條代碼:
mInstrumentation.callApplicationOnCreate(app);
這句作用是調(diào)用persistent應(yīng)用的Applicaiton中的onCreate方法堪藐。
上面說了persistent應(yīng)用的啟動過程,既然是persistent的挑围,那么當(dāng)用應(yīng)用出現(xiàn)異常時(shí)它也需要自動重啟礁竞。這里Android系統(tǒng)中實(shí)現(xiàn)自動重啟的做法是這樣的,我們回頭看看上面attachApplicationLocked方法中在bindApplication之前贪惹,會構(gòu)建一個(gè)AppDeathRecipient苏章,相當(dāng)于一個(gè)監(jiān)聽器,然后把這個(gè)監(jiān)聽器跟persistent進(jìn)程綁在一起奏瞬,由AMS來監(jiān)聽,當(dāng)persistent進(jìn)程意外死亡時(shí)泉孩,AMS就能知道硼端,并且會嘗試重新啟動這個(gè)應(yīng)用。
AppDeathRecipient的實(shí)現(xiàn)如下:
private final class AppDeathRecipient implements IBinder.DeathRecipient {
final ProcessRecord mApp;
final int mPid;
final IApplicationThread mAppThread;
AppDeathRecipient(ProcessRecord app, int pid,
IApplicationThread thread) {
if (DEBUG_ALL) Slog.v(
TAG, "New death recipient " + this
+ " for thread " + thread.asBinder());
mApp = app;
mPid = pid;
mAppThread = thread;
}
@Override
public void binderDied() {
if (DEBUG_ALL) Slog.v(
TAG, "Death received in " + this
+ " for thread " + mAppThread.asBinder());
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
當(dāng)persistent應(yīng)用意外退出時(shí)寓搬,系統(tǒng)會回調(diào)AppDeathRecipient的binderDied方法珍昨,這個(gè)方法中只會執(zhí)行appDiedLocked這個(gè)方法,而最終會執(zhí)行handleAppDiedLocked這個(gè)方法:
private final void handleAppDiedLocked(ProcessRecord app,
boolean restarting, boolean allowRestart) {
int pid = app.pid;
boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,
false /*replacingPid*/);
if (!kept && !restarting) {
removeLruProcessLocked(app);
if (pid > 0) {
ProcessList.remove(pid);
}
}
if (mProfileProc == app) {
clearProfilerLocked();
}
// Remove this application's activities from active lists.
boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
app.activities.clear();
if (app.instrumentationClass != null) {
Slog.w(TAG, "Crash of app " + app.processName
+ " running instrumentation " + app.instrumentationClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
}
if (!restarting && hasVisibleActivities
&& !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
// If there was nothing to resume, and we are not already restarting this process, but
// there is a visible activity that is hosted by the process... then make sure all
// visible activities are running, taking care of restarting this process.
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
這個(gè)方法的作用就是將進(jìn)程從ActivityManager中移除句喷,其中的變量kept是根據(jù)方法cleanUpApplicationRecordLocked的結(jié)果镣典,其意義是是否要保留這個(gè)進(jìn)程,我們看看它的實(shí)現(xiàn):
private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
......
if (!app.persistent || app.isolated) {
if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Removing non-persistent process during cleanup: " + app);
if (!replacingPid) {
removeProcessNameLocked(app.processName, app.uid);
}
if (mHeavyWeightProcess == app) {
mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
mHeavyWeightProcess.userId, 0));
mHeavyWeightProcess = null;
}
} else if (!app.removed) {
// This app is persistent, so we need to keep its record around.
// If it is not already on the pending app list, add it there
// and start a new process for it.
if (mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
restart = true;
}
}
......
if (restart && !app.isolated) {
// We have components that still need to be running in the
// process, so re-launch it.
if (index < 0) {
ProcessList.remove(app.pid);
}
addProcessNameLocked(app);
startProcessLocked(app, "restart", app.processName);
return true;
} else if (app.pid > 0 && app.pid != MY_PID) {
// Goodbye!
boolean removed;
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
}
app.setPid(0);
}
return false;
}
我們看到如果是persistent應(yīng)用且還沒有被移除唾琼,AMS會重新將它添加到mPersistentStartingProcesses這個(gè)啟動緩存列表中兄春,并再調(diào)用startProcessLocked方法重啟進(jìn)程。到此锡溯,persistent應(yīng)用的重啟機(jī)制也就說完了赶舆。
參考文章: