Service生命周期时序图
Service.onCreate()←ApplicationThreadProxy.scheduleCreateService()←realStartServiceLocked()
调用scheduleCreateService()前会调用bumpServiceExecutingLocked()
Service.onBind()/onRebind()←ApplicationThreadProxy.scheduleBindService()←
requestServiceBindingLocked()
调用 scheduleBindService()前会调用bumpServiceExecutingLocked()
Service.onStartCommand←ApplicationThreadProxy.scheduleServiceArgs()←sendServiceArgsLocked()
调用 scheduleServiceArgs()前会调用bumpServiceExecutingLocked()
Service.onUnbind()←ApplicationThreadProxy.scheduleUnbindService()←removeConnectionLocked()
调用 scheduleUnbindService()前会调用bumpServiceExecutingLocked()
Service.onDestroy()←ApplicationThreadProxy.scheduleStopService()←bringDownServiceLocked()
调用 scheduleStopService()前会调用bumpServiceExecutingLocked()
ActiveServices.bumpServiceExecutingLocked()→
ActiveServices.scheduleServiceTimeoutLocked()→…→
ActiveServices.serviceTimeout()→…→
ActivityManagerSerivce.appNotResponding()→…→
Dialog.show()
ActiveServices.java
static final int SERVICE_TIMEOUT = 20*1000;
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
final ActivityManagerService mAm;
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
long now = SystemClock.uptimeMillis();
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg,
proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
...
if (anrMessage != null) {
mAm.appNotResponding(proc, null, null, false, anrMessage);
}
}
ActivityManagerService.java
final MainHandler mHandler;
final class MainHandler extends Handler {
public MainHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case SERVICE_TIMEOUT_MSG: {
...
mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;
}
}
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, boolean aboveSystem, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
...
synchronized (this) {
// PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.
if (mShuttingDown) {
Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
return;
} else if (app.notResponding) {
//已经弹出ANR,再次ANR直接return
Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
return;
} else if (app.crashing) {
Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
return;
}
// In case we come through here for the same app before completing
// this one, mark as anring now so we will bail out.
//标记ANR,避免多次执行
app.notResponding = true;
// Log the ANR to the event log.
EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
app.processName, app.info.flags, annotation);
// Dump thread traces as quickly as we can, starting with "interesting" processes.
firstPids.add(app.pid);
int parentPid = app.pid;
if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
if (parentPid != app.pid) firstPids.add(parentPid);
if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord r = mLruProcesses.get(i);
if (r != null && r.thread != null) {
int pid = r.pid;
if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
if (r.persistent) {
firstPids.add(pid);
} else {
lastPids.put(pid, Boolean.TRUE);
}
}
}
}
}
// Log the ANR to the main log.
StringBuilder info = new StringBuilder();
info.setLength(0);
info.append("ANR in ").append(app.processName);
if (activity != null && activity.shortComponentName != null) {
info.append(" (").append(activity.shortComponentName).append(")");
}
info.append("\\n");
info.append("PID: ").append(app.pid).append("\\n");
if (annotation != null) {
info.append("Reason: ").append(annotation).append("\\n");
}
if (parent != null && parent != activity) {
info.append("Parent: ").append(parent.shortComponentName).append("\\n");
}
final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
NATIVE_STACKS_OF_INTEREST);
String cpuInfo = null;
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
synchronized (mProcessCpuTracker) {
cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
}
info.append(processCpuTracker.printCurrentLoad());
info.append(cpuInfo);
}
info.append(processCpuTracker.printCurrentState(anrTime));
Slog.e(TAG, info.toString());
if (tracesFile == null) {
// There is no trace file, so dump (only) the alleged culprit's threads to the log
Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
}
addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, null);
...
// Unless configured otherwise, swallow ANRs in background processes & kill the process.
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
synchronized (this) {
mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
app.kill("bg anr", true);
return;
}
// Set the app's notResponding state, and look up the errorReportReceiver
makeAppNotRespondingLocked(app,
activity != null ? activity.shortComponentName : null,
annotation != null ? "ANR " + annotation : "ANR",
info.toString());
// Bring up the infamous App Not Responding dialog
Message msg = Message.obtain();
HashMap<String, Object> map = new HashMap<String, Object>();
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
msg.arg1 = aboveSystem ? 1 : 0;
map.put("app", app);
if (activity != null) {
map.put("activity", activity);
}
mUiHandler.sendMessage(msg);
}
}
final class UiHandler extends Handler {
public UiHandler() {
super(com.android.server.UiThread.get().getLooper(), null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case SHOW_NOT_RESPONDING_MSG: {
synchronized (ActivityManagerService.this) {
HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
ProcessRecord proc = (ProcessRecord)data.get("app");
if (proc != null && proc.anrDialog != null) {
Slog.e(TAG, "App already has anr dialog: " + proc);
return;
}
Intent intent = new Intent("android.intent.action.ANR");
if (!mProcessesReady) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY| Intent.FLAG_RECEIVER_FOREGROUND);
}
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */);
if (mShowDialogs) {
Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
mContext, proc, (ActivityRecord)data.get("activity"),
msg.arg1 != 0);
d.show();
proc.anrDialog = d;
} else {
// Just kill the app if there is no dialog to be shown.
killAppAtUsersRequest(proc, null);
}
}
ensureBootCompleted();
} break;
}
}
}
Service在执行完生命周期方法后都会通知ActivityManagerService执行serviceDoneExecuting()(这一步我并没有在时序图里画出来,实在太多了)
serviceDoneExecuting()内部会移除超时msg,所以如果超过20s(后台服务200s,默认当然是后台服务)还没收到这个通知,那么超时msg就进入handleMessage
ActivityManagerService.serviceDoneExecuting()→
ActiveServices.serviceDoneExecutingLocked()
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
...
if (r.executeNesting <= 0) {
if (r.app != null) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortName);
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {//app没有正在执行的service
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}
...
}