ActivityManagerService之Service啟動過程解析
緣由
我曾經(jīng)任職于一家小公司,負(fù)責(zé)上層一切事務(wù),而公司為了給客戶(尤其是小客戶)提供開發(fā)的便利,會強(qiáng)行去掉一些限制,其中就包括啟動 Service 的限制。
本文來分析 Service 的整體啟動流程,順帶也會提一提 Service 啟動的一些限制。但是,讀者請務(wù)必自行了解 Service 的啟動方式,包括前臺 Service 的啟動,這些基本知識本文不會過多提及。
啟動 Service
Service 的啟動最終會調(diào)用如下方法
// ContextImpl.java private ComponentName startServiceCommon(Intent service, boolean requireForeground, UserHandle user) { try { // 從 Android 5.0 ,必須使用顯式 Intent 啟動 Service validateServiceIntent(service); service.prepareToLeaveProcess(this); // 通過 AMS 啟動 Service ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), requireForeground, getOpPackageName(), getAttributionTag(), user.getIdentifier()); if (cn != null) { // ... 處理異常結(jié)果 ... } // 成功啟動后,返回已啟動的 Service 組件名 return cn; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
Service 最終是通過 AMS 進(jìn)行啟動的,一旦啟動成功,會返回 Service 的組件名,通過這個返回結(jié)果,可以判斷 Service 是否啟動成功,這一點(diǎn)往往被很多開發(fā)者忽略。
AMS 最終會調(diào)用 ActiveService#startServiceLocked() 來啟動 Service
ActivityManagerService 把 Service 的所有事務(wù)都交給 ActiveServices 處理。
// ActiveServices.java ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage, @Nullable String callingFeatureId, final int userId, boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException { // 調(diào)用方是否處于前臺 final boolean callerFg; if (caller != null) { final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller + " (pid=" + callingPid + ") when starting service " + service); } callerFg = callerApp.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND; } else { callerFg = true; } // 1. 查詢 Service // 其實這是是從緩存獲取 ServiceRecord,或者建立 ServiceRecord 并緩存 ServiceLookupResult res = retrieveServiceLocked(service, null, resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg, false, false); if (res == null) { return null; } if (res.record == null) { return new ComponentName("!", res.permission != null ? res.permission : "private to package"); } // 從查詢的結(jié)果中獲取 Service 記錄 ServiceRecord r = res.record; // 2. 對 Service 啟動施加限制 // ... if (forcedStandby || (!r.startRequested && !fgRequired)) { // Service 所在的進(jìn)程處于后臺,是無法啟動 Service final int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName, r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { Slog.w(TAG, "Background start not allowed: service " + service + " to " + r.shortInstanceName + " from pid=" + callingPid + " uid=" + callingUid + " pkg=" + callingPackage + " startFg?=" + fgRequired); // ... UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(r.appInfo.uid); return new ComponentName("?", "app is in background uid " + uidRec); } } // ... // 3. 進(jìn)入下一步 Service 啟動過程 return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg, allowBackgroundActivityStarts, backgroundActivityStartsToken); }
首先為 Service 在服務(wù)端建立一個記錄 ServiceRecord 并緩存起來,這個過程比較簡單,讀者自行分析。
然后,在 Service 啟動之前,施加一些限制,代碼中展示了一段后臺 app 無法啟動 Service 的限制,但是也省略了其他限制的代碼,有興趣的讀者可以自行分析。
本文旨在分析 Service 的啟動流程,對于一些小細(xì)節(jié),限于篇幅原因,就不細(xì)致分析,請讀者自行研讀代碼。
最后進(jìn)入下一步的啟動的流程
Service 的啟動,會調(diào)用好幾個類似的函數(shù),但是每一個函數(shù)最做了一部分功能,這樣就可以把一個龐大的函數(shù)分割為幾個小的函數(shù),代碼閱讀性更高,我們要學(xué)習(xí)這種做法。
private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service, int callingUid, int callingPid, boolean fgRequired, boolean callerFg, boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException { // ... // 1. 更新 ServiceRecord 數(shù)據(jù) r.lastActivity = SystemClock.uptimeMillis(); r.startRequested = true; r.delayedStop = false; r.fgRequired = fgRequired; // 保存即將發(fā)送給 Service 的參數(shù) r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), service, neededGrants, callingUid)); // 授予 app 啟動前臺 Service 的 app op 權(quán)限 if (fgRequired) { // ... } // 下面一段,確定 addToStarting 的值 final ServiceMap smap = getServiceMapLocked(r.userId); boolean addToStarting = false; // 注意這里的判斷條件 // !callerFg 表示調(diào)用方不處于前臺 // !fgRequired 表示啟動的是 非前臺Service // r.app == null 表示 Service 還沒有啟動過 if (!callerFg && !fgRequired && r.app == null && mAm.mUserController.hasStartedUserState(r.userId)) { ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid); if (proc == null || proc.mState.getCurProcState() > PROCESS_STATE_RECEIVER) { // app 沒有創(chuàng)建,或者已經(jīng)創(chuàng)建,但是在后臺沒有運(yùn)行任何四大組件 // ... // 延時Service不在這里啟動,直接返回 if (r.delayed) { return r.name; } // 如果目前要啟動非前臺Service超時過了最大數(shù)量的,那么當(dāng)前這個Service,要設(shè)置為延時 Service // 而延時 Service 不在這里啟動,因此直接返回 if (smap.mStartingBackground.size() >= mMaxStartingBackground) { // Something else is starting, delay! Slog.i(TAG_SERVICE, "Delaying start of: " + r); smap.mDelayedStartList.add(r); r.delayed = true; return r.name; } addToStarting = true; } else if (proc.mState.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) { // app 處于后臺,但是只運(yùn)行了 service 和 receiver addToStarting = true; } } // allowBackgroundActivityStarts 目前為 false if (allowBackgroundActivityStarts) { r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken); } // 2. 繼續(xù)下一階段的啟動流程 ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); return cmp; }
現(xiàn)在沒有 Service 的啟動限制了,是時候正式啟動了,首先更新 ServiceRecord 數(shù)據(jù),這里要注意,使用 ServiceRecord#pendingStarts 保存了要發(fā)送給 Service 的參數(shù)。
接下來有一段關(guān)于延時 Service 以及監(jiān)聽 后臺Service 相關(guān)的代碼,這是為了優(yōu)化 Service 啟動過多的情況,而做出的一個優(yōu)化。對于系統(tǒng)優(yōu)化的開發(fā)者,你可能要重點(diǎn)關(guān)注一下,本文先不管這個優(yōu)化功能。
然后繼續(xù)看下一步的啟動流程
// ActiveServices.java ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException { synchronized (mAm.mProcessStats.mLock) { final ServiceState stracker = r.getTracker(); if (stracker != null) { stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity); } } // 是否調(diào)用 onStart() r.callStart = false; final int uid = r.appInfo.uid; final String packageName = r.name.getPackageName(); final String serviceName = r.name.getClassName(); FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName, serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START); mAm.mBatteryStatsService.noteServiceStartRunning(uid, packageName, serviceName); // 1. 拉起 Service String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false /* whileRestarting */, false /* permissionsReviewRequired */, false /* packageFrozen */, true /* enqueueOomAdj */); /* Will be a no-op if nothing pending */ mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); if (error != null) { return new ComponentName("!!", error); } // 優(yōu)化后臺Service啟動過多的情況 if (r.startRequested && addToStarting) { boolean first = smap.mStartingBackground.size() == 0; smap.mStartingBackground.add(r); // 設(shè)置一個超時時間 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() 拉起 Service
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen, boolean enqueueOomAdj) throws TransactionTooLargeException { // 1. 如果 Service 已經(jīng)啟動過一次,直接發(fā)送發(fā)送參數(shù)給 Service 即可 // 因為只有 Service 啟動過,r.app 才不為 null if (r.app != null && r.app.getThread() != null) { sendServiceArgsLocked(r, execInFg, false); return null; } // ... final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0; final String procName = r.processName; HostingRecord hostingRecord = new HostingRecord("service", r.instanceName); ProcessRecord app; if (!isolated) { // 1. Service 進(jìn)程存在,但是 Service 還沒有啟動過,那么通知宿主進(jìn)程啟動 Service // 由于前面已經(jīng)判斷過 r.app 不為 null 的情況,所以這里處理的就是 Service 沒有啟動過的情況 app = mAm.getProcessRecordLocked(procName, r.appInfo.uid); if (app != null) { // 進(jìn)程粗在 final IApplicationThread thread = app.getThread(); final int pid = app.getPid(); final UidRecord uidRecord = app.getUidRecord(); if (thread != null) { // attach application 已經(jīng)完成 try { app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats); realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg, enqueueOomAdj); return null; } // ... } } } else { // ... } // 3. Service 所在的進(jìn)程沒有運(yùn)行,那么要 fork 一個進(jìn)程 if (app == null && !permissionsReviewRequired && !packageFrozen) { // TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service // was initiated from a notification tap or not. if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated)) == 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, enqueueOomAdj); return msg; } if (isolated) { r.isolatedProc = app; } } // 對于前臺 Service 的 app, 暫時添加到省電模式白名單中 if (r.fgRequired) { mAm.tempAllowlistUidLocked(r.appInfo.uid, SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH, "fg-service-launch", TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED, r.mRecentCallingUid); } // 3.1 mPendingServices 保存正在等待進(jìn)程起來的 Service // 進(jìn)程起來后,執(zhí)行 attach application 過程時,會自動啟動這個 Service if (!mPendingServices.contains(r)) { mPendingServices.add(r); } if (r.delayedStop) { // ... } return null; }
拉起一個 Service 要分好幾種情況
- 如果 Service 已經(jīng)啟動過,那么直接發(fā)送參數(shù)給 Service 去執(zhí)行任務(wù)即可。這是最簡單的一種情況。
- 如果 Service 沒有啟動過,但是 Service 的宿主進(jìn)程是存在的,那么通知宿主進(jìn)程創(chuàng)建 Service,然后發(fā)送參數(shù)給它。
- 如果 Service 的宿主進(jìn)程不存在,那么得先 fork 一個進(jìn)程,然后用 mPendingServices 保存這個等待進(jìn)程啟動的 Service。當(dāng)進(jìn)程起來后,在執(zhí)行 attach application 的過程中,AMS 會自動完成 Service 的啟動流程。
第3種情況,明顯是包含前面兩種情況,因此下面直接分析這個過程。
宿主進(jìn)程的啟動
Service 的宿主進(jìn)程起來后,在執(zhí)行 attach application 的過程中,AMS 會自動啟動那些等待進(jìn)程起來的 Service,如下
private boolean attachApplicationLocked(@NonNull IApplicationThread thread, int pid, int callingUid, long startSeq) { // ... try { // ... // 進(jìn)程初始化 if (app.getIsolatedEntryPoint() != null) { // This is an isolated process which should just call an entry point instead of // being bound to an application. thread.runIsolatedEntryPoint( app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs()); } else if (instr2 != null) { thread.bindApplication(processName, appInfo, providerList, instr2.mClass, profilerInfo, instr2.mArguments, instr2.mWatcher, instr2.mUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), app.getCompat(), getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, app.getDisabledCompatChanges(), serializedSystemFontMap); } else { thread.bindApplication(processName, appInfo, providerList, null, profilerInfo, null, null, null, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.isPersistent(), new Configuration(app.getWindowProcessController().getConfiguration()), app.getCompat(), getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked(), buildSerial, autofillOptions, contentCaptureOptions, app.getDisabledCompatChanges(), serializedSystemFontMap); } // ... } catch (Exception e) { // ... return false; } // ... if (!badApp) { try { // 啟動等待進(jìn)程的 Service didSomething |= mServices.attachApplicationLocked(app, processName); checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked"); } } // ... return true; }
最終調(diào)用 ActiveServices#attachApplicationLocked() 完成 Service 的啟動
// ActiveServices.java boolean attachApplicationLocked(ProcessRecord proc, String processName) throws RemoteException { boolean didSomething = false; // mPendingServices 保存的就是那些等待進(jìn)程起來的 Service if (mPendingServices.size() > 0) { ServiceRecord sr = null; try { // 遍歷 mPendingServices ,啟動屬于該進(jìn)程的所有 Service for (int i=0; i<mPendingServices.size(); i++) { sr = mPendingServices.get(i); // 過濾掉不屬于這個進(jìn)程的 Service if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid || !processName.equals(sr.processName))) { continue; } final IApplicationThread thread = proc.getThread(); final int pid = proc.getPid(); final UidRecord uidRecord = proc.getUidRecord(); mPendingServices.remove(i); i--; proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode, mAm.mProcessStats); // 啟動 Service realStartServiceLocked(sr, proc, thread, pid, uidRecord, sr.createdFromFg, true); didSomething = true; if (!isServiceNeededLocked(sr, false, false)) { bringDownServiceLocked(sr, true); } mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE); } } catch (RemoteException e) { // ... } } // 處理進(jìn)程重啟而需要重啟的 Service if (mRestartingServices.size() > 0) { // ... } return didSomething; }
終于,我們看到了我們想看到的東西,先從 mPendingServices 中過濾掉不屬于進(jìn)程的 Service,然后啟動它
// ActiveServices.java private void realStartServiceLocked(ServiceRecord r, ProcessRecord app, IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg, boolean enqueueOomAdj) throws RemoteException { // ... // 注意,r.app 的值才不為 null,也就是 ServiceRecord#app 不為 null // 因此可以通過 r.app 判斷 Service 是否已經(jīng)啟動過 r.setProcess(app, thread, pid, uidRecord); r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); final ProcessServiceRecord psr = app.mServices; final boolean newService = psr.startService(r); // 注意,這里實現(xiàn)了 Service 超時的功能 bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */); mAm.updateLruProcessLocked(app, false, null); updateServiceForegroundLocked(psr, /* oomAdj= */ false); // Force an immediate oomAdjUpdate, so the client app could be in the correct process state // before doing any service related transactions mAm.enqueueOomAdjTargetLocked(app); mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE); boolean created = false; try { // ... // 1. 通知宿主進(jìn)程創(chuàng)建Service thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo), app.mState.getReportedProcState()); r.postNotification(); created = true; // ... } catch (DeadObjectException e) { // ... } finally { if (!created) { // ... } } // ... // 2. 發(fā)送參數(shù)給 Service sendServiceArgsLocked(r, execInFg, true); if (r.delayed) { // ... } if (r.delayedStop) { // ... } }
現(xiàn)在,正式與宿主進(jìn)程交互來啟動 Service
- 首先通過 IApplicationThread#scheduleCreateService() 來通知宿主進(jìn)程創(chuàng)建 Service。
- 然后通過 IApplicationThread#scheduleServiceArgs() 把參數(shù)發(fā)送給宿主進(jìn)程,宿主進(jìn)程會把參數(shù)發(fā)送給 Service 執(zhí)行任務(wù)。
宿主進(jìn)程創(chuàng)建 Service
宿主進(jìn)程接收到創(chuàng)建 Service 的指令后,會通過 Handler 發(fā)送一個消息,最終調(diào)用如下方法
// ActivityThread.java private void handleCreateService(CreateServiceData data) { unscheduleGcIdler(); LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { // 創(chuàng)建 Application,并調(diào)用 Application#onCreate() Application app = packageInfo.makeApplication(false, mInstrumentation); final java.lang.ClassLoader cl; if (data.info.splitName != null) { cl = packageInfo.getSplitClassLoader(data.info.splitName); } else { cl = packageInfo.getClassLoader(); } // 創(chuàng)建 Service service = packageInfo.getAppFactory() .instantiateService(cl, data.info.name, data.intent); ContextImpl context = ContextImpl.getImpl(service .createServiceBaseContext(this, packageInfo)); if (data.info.splitName != null) { context = (ContextImpl) context.createContextForSplit(data.info.splitName); } if (data.info.attributionTags != null && data.info.attributionTags.length > 0) { final String attributionTag = data.info.attributionTags[0]; context = (ContextImpl) context.createAttributionContext(attributionTag); } context.getResources().addLoaders( app.getResources().getLoaders().toArray(new ResourcesLoader[0])); context.setOuterContext(service); service.attach(context, this, data.info.name, data.token, app, ActivityManager.getService()); // 執(zhí)行 Service#onCreate() service.onCreate(); mServicesData.put(data.token, data); mServices.put(data.token, service); // 通知服務(wù)端Service創(chuàng)建成功 try { ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } catch (Exception e) { // ... } }
宿主繼承會先創(chuàng)建 Application,并執(zhí)行 Application#onCreate(),然后創(chuàng)建 Service,并執(zhí)行 Service#onCreate(),最后通知服務(wù)端 Service 創(chuàng)建成功。這一套流程,簡直行云流水。
Service 接收參數(shù)
宿主進(jìn)程接收到服務(wù)端發(fā)送過來的 Service 啟動參數(shù)后,最終調(diào)用如下方法
// ActivityThread.java private void handleServiceArgs(ServiceArgsData data) { CreateServiceData createData = mServicesData.get(data.token); Service s = mServices.get(data.token); if (s != null) { try { if (data.args != null) { data.args.setExtrasClassLoader(s.getClassLoader()); data.args.prepareToEnterProcess(isProtectedComponent(createData.info), s.getAttributionSource()); } int res; if (!data.taskRemoved) { // 調(diào)用 Service#onStartCommand() 接收參數(shù),并執(zhí)行任務(wù) // 注意,這里是在主線程 res = s.onStartCommand(data.args, data.flags, data.startId); } else { s.onTaskRemoved(data.args); res = Service.START_TASK_REMOVED_COMPLETE; } QueuedWork.waitToFinish(); try { // 把 Service#onStartCommand() 的執(zhí)行結(jié)果反饋給服務(wù)端 // 因為這個結(jié)果影響到 Service 重啟的方式 ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_START, data.startId, res); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } catch (Exception e) { // ... } } }
當(dāng)宿主進(jìn)程收到 Service 的啟動參數(shù)后,調(diào)用 Service#onStartCommand() 接收參數(shù),并執(zhí)行任務(wù)。
注意,Service#onStartCommand() 是在主線程中執(zhí)行,其實四大組件的生命周期都是在主線程中執(zhí)行的,這一點(diǎn)大家要牢記。
然后把 Service#onStartCommand() 的返回結(jié)果返回給服務(wù)端。這個方法的返回結(jié)果很重要,它影響了 Service 重啟的方式。這里簡單展示下結(jié)果的處理流程
// ActiveServices.java void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res, boolean enqueueOomAdj) { boolean inDestroying = mDestroyingServices.contains(r); if (r != null) { if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) { // 注意了,ServiceRecord#callStart , 是在 Service 執(zhí)行完 onStartCommand() 并反饋結(jié)果后,才設(shè)置為 true r.callStart = true; switch (res) { case Service.START_STICKY_COMPATIBILITY: // Service 會重啟,但是不會收到原來的啟動參數(shù) case Service.START_STICKY: { // 注意最后一個參數(shù)為 true // 它表示從已發(fā)送的參數(shù) Service#deliveredStarts 中移除此次執(zhí)行的參數(shù) // 因為Service重啟時,不需要這個參數(shù) r.findDeliveredStart(startId, false, true); // Don't stop if killed. r.stopIfKilled = false; break; } case Service.START_NOT_STICKY: { // ... break; } // Service 會重啟,并且也會收到原來的啟動參數(shù) case Service.START_REDELIVER_INTENT: { // 注意最后一個參數(shù) true // 它表示不需要從已發(fā)送的參數(shù) Service#deliveredStarts 中移除此次執(zhí)行的參數(shù) // 因此Service重啟時,需要這個參數(shù) ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false); if (si != null) { si.deliveryCount = 0; si.doneExecutingCount++; // Don't stop if killed. r.stopIfKilled = true; } break; } // ... } if (res == Service.START_STICKY_COMPATIBILITY) { r.callStart = false; } } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) { // ... } final long origId = Binder.clearCallingIdentity(); // 主要更新 oom ajd serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj); Binder.restoreCallingIdentity(origId); } }
這里就涉及到 Service 的基本功,上面展示了兩個返回值的處理過程,這兩個返回值都表示,由于內(nèi)存不足而殺掉的 Service,當(dāng)內(nèi)存充足時,會重啟 Service,但是一個返回值需要再次發(fā)送之前的啟動參數(shù),而另外一個返回值不需要。
對于需要發(fā)送參數(shù)的返回值,不需要從 Service#deliveredStart 列表中刪除已經(jīng)發(fā)送的參數(shù),因為 Service 重啟時,需要發(fā)送它。相反,就需要從列表中刪除已經(jīng)發(fā)送的參數(shù),因為 Service 重啟不再需要它了。
結(jié)束
本文完整了分析了 Service 的啟動流程,這個是最基本的,并且需要掌握的。
本文還順帶提了一下 Service 啟動的限制,對于一個專業(yè)的開發(fā)者來說,遵守這些限制即可,但是對于系統(tǒng)開發(fā)者來說,你可能想 去掉/修改/增加 一些限制,那么你得自己研究下。
其實本文還遺留了一個很值得探討的話題,那就是優(yōu)化大量Service啟動,對于系統(tǒng)優(yōu)化的開發(fā)者來說,應(yīng)該是必須要掌握的,后面如果有興趣了,也有時間了,我會補(bǔ)一篇文章,更多關(guān)于ActivityManagerService Service啟動的資料請關(guān)注腳本之家其它相關(guān)文章!
- Android registerForActivityResult動態(tài)申請權(quán)限案例詳解
- ActivityManagerService廣播并行發(fā)送與串行發(fā)送示例解析
- ActivityManagerService廣播注冊與發(fā)送示例解析
- Android面向單Activity開發(fā)示例解析
- Vue3源碼分析reactivity實現(xiàn)方法示例
- vue3源碼分析reactivity實現(xiàn)原理
- Android10 App啟動Activity源碼分析
- Android?Activity共享元素動畫示例解析
- Android?registerForActivityResult新用法實現(xiàn)兩個Activity間數(shù)據(jù)傳遞
相關(guān)文章
Android 使用Vibrator服務(wù)實現(xiàn)點(diǎn)擊按鈕帶有震動效果
這篇文章主要介紹了Android 使用Vibrator服務(wù)實現(xiàn)點(diǎn)擊按鈕帶有震動效果,,本文通過實例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)火鍋工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06Android使用xUtils3.0實現(xiàn)文件上傳
這篇文章主要為大家詳細(xì)介紹了Android使用xUtils3.0實現(xiàn)文件上傳的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11android studio實現(xiàn)簡單的計算器(無bug)
這篇文章主要為大家詳細(xì)介紹了android studio實現(xiàn)簡單計算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-08-08Android App開發(fā)中使用RecyclerView替代ListView的實踐
RecyclerView是Android L即5.0版本以來新加入的一個組件,主要用來實現(xiàn)item的瀑布式排列,因而被人們廣泛認(rèn)為用來替代ListView,這里我們就來看一下Android App開發(fā)中使用RecyclerView替代ListView的實踐:2016-06-06