在前面的一篇文章中,分析了Broadcast Timeout的流程,接下來繼續分析Service Timeout的流程。Service默認不會運行在子線程中,它也不會運行在一個獨立的進程中,它一樣執行在UI線程中,所以也不能在Service中執行耗時操做,不然也會產生的ANR。java
Service Timeout總體流程以下圖所示:app
1.startService(ContextImpl.java)post
/*
* 啓動服務
*/
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, mUser);
}
private ComponentName startServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);//驗證Service的Intent
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());//調用AMS的start方法
........
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
2.startService(ActivityManagerService.java)
在ActivityManagerService.java類中
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
......
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);//調用ActiveServices的startServiceLocked方法
Binder.restoreCallingIdentity(origId);
return res;
}
}
3.startServiceLocked(ActiveServices.java)
在ActiveServices.java類中
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, String callingPackage, final int userId)
throws TransactionTooLargeException {
final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
.........
//調用者不是處於後臺線程組中
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
.......
ServiceRecord r = res.record;
......
//準備startService參數
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants));
......
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
r.callStart = false;
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
//調用bringUpServiceLocked方法將服務調起
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
.......
return r.name;
}
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
......
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
......
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
//調用realStartServiceLocked方法啓動服務
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
........
}
........
}
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
.......
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
//開始監控onCreate方法執行時長
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
mAm.updateOomAdjLocked();
boolean created = false;
try {
......
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
//開始Service的onCreate流程
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
......
} finally {
......
}
......
//開始Service的onBind流程
requestServiceBindingsLocked(r, execInFg);
......
//開始Service的onStart流程
sendServiceArgsLocked(r, execInFg, true);
......
}
4.bumpServiceExecutingLocked(ActiveServices.java)
/*
* 記錄服務方法執行開始時間,並開始監控服務方法執行是否超時
*/
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
......
long now = SystemClock.uptimeMillis();//記錄當前方法執行的開始時間
if (r.executeNesting == 0) {
r.executeFg = fg;
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
if (r.app.executingServices.size() == 1) {
//服務方法首次執行時,調用該方法
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
//服務方法非首次執行時,調用該方法
scheduleServiceTimeoutLocked(r.app);
}
r.executeFg |= fg;//記錄服務是否在前臺執行
r.executeNesting++;//記錄服務執行方法的次數
r.executingStart = now;//記錄服務方法執行的開始時間
}
在執行服務的生命週期方法時,會調用bumpServiceExecutingLocked來監控服務方法執行是否超時,該方法最終調用scheduleServiceTimeoutLocked方法來發送SERVICE_TIMEOUT_MSG消息到ActivityManagerService中。
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
......
long now = SystemClock.uptimeMillis();
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
//發送消息到AMS中,並添加延遲時間,若是是前臺服務,則超時時間爲20s,若是是後臺服務,則超時時間爲200s
mAm.mHandler.sendMessageAtTime(msg,
proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}
//服務超時時間爲20s
static final int SERVICE_TIMEOUT = 20*1000;
//在後臺線程組中服務超時時間爲200s
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
5.handleMessage方法(ActivityManagerService.java)
ActivityManagerService接收到scheduleServiceTimeoutLocked方法發送過來的SERVICE_TIMEOUT_MSG消息後,調用ActiveServices的serviceTimeout方法發送ANR消息
public void handleMessage(Message msg) {
case SERVICE_TIMEOUT_MSG: {
......
mServices.serviceTimeout((ProcessRecord)msg.obj);//調用ActiveServices的serviceTimeOut()方法
} break;
}
6.serviceTimeout方法(ActiveServices.java)
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
synchronized(mAm) {
......
final long now = SystemClock.uptimeMillis();
//計算當前時間減去服務超時時間
final long maxTime = now -
(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = null;
long nextTime = 0;
//遍歷服務執行方法列表,若是有方法執行時間超過服務執行超時最大時間,則發送ANR消息
for (int i=proc.executingServices.size()-1; i>=0; i--) {
ServiceRecord sr = proc.executingServices.valueAt(i);
//服務執行開始時間小於maxTime,則說明服務已經超時了
if (sr.executingStart < maxTime) {
timeout = sr;
break;
}
if (sr.executingStart > nextTime) {
nextTime = sr.executingStart;//更新服務執行下一次開始時間
}
}
if (timeout != null && mAm.mLruProcesses.contains(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
......
anrMessage = "executing service " + timeout.shortName;//記錄服務執行超時的一些信息
} else {
//服務沒有超時,則監控下一個服務方法執行是否超時
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
}
}
//服務超時,發送ANR消息給AppErrors給用戶顯示
if (anrMessage != null) {
mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
}
}
在serviceTimeout方法中判斷服務方法執行是否超時,若是執行超時則發送ANR消息給AppErrors,不然繼續監控下一個服務方法執行是否超時。ui
在服務方法執行完成後,將取消服務超時監控。在realStartServiceLocked方法中,執行完bumpServiceExecutingLocked方法後,接着執行ActivityThread的scheduleCreateService方法。
1.scheduleCreateService方法(ActivityThread.java)this
/*
* createService方法來建立服務
*/
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
public void handleMessage(Message msg) {
case CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
private void handleCreateService(CreateServiceData data) {
.....
// 獲取服務的package信息
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
// 經過反射建立服務類
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
......
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
//回調服務的onCreate方法
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);//調用AMS的serviceDoneExecuting方法
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
......
}
}
2.serviceDoneExecuting方法(ActivityManagerService.java)
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
3.serviceDoneExecutingLocked方法(ActiveServices.java)
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
.......
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
Binder.restoreCallingIdentity(origId);
} else {
........
}
}
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
......
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
.....
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortName);
//移除SERVICE_TIMEOUT_MSG消息,取消對服務方法執行時間的監控
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
......
}
.......
}
r.executeFg = false;
.......
}
}
在serviceDoneExecutingLocked方法中,若是執行完了服務的方法,就移除SERVICE_TIMEOUT_MSG消息,取消對服務方法執行時間的監控。
至此,完整的介紹了在執行服務方法的時候,設置監聽服務超時的過程以及移除監聽服務超時的過程。默認狀況下,服務執行的超時時間爲20s,在後臺線程組中服務執行超時時間爲200s。
線程