ActivityManagerService之Service啟動(dòng)過程解析
緣由
我曾經(jīng)任職于一家小公司,負(fù)責(zé)上層一切事務(wù),而公司為了給客戶(尤其是小客戶)提供開發(fā)的便利,會(huì)強(qiáng)行去掉一些限制,其中就包括啟動(dòng) Service 的限制。
本文來分析 Service 的整體啟動(dòng)流程,順帶也會(huì)提一提 Service 啟動(dòng)的一些限制。但是,讀者請(qǐng)務(wù)必自行了解 Service 的啟動(dòng)方式,包括前臺(tái) Service 的啟動(dòng),這些基本知識(shí)本文不會(huì)過多提及。
啟動(dòng) Service
Service 的啟動(dòng)最終會(huì)調(diào)用如下方法
// ContextImpl.java
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
// 從 Android 5.0 ,必須使用顯式 Intent 啟動(dòng) Service
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// 通過 AMS 啟動(dòng) Service
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
// ... 處理異常結(jié)果 ...
}
// 成功啟動(dòng)后,返回已啟動(dòng)的 Service 組件名
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
Service 最終是通過 AMS 進(jìn)行啟動(dòng)的,一旦啟動(dòng)成功,會(huì)返回 Service 的組件名,通過這個(gè)返回結(jié)果,可以判斷 Service 是否啟動(dòng)成功,這一點(diǎn)往往被很多開發(fā)者忽略。
AMS 最終會(huì)調(diào)用 ActiveService#startServiceLocked() 來啟動(dòng) 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)用方是否處于前臺(tái)
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
// 其實(shí)這是是從緩存獲取 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. 對(duì) Service 啟動(dòng)施加限制
// ...
if (forcedStandby || (!r.startRequested && !fgRequired)) {
// Service 所在的進(jìn)程處于后臺(tái),是無法啟動(dòng) 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 啟動(dòng)過程
return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
allowBackgroundActivityStarts, backgroundActivityStartsToken);
}
首先為 Service 在服務(wù)端建立一個(gè)記錄 ServiceRecord 并緩存起來,這個(gè)過程比較簡單,讀者自行分析。
然后,在 Service 啟動(dòng)之前,施加一些限制,代碼中展示了一段后臺(tái) app 無法啟動(dòng) Service 的限制,但是也省略了其他限制的代碼,有興趣的讀者可以自行分析。
本文旨在分析 Service 的啟動(dòng)流程,對(duì)于一些小細(xì)節(jié),限于篇幅原因,就不細(xì)致分析,請(qǐng)讀者自行研讀代碼。
最后進(jìn)入下一步的啟動(dòng)的流程
Service 的啟動(dòng),會(huì)調(diào)用好幾個(gè)類似的函數(shù),但是每一個(gè)函數(shù)最做了一部分功能,這樣就可以把一個(gè)龐大的函數(shù)分割為幾個(gè)小的函數(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 啟動(dòng)前臺(tái) Service 的 app op 權(quán)限
if (fgRequired) {
// ...
}
// 下面一段,確定 addToStarting 的值
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
// 注意這里的判斷條件
// !callerFg 表示調(diào)用方不處于前臺(tái)
// !fgRequired 表示啟動(dòng)的是 非前臺(tái)Service
// r.app == null 表示 Service 還沒有啟動(dòng)過
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)建,但是在后臺(tái)沒有運(yùn)行任何四大組件
// ...
// 延時(shí)Service不在這里啟動(dòng),直接返回
if (r.delayed) {
return r.name;
}
// 如果目前要啟動(dòng)非前臺(tái)Service超時(shí)過了最大數(shù)量的,那么當(dāng)前這個(gè)Service,要設(shè)置為延時(shí) Service
// 而延時(shí) Service 不在這里啟動(dòng),因此直接返回
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 處于后臺(tái),但是只運(yùn)行了 service 和 receiver
addToStarting = true;
}
}
// allowBackgroundActivityStarts 目前為 false
if (allowBackgroundActivityStarts) {
r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken);
}
// 2. 繼續(xù)下一階段的啟動(dòng)流程
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
現(xiàn)在沒有 Service 的啟動(dòng)限制了,是時(shí)候正式啟動(dòng)了,首先更新 ServiceRecord 數(shù)據(jù),這里要注意,使用 ServiceRecord#pendingStarts 保存了要發(fā)送給 Service 的參數(shù)。
接下來有一段關(guān)于延時(shí) Service 以及監(jiān)聽 后臺(tái)Service 相關(guān)的代碼,這是為了優(yōu)化 Service 啟動(dòng)過多的情況,而做出的一個(gè)優(yōu)化。對(duì)于系統(tǒng)優(yōu)化的開發(fā)者,你可能要重點(diǎn)關(guān)注一下,本文先不管這個(gè)優(yōu)化功能。
然后繼續(xù)看下一步的啟動(dòng)流程
// 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)化后臺(tái)Service啟動(dòng)過多的情況
if (r.startRequested && addToStarting) {
boolean first = smap.mStartingBackground.size() == 0;
smap.mStartingBackground.add(r);
// 設(shè)置一個(gè)超時(shí)時(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)啟動(dòng)過一次,直接發(fā)送發(fā)送參數(shù)給 Service 即可
// 因?yàn)橹挥?Service 啟動(dòng)過,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 還沒有啟動(dòng)過,那么通知宿主進(jìn)程啟動(dòng) Service
// 由于前面已經(jīng)判斷過 r.app 不為 null 的情況,所以這里處理的就是 Service 沒有啟動(dòng)過的情況
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 一個(gè)進(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;
}
}
// 對(duì)于前臺(tái) Service 的 app, 暫時(shí)添加到省電模式白名單中
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 過程時(shí),會(huì)自動(dòng)啟動(dòng)這個(gè) Service
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
// ...
}
return null;
}
拉起一個(gè) Service 要分好幾種情況
- 如果 Service 已經(jīng)啟動(dòng)過,那么直接發(fā)送參數(shù)給 Service 去執(zhí)行任務(wù)即可。這是最簡單的一種情況。
- 如果 Service 沒有啟動(dòng)過,但是 Service 的宿主進(jìn)程是存在的,那么通知宿主進(jìn)程創(chuàng)建 Service,然后發(fā)送參數(shù)給它。
- 如果 Service 的宿主進(jìn)程不存在,那么得先 fork 一個(gè)進(jìn)程,然后用 mPendingServices 保存這個(gè)等待進(jìn)程啟動(dòng)的 Service。當(dāng)進(jìn)程起來后,在執(zhí)行 attach application 的過程中,AMS 會(huì)自動(dòng)完成 Service 的啟動(dòng)流程。
第3種情況,明顯是包含前面兩種情況,因此下面直接分析這個(gè)過程。
宿主進(jìn)程的啟動(dòng)
Service 的宿主進(jìn)程起來后,在執(zhí)行 attach application 的過程中,AMS 會(huì)自動(dòng)啟動(dòng)那些等待進(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 {
// 啟動(dòng)等待進(jìn)程的 Service
didSomething |= mServices.attachApplicationLocked(app, processName);
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
}
}
// ...
return true;
}
最終調(diào)用 ActiveServices#attachApplicationLocked() 完成 Service 的啟動(dòng)
// 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 ,啟動(dòng)屬于該進(jìn)程的所有 Service
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
// 過濾掉不屬于這個(gè)進(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);
// 啟動(dòng) 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,然后啟動(dòng)它
// 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)啟動(dòng)過
r.setProcess(app, thread, pid, uidRecord);
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final ProcessServiceRecord psr = app.mServices;
final boolean newService = psr.startService(r);
// 注意,這里實(shí)現(xiàn)了 Service 超時(shí)的功能
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)程交互來啟動(dòng) Service
- 首先通過 IApplicationThread#scheduleCreateService() 來通知宿主進(jìn)程創(chuàng)建 Service。
- 然后通過 IApplicationThread#scheduleServiceArgs() 把參數(shù)發(fā)送給宿主進(jìn)程,宿主進(jìn)程會(huì)把參數(shù)發(fā)送給 Service 執(zhí)行任務(wù)。
宿主進(jìn)程創(chuàng)建 Service
宿主進(jìn)程接收到創(chuàng)建 Service 的指令后,會(huì)通過 Handler 發(fā)送一個(gè)消息,最終調(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) {
// ...
}
}
宿主繼承會(huì)先創(chuàng)建 Application,并執(zhí)行 Application#onCreate(),然后創(chuàng)建 Service,并執(zhí)行 Service#onCreate(),最后通知服務(wù)端 Service 創(chuàng)建成功。這一套流程,簡直行云流水。
Service 接收參數(shù)
宿主進(jìn)程接收到服務(wù)端發(fā)送過來的 Service 啟動(dòng)參數(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ù)端
// 因?yàn)檫@個(gè)結(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 的啟動(dòng)參數(shù)后,調(diào)用 Service#onStartCommand() 接收參數(shù),并執(zhí)行任務(wù)。
注意,Service#onStartCommand() 是在主線程中執(zhí)行,其實(shí)四大組件的生命周期都是在主線程中執(zhí)行的,這一點(diǎn)大家要牢記。
然后把 Service#onStartCommand() 的返回結(jié)果返回給服務(wù)端。這個(gè)方法的返回結(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 會(huì)重啟,但是不會(huì)收到原來的啟動(dòng)參數(shù)
case Service.START_STICKY: {
// 注意最后一個(gè)參數(shù)為 true
// 它表示從已發(fā)送的參數(shù) Service#deliveredStarts 中移除此次執(zhí)行的參數(shù)
// 因?yàn)镾ervice重啟時(shí),不需要這個(gè)參數(shù)
r.findDeliveredStart(startId, false, true);
// Don't stop if killed.
r.stopIfKilled = false;
break;
}
case Service.START_NOT_STICKY: {
// ...
break;
}
// Service 會(huì)重啟,并且也會(huì)收到原來的啟動(dòng)參數(shù)
case Service.START_REDELIVER_INTENT: {
// 注意最后一個(gè)參數(shù) true
// 它表示不需要從已發(fā)送的參數(shù) Service#deliveredStarts 中移除此次執(zhí)行的參數(shù)
// 因此Service重啟時(shí),需要這個(gè)參數(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 的基本功,上面展示了兩個(gè)返回值的處理過程,這兩個(gè)返回值都表示,由于內(nèi)存不足而殺掉的 Service,當(dāng)內(nèi)存充足時(shí),會(huì)重啟 Service,但是一個(gè)返回值需要再次發(fā)送之前的啟動(dòng)參數(shù),而另外一個(gè)返回值不需要。
對(duì)于需要發(fā)送參數(shù)的返回值,不需要從 Service#deliveredStart 列表中刪除已經(jīng)發(fā)送的參數(shù),因?yàn)?Service 重啟時(shí),需要發(fā)送它。相反,就需要從列表中刪除已經(jīng)發(fā)送的參數(shù),因?yàn)?Service 重啟不再需要它了。
結(jié)束
本文完整了分析了 Service 的啟動(dòng)流程,這個(gè)是最基本的,并且需要掌握的。
本文還順帶提了一下 Service 啟動(dòng)的限制,對(duì)于一個(gè)專業(yè)的開發(fā)者來說,遵守這些限制即可,但是對(duì)于系統(tǒng)開發(fā)者來說,你可能想 去掉/修改/增加 一些限制,那么你得自己研究下。
其實(shí)本文還遺留了一個(gè)很值得探討的話題,那就是優(yōu)化大量Service啟動(dòng),對(duì)于系統(tǒng)優(yōu)化的開發(fā)者來說,應(yīng)該是必須要掌握的,后面如果有興趣了,也有時(shí)間了,我會(huì)補(bǔ)一篇文章,更多關(guān)于ActivityManagerService Service啟動(dòng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android registerForActivityResult動(dòng)態(tài)申請(qǐng)權(quán)限案例詳解
- ActivityManagerService廣播并行發(fā)送與串行發(fā)送示例解析
- ActivityManagerService廣播注冊(cè)與發(fā)送示例解析
- Android面向單Activity開發(fā)示例解析
- Vue3源碼分析reactivity實(shí)現(xiàn)方法示例
- vue3源碼分析reactivity實(shí)現(xiàn)原理
- Android10 App啟動(dòng)Activity源碼分析
- Android?Activity共享元素動(dòng)畫示例解析
- Android?registerForActivityResult新用法實(shí)現(xiàn)兩個(gè)Activity間數(shù)據(jù)傳遞
相關(guān)文章
Android 使用Vibrator服務(wù)實(shí)現(xiàn)點(diǎn)擊按鈕帶有震動(dòng)效果
這篇文章主要介紹了Android 使用Vibrator服務(wù)實(shí)現(xiàn)點(diǎn)擊按鈕帶有震動(dòng)效果,,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)火鍋工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Android實(shí)現(xiàn)底部導(dǎo)航欄功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部導(dǎo)航欄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
Android使用xUtils3.0實(shí)現(xiàn)文件上傳
這篇文章主要為大家詳細(xì)介紹了Android使用xUtils3.0實(shí)現(xiàn)文件上傳的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
android studio實(shí)現(xiàn)簡單的計(jì)算器(無bug)
這篇文章主要為大家詳細(xì)介紹了android studio實(shí)現(xiàn)簡單計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
Android App開發(fā)中使用RecyclerView替代ListView的實(shí)踐
RecyclerView是Android L即5.0版本以來新加入的一個(gè)組件,主要用來實(shí)現(xiàn)item的瀑布式排列,因而被人們廣泛認(rèn)為用來替代ListView,這里我們就來看一下Android App開發(fā)中使用RecyclerView替代ListView的實(shí)踐:2016-06-06

