前言
在android系统开发过程中,我们有时候需要配置我们的某个应用,在开机后自动启动,并在设备低内存时不被kill。
如何实现
我们可以配置应用的AndroidManifest.xml
<application android:name="PhoneApp"
android:persistent="true"//设置成persistent应用,开机自动启动,kill后自动启动。
android:label="@string/phoneAppLabel"
android:icon="@mipmap/ic_launcher_phone"
android:allowBackup="false"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
配置peristent属性。
persist应用启动流程
ActivityManagerService.java
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
traceLog.traceBegin("PhaseActivityManagerReady");
...
// Only start up encryption-aware persistent apps; once user is
// unlocked we'll come back around and start unaware apps
//启动persist应用,在启动launcher之前
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
...
if (bootingSystemUser) {
//启动luncher
mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
}
..
}
继续看startPersistentApps 函数
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, null, false, null /* ABI override */);
}
}
} catch (RemoteException ex) {
}
}
}
startPersistentApps 函数中,遍历当前系统中persistent属性的app,非android进程时执行addApplocked;
@GuardedBy("this")
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
String abiOverride) {
return addAppLocked(info, customProcess, isolated, false /* disableHiddenApiChecks */,
false /* mountExtStorageFull */, abiOverride);
}
// TODO: Move to ProcessList?
@GuardedBy("this")
final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
info.uid, true);
} else {
app = null;
}
if (app == null) {
app = mProcessList.newProcessRecordLocked(info, customProcess, isolated, 0,
new HostingRecord("added application",
customProcess != null ? customProcess : info.processName));
mProcessList.updateLruProcessLocked(app, false, null);
updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
}
// 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.setPersistent(true);
app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
}
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
mProcessList.startProcessLocked(app, new HostingRecord("added application",
customProcess != null ? customProcess : app.processName),
disableHiddenApiChecks, mountExtStorageFull, abiOverride);
}
return app;
}
addAppLocked 启动persistent应用,并配置maxAdj = PERSISTENT_PROC_ADJ = -800;
同时将app,添加到mPersistentStartingProcesses 列表中
-800 表示进程属于高优先级,当系统资源紧张时,lowmemorykiller机制回收应用时会跳过persistent进程。
重启机制
虽然我们设置了persistent 应用的adj = -800,但是并不能保证100%不会被kill,例如通过adb kill pids kill。
google 对persistent应用做了重启机制。
重启机制
android在进程启动后调用到attachApplicationLocked时会创建一个进程死亡监听器AppDeathRecipient
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
......
final String processName = app.processName;
try {
//app死亡监听器
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
mProcessList.startProcessLocked(app,
new HostingRecord("link fail", processName));
return false;
}
......
}
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() {
//当应用死亡后,调用binderDied
if (DEBUG_ALL) Slog.v(
TAG, "Death received in " + this
+ " for thread " + mAppThread.asBinder());
synchronized(ActivityManagerService.this) {
appDiedLocked(mApp, mPid, mAppThread, true);
}
}
}
// appDiedLocked
@GuardedBy("this")
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
boolean fromBinderDied) {
......
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
//处理app died
handleAppDiedLocked(app, false, true);
......
}
//hadlerAppDiedLocked
@GuardedBy("this")
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 (mProfileData.getProfileProc() == app) {
clearProfilerLocked();
}
mAtmInternal.handleAppDied(app.getWindowProcessController(), restarting, () -> {
Slog.w(TAG, "Crash of app " + app.processName
+ " running instrumentation " + app.getActiveInstrumentation().mClass);
Bundle info = new Bundle();
info.putString("shortMsg", "Process crashed.");
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
});
}
appDiedLocked()最终会执行到cleanUpApplicationRecordLocked(),我们可以看一下这个方法做了什么
@GuardedBy("this")
final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
......
} 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.
// app是mPersistentStartingProcesses 列表中的应用时,restart = true
if (mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
restart = true;
}
}
//restart = true app应用重启
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);
}
mProcessList.addProcessNameLocked(app);
app.pendingStart = false;
mProcessList.startProcessLocked(app,
new HostingRecord("restart", app.processName));
return true;
我们看到发现是persistent应用时,设置restart = true,并调用重启。