1. Service概述java
Service做爲Android四大組件之一,在開發過程當中很是經常使用,它雖然沒有ui,可是一樣能夠在後臺作不少重要的事情,咱們平時使用啓動service主要經過startService以及bindService來啓動service以便已經相關操做。本文將介紹startService的原理,後續將分別介紹bindService的原理,以及在Android O上對service的新增限制管控。
注:本文基於Android 8.1
2. Service分類web
從啓動方式上,能夠分別經過startService以及bindService啓動,二者之間最重要的區別在於bindService能夠創建binder鏈接,更加方便通訊。
從運行方式上,能夠分爲前臺service(foregroundService,下面簡稱fg-service)與後臺service,二者的區別在於有前臺service的進程對應的優先級會更高,不容易被系統清理掉,可是前臺service須要在通知欄裏面顯示一個常駐的通知。緩存
3. startService時序圖
數據結構
startService的啓動大體分爲三種狀況:app
對應進程不存在(先啓動進程而後啓動service並執行onCreate和onStartCommand)
進程存在可是service不存在(啓動service並執行onCreate和onStartCommand)
進程和service都存在(只執行onStartCommand)異步
上面的時序圖主要針對進程存在,可是service不存在的狀況,其餘兩種在主要流程上沒有太大區別,關鍵在於其中有一些特殊判斷,在文章過程當中也會提到。
4. 源碼解析
4.1 ContextImpl.startServiceoop
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
public ComponentName startForegroundService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, true, mUser);
}
// 最終的入口都在這個方法中
// foreground service只是傳參requireForeground爲true,普通service爲false
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// binder call至ams
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}post
最終經過startServiceCommon調用至ams,注意這裏返回值有進行特殊處理,而後拋出了一些異常,主要返回值的component的packageName有"!","!!","?"三種,後面在介紹源碼過程當中能夠看到具體是哪裏會返回這些異常。
"!":權限校驗沒經過,不容許啓動
"!!":沒法啓動
"?":不容許啓動
4.2 ActivityManagerService.startServiceui
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// 進行一些簡單的校驗
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
// callingPackage不能爲空
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
// mService正是ActiveServices對象
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}this
這塊只是簡單校驗以後,就調用到了ActiveServices.startServiceLocked。
參數解析:
caller:發起startService的進程對應的IApplicationThread對象
service:要啓動的service的intent
resolvedType:service類型,啓動的時候能夠設置data已經schema等
requireForeground:是否發起啓動foregroundService
callingPackage:發起startService的進程的packageName
userId:當前用戶id
4.3 ActiveServices.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
final boolean callerFg;
// 獲取發起binder call的caller進程,若是不存在則拋異常
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + callingPid
+ ") when starting service " + service);
}
// 根據當前這個進程所處的調度環境判斷是前臺仍是後臺
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
// 拿到要啓動的service的信息
// 主要是從packageManagerService中查詢,而後緩存起來
// 其中還進行了一些權限的校驗,4.4小節詳細介紹
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
// 沒有查到要啓動的service,直接return了
if (res == null) {
return null;
}
// 這裏就能看到前面提到的返回component的package爲「!」的狀況了
// 緣由是沒有對應的servicerecord,沒有的緣由會在下面4.4小節中進一步介紹
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
// 拿到要啓動的serviceRecord,這個就是咱們在manifest中註冊的service組件對應在系統中封裝起來的對象
ServiceRecord r = res.record;
// 判斷user是否存在
if (!mAm.mUserController.exists(r.userId)) {
return null;
}
// 是否要啓動fg-service
if (!r.startRequested && !fgRequired) {
// 這塊是校驗若是要啓動的service是一個後臺service
// 那麼須要看是否擁有後臺啓動的權限,不容許就沒法後臺啓動
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// 新升級到O的應用可能會遇到這問題,由於不容許後臺狀況下的app啓動後臺service
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage);
if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
return null;
}
// 不容許啓動,此處封裝component的packageName爲「?」,對應前面提到的,會拋出相關異常
UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
...
// 若是這個service正在調度重啓,那麼取消重啓,由於立刻要啓動了
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "START SERVICE WHILE RESTART PENDING: " + r);
}
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
// 若是調用者在後臺,且不是啓動的前臺service,判斷是否須要delay
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
if (r.delayed) {
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
addToStarting = true;
}
}
...
// 準備啓動service了
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
小結:
校驗caller
拿到serviceRecord,進一步校驗
校驗是否有能夠後臺啓動
是否須要delay
startServiceInnerLocked
4.4 ActiveServices.retrieveServiceLocked
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
ServiceRecord r = null;
// 獲取user
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
// 根據userId獲取ServiceMap
// 有一個user爲key,ServiceMap爲v的map,保存了全部的service信息
// 每一個user對應一個
// ServiceMap是一個handler對象,用的looper是ActivityManager線程
// 其中主要保存的都是存放service的各map,以不一樣的方式存儲的Servicerecord
ServiceMap smap = getServiceMapLocked(userId);
final ComponentName comp = service.getComponent();
// 經過component從ServiceMap查詢
if (comp != null) {
r = smap.mServicesByName.get(comp);
}
...
if (r == null) {
try {
// 若是沒能查到,那須要從PackageManager去查詢了
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId, callingUid);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
": not found");
return null;
}
// 封裝ComponentName
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
// FLAG_EXTERNAL_SERVICE類型的service必須有人去bind
// 這塊就不貼具體實現了,startService過程當中這個邏輯不會走到
...
if (userId > 0) {
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)
&& mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
userId = 0;
smap = getServiceMapLocked(0);
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = smap.mServicesByName.get(name);
// 拿到ServiceRecord,若是沒有須要新建
if (r == null && createIfNeeded) {
...
// 這塊主要就是ServiceRecord對象建立以及放入ServiceMap中
}
}
}
if (r != null) {
...
// 這塊主要是作一些權限校驗,包括export(manifest中指定是否容許其餘進程啓動)
// 以及本身指定的service權限
if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
resolvedType, r.appInfo)) {
return null;
}
// 查找成功
return new ServiceLookupResult(r, null);
}
// 沒有查找成功返回null
// 上面一節有提到,若是這裏返回null則會再進一步返回到ContextImpl中拋出異常
return null;
}
這塊作了兩件事:
查找ServiceRecord,若是不存在則建立
權限檢查
4.5 ActiveServices.startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
...
r.callStart = false;
synchronized (r.stats.getBatteryStats()) {
r.stats.startRunningLocked();
}
// bringUpServiceLocked這個是啓動service的核心
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
// 下面主要是進行delay
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
if (first) {
smap.rescheduleDelayedStartsLocked();
}
} else if (callerFg || r.fgRequired) {
smap.ensureNotStartingBackgroundLocked(r);
}
return r.name;
}
這裏沒作什麼事,主要實現都在bringUpServiceLocked
4.6 ActiveServices.bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
// 從上面的時序圖能夠知道sendServiceArgsLocked中主要是要調度執行service的onStartCommand
// 這裏怎麼直接就執行了呢?
// 緣由在於判斷條件,對於沒有執行onCreate的service,r.app是null,因此不會執行這個流程
// 也就是沒有啓動過的service不會走這裏,只有啓動過的service纔會
// 因此對於已經啓動過的service,重複startService只會走onStartCommand,就是由於這裏,而後return
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
// 若是不是調度重啓,且已經在restart列表中,return
// 只有調度重啓的地方調用過來whileRestarting爲true
if (!whileRestarting && mRestartingServices.contains(r)) {
return null;
}
// 從restart中移除,由於立刻要執行啓動了
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
...
// 這中間是一些簡單的狀態判斷,有興趣能夠本身查看源碼
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
// 進程存在那就直接走真正啓動service的邏輯了
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
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 {
// isolated進程處理,O上webview進程屬於這種類型,加以特殊處理,標記hostingType
// hostingType主要用於啓動進程的時候
app = r.isolatedProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingType = "webview_service";
}
}
// 進程不存在,那還得先啓動進程
if (app == null && !permissionsReviewRequired) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingType, r.name, false, isolated, false)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
...
// 由於要啓動進程,因此須要記一下此次啓動進程的緣由是由於須要啓動這個service
// 等到進程啓動成功以後,在進程attachApplicationLocked的時候會再去啓動這個serivice
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
return null;
}
小結:
若是service已經存在那麼直接調度sendServiceArgsLocked(將會執行service.onStartCommand)
處理service重啓相關數據結構
進程存在,則realStartServiceLocked
進程不存在則先啓動進程並把service保存在mPendingServices
4.7 ActiveServices.realStartServiceLocked
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);
// 這裏主要是計算設置service的timeout
// 由於service的執行是計算在ANR機制中的,這裏就是開始計時
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
// 若是是前臺service須要更新並記錄當前前臺serivice的狀態
updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
// 更新進程優先級
mAm.updateOomAdjLocked();
boolean created = false;
try {
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
// 設置process的狀態爲start service
// 這樣在更新進程優先級的時候會有對應的處理,其實就是會提高優先級
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
// 到APP的進程中了,執行IApplicationThread.scheduleCreateService
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true;
} catch (DeadObjectException e) {
// 發現執行過程當中進程掛掉了,須要處理後事,主要是進程中一些狀態的清除
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app);
throw e;
} finally {
if (!created) {
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
if (newService) {
app.services.remove(r);
r.app = null;
}
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
// 更新綁定的activity,這塊主要針對bindService
updateServiceClientActivitiesLocked(app, null, true);
// 若是須要執行service的start則加入到pendingStarts
// r.startRequested在startServiceLocked就標記了
// 且startServiceLocked時就已經加入到pendingStarts
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
// 這裏將會執行service.onStartCommand
sendServiceArgsLocked(r, execInFg, true);
...
// delay相關
}
小結:
開始計算service 「create」的ANR計時
調用到app進程建立並執行service的onCreate
sendServiceArgsLocked
4.8 ActiveServices.sendServiceArgsLocked
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
// startServiceLocked時已經加入到pendingStarts
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
ArrayList<ServiceStartArgs> args = new ArrayList<>();
while (r.pendingStarts.size() > 0) {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
if (si.intent == null && N > 1) {
continue;
}
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.neededGrants != null) {
mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
si.getUriPermissionsLocked());
}
mAm.grantEphemeralAccessLocked(r.userId, si.intent,
r.appInfo.uid, UserHandle.getAppId(si.callingId));
// 再次開始ANR的計時,不過此處計時是「start」
bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
mAm.updateOomAdjLocked(r.app, true);
}
// O上開始,調用startForegroundService須要5s內調用startForeground
// 若是調用startForegroundService就處於r.fgRequired
// 此處是若是發現須要調用startForeground可是沒調,則認爲超時了
if (r.fgRequired && !r.fgWaiting) {
if (!r.isForeground) {
scheduleServiceForegroundTransitionTimeoutLocked(r);
} else {
r.fgRequired = false;
}
}
int flags = 0;
if (si.deliveryCount > 1) {
flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
// 建立ServiceStartArgs
args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
}
ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
slice.setInlineCountLimit(4);
Exception caughtException = null;
try {
// 調度到APP進程執行scheduleServiceArgs(將會執行service.onStartCommand)
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
scheduleServiceArgs
...
}
// 若是發生了異常須要停掉service
if (caughtException != null) {
final boolean inDestroying = mDestroyingServices.contains(r);
for (int i = 0; i < args.size(); i++) {
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
}
if (caughtException instanceof TransactionTooLargeException) {
throw (TransactionTooLargeException)caughtException;
}
}
}
小結:
開始service「start」的ANR計時
建立ServiceStartArgs
調度到app進程執行service的onStartCommand
4.9 ActivityThread.handleCreateService
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) {
switch (msg.what) {
...
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) {
unscheduleGcIdler();
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) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
// 建立application
Application app = packageInfo.makeApplication(false, mInstrumentation);
// 執行service attach
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
// 執行service的onCreate
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
app進程中binder線程調度過來以後,發送消息到主線程執行handleCreateService,在handleCreateService中終於看到了咱們熟悉的onCreate了
處理完了service的生命週期,還要告訴ams,我處理完了,由於那邊還在進行service的ANR計時呢
4.10 ActivityThread.handleServiceArgs
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
data.args.prepareToEnterProcess();
}
int res;
if (!data.taskRemoved) {
// 執行service的onStartCommand方法
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
// 這裏在前面講解SharedPreferences的時候有提到,是在等待sp的任務寫入完成
QueuedWork.waitToFinish();
try {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
ensureJitEnabled();
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to start service " + s
+ " with " + data.args + ": " + e.toString(), e);
}
}
}
}
scheduleServiceArgs中一樣是發送消息到app主線程而後執行scheduleServiceArgs
scheduleServiceArgs中執行service.onStartCommand,而後告訴AMS執行完畢
4.11 ActivityManagerService.serviceDoneExecuting
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");
}
// ActiveSercices.serviceDoneExecutingLocked
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
4.12 ActiveServices.serviceDoneExecutingLocked
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
r.callStart = true;
// 這裏的res是onStartCommand的返回值
switch (res) {
case Service.START_STICKY_COMPATIBILITY:
case Service.START_STICKY: {
r.findDeliveredStart(startId, true);
r.stopIfKilled = false;
break;
}
case Service.START_NOT_STICKY: {
r.findDeliveredStart(startId, true);
if (r.getLastStartId() == startId) {
r.stopIfKilled = true;
}
break;
}
case Service.START_REDELIVER_INTENT: {
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
si.deliveryCount = 0;
si.doneExecutingCount++;
r.stopIfKilled = true;
}
break;
}
case Service.START_TASK_REMOVED_COMPLETE: {
r.findDeliveredStart(startId, true);
break;
}
default:
throw new IllegalArgumentException(
"Unknown service start result: " + res);
}
if (res == Service.START_STICKY_COMPATIBILITY) {
r.callStart = false;
}
} else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
if (!inDestroying) {
if (r.app != null) {
Slog.w(TAG, "Service done with onDestroy, but not inDestroying: "
+ r + ", app=" + r.app);
}
} else if (r.executeNesting != 1) {
Slog.w(TAG, "Service done with onDestroy, but executeNesting="
+ r.executeNesting + ": " + r);
r.executeNesting = 1;
}
}
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
Binder.restoreCallingIdentity(origId);
} else {
Slog.w(TAG, "Done executing unknown service from pid "
+ Binder.getCallingPid());
}
}
其中的res處理:
若是是START_STICKY_COMPATIBILITY或者START_STICKY那麼若是進程掛掉了,service依舊會重啓,不少app會利用這個進行保活。
在其中的serviceDoneExecutingLocked會把前面的計時消息給remove掉,若是service的生命週期在規定時間內執行完畢,就不會ANR了。
總結
startService過程當中若是進程不存在會建立進程 service不存在時默認狀況下會先執行service的onCreate,再執行service的onStartCommand service存在時只會執行service的onStartCommand service的onCreate和onStartCommand都會被ANR計時監控,規定時間內沒有處理完就會超時 onStartCommand處理以後還要等待sp寫入完畢纔會返回ams,因此不適合在onStartCommand中作大量的sp操做,即便是用的是apply異步進行 onStartCommand的返回值能夠控制service是否在進程被kill以後依舊重啓service