Android5.1.1源码 - App服务进程被杀后自动重启的原因
@(Android研究)[App服务重启]
[TOC]
前言
当通过长按HOME键的方式
清理一个App时,不仅这个App进程会被杀掉,与这个App相关的服务进程也会被杀掉,但是服务进程被杀后会被系统重启,在下文中分析了重启的原因。
分析
长按HOME键清理App最终会执行到ActivityManagerService.cleanUpRemovedTaskLocked方法中,ActivityManagerService类在文件"frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java"中,下面是ActivityManagerService.cleanUpRemovedTaskLocked方法的源码:
private void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess) {
mRecentTasks.remove(tr);
tr.removedFromRecents();
ComponentName component = tr.getBaseIntent().getComponent();
if (component == null) {
Slog.w(TAG, "No component for base intent of task: " + tr);
return;
}
......
// Find any running services associated with this app and stop if needed.
mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));
// Kill the running processes.
for (int i = 0; i < procsToKill.size(); i++) {
ProcessRecord pr = procsToKill.get(i);
if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
pr.kill("remove task", true);
} else {
pr.waitingToKill = "remove task";
}
}
}
mServices是ActiveServices类的对象,mServices.cleanUpRemovedTaskLocked(...)
语句杀掉了与app相关的服务进程,在执行完ActiveServices.cleanUpRemovedTaskLocked方法后,就会调用pr.kill
方法杀掉app进程和app所属进程组中所有的进程。关于杀掉app所属进程组所有进程的分析可以看这篇文章:Android5.1.1源码 - App进程被杀后与App相关的所有服务进程均被杀的原因。本文主要分析ActiveServices.cleanUpRemovedTaskLocked
方法做了什么。
ActiveServices类的源码在文件"frameworks/base/services/core/java/com/android/server/am/ActiveServices.java"中,下面是ActiveServices.cleanUpRemovedTaskLocked方法的源码:
void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
ArrayMap<ComponentName, ServiceRecord> alls = getServices(tr.userId);
for (int i=0; i<alls.size(); i++) {
ServiceRecord sr = alls.valueAt(i);
if (sr.packageName.equals(component.getPackageName())) {
services.add(sr);
}
}
// Take care of any running services associated with the app.
for (int i=0; i<services.size(); i++) {
ServiceRecord sr = services.get(i);
if (sr.startRequested) {
if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) {
Slog.i(TAG, "Stopping service " + sr.shortName + ": remove task");
stopServiceLocked(sr);
} else {
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
sr.makeNextStartId(), baseIntent, null));
if (sr.app != null && sr.app.thread != null) {
// We always run in the foreground, since this is called as
// part of the "remove task" UI operation.
sendServiceArgsLocked(sr, true, false);
}
}
}
}
}
这个方法先获得了所有的服务,然后将包名与"component.getPackageName()"相等的服务保存到了services中。
遍历services,sr.startRequested为true表明这个服务已经启动,当sr.serviceInfo.flags设置了ServiceInfo.FLAG_STOP_WITH_TASK标识时,会调用stopServiceLocked方法停止服务,如果调用了stopServiceLocked方法那么这个服务就不会再重启了
。
什么情况下会设置ServiceInfo.FLAG_STOP_WITH_TASK标识哪?当App的AndroidManifest.xml中服务标签被设置了android:stopWithTask="true"
,那么sr.serviceInfo.flags会被设置ServiceInfo.FLAG_STOP_WITH_TASK标识,下面是一个例子:
<service android:stopWithTask="true" android:name=".MyService" android:process=":myservice" />
回到ActiveServices.cleanUpRemovedTaskLocked方法中,当sr.serviceInfo.flags没有设置ServiceInfo.FLAG_STOP_WITH_TASK标识时,会执行下面的代码:
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
sr.makeNextStartId(), baseIntent, null));
if (sr.app != null && sr.app.thread != null) {
// We always run in the foreground, since this is called as
// part of the "remove task" UI operation.
sendServiceArgsLocked(sr, true, false);
}
sr.pendingStarts.add(...)语句添加了要重启的服务信息,然后调用sendServiceArgsLocked方法重启服务。