前言
我們已經(jīng)了解了BroadcastReceiver的原理狮崩,我們?cè)賮?lái)看看四大組件之一的Service是怎么啟動(dòng)的焕盟,以及怎么運(yùn)行的原理缨叫。
如果遇到什么問(wèn)題可以來(lái)到http://www.reibang.com/p/c4927c0b80a9本文下進(jìn)行交流
正文
啟動(dòng)Service的入口就是startService和bindService方法色查。我們先來(lái)看看startService在ContextImpl中做了什么消玄。
startService原理
文件:/frameworks/base/core/java/android/app/ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, false, mUser);
}
@Override
public ComponentName startForegroundService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, true, mUser);
}
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
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();
}
}
此時(shí)調(diào)用的就是AMS的startService方法跟伏。
AMS startService
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
....
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
mServices是一個(gè)ActiveServices對(duì)象。這個(gè)對(duì)象是在AMS的構(gòu)造函數(shù)中初始化好的翩瓜。
這里調(diào)用了ActiveServices的startServiceLocked酬姆。
ActiveServices startServiceLocked
文件:/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, 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;
}
ServiceLookupResult res =
retrieveServiceLocked(service, 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");
}
ServiceRecord r = res.record;
...
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
}
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));
if (fgRequired) {
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true);
}
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
...
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
核心流程有如下三個(gè):
- 1.retrieveServiceLocked 從ActiveServices中獲取ServiceLookupResult 需要啟動(dòng)Service對(duì)象
- 2.往ServiceRecord對(duì)象的pendingStarts幾個(gè)中添加一個(gè)ServiceRecord.StartItem對(duì)象。而這個(gè)對(duì)象就是之后Service聲明周期中onCommandStart的回調(diào)參數(shù)
- 3.startServiceInnerLocked 執(zhí)行Service的啟動(dòng)的流程奥溺。
注意這里addToStarting是一個(gè)比較關(guān)鍵的判斷辞色,addToStarting默認(rèn)為false。
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;
} else if (DEBUG_DELAYED_STARTS) {
}
} else if (DEBUG_DELAYED_STARTS) {
}
如果此時(shí)不是啟動(dòng)前臺(tái)服務(wù)浮定,則需要進(jìn)一步進(jìn)行處理相满。如果ProcessRecord為空或者curProcState大于PROCESS_STATE_RECEIVER這個(gè)優(yōu)先級(jí)數(shù)值;也就是優(yōu)先級(jí)更小桦卒。
為了避免此時(shí)App應(yīng)用是沒(méi)有任何的前臺(tái)ui立美,或者App應(yīng)用還沒(méi)有聲明。避免有的App通過(guò)startService進(jìn)行應(yīng)用的包活或者拉起應(yīng)用方灾。就會(huì)進(jìn)行如下能夠存在的最大后臺(tái)服務(wù)數(shù)量建蹄,則放入mDelayedStartList中進(jìn)行延時(shí)啟動(dòng)后臺(tái)服務(wù),現(xiàn)在直接返回了裕偿。
不然則說(shuō)明能夠允許啟動(dòng)后臺(tái)服務(wù)洞慎, 就設(shè)置為addToStarting為true。
ActiveServices retrieveServiceLocked
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
ServiceRecord r = null;
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
ServiceMap smap = getServiceMapLocked(userId);
final ComponentName comp = service.getComponent();
if (comp != null) {
r = smap.mServicesByName.get(comp);
}
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
r = null;
}
if (r == null) {
try {
int flags = ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
if (allowInstant) {
flags |= PackageManager.MATCH_INSTANT;
}
ResolveInfo rInfo = mAm.getPackageManagerInternalLocked().resolveService(service,
resolvedType, flags, userId, callingUid);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
return null;
}
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
if (isBindExternal) {
if (!sInfo.exported) {
}
if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
}
ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = new ApplicationInfo(sInfo.applicationInfo);
sInfo.applicationInfo.packageName = aInfo.packageName;
sInfo.applicationInfo.uid = aInfo.uid;
name = new ComponentName(aInfo.packageName, name.getClassName());
service.setComponent(name);
} else {
}
} else if (isBindExternal) {
}
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);
if (r == null && createIfNeeded) {
final Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
final ServiceRestarter res = new ServiceRestarter();
final BatteryStatsImpl.Uid.Pkg.Serv ss;
final BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
ss = stats.getServiceStatsLocked(
sInfo.applicationInfo.uid, sInfo.packageName,
sInfo.name);
}
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
for (int i=mPendingServices.size()-1; i>=0; i--) {
final ServiceRecord pr = mPendingServices.get(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.name.equals(name)) {
mPendingServices.remove(i);
}
}
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
}
if (r != null) {
...
return new ServiceLookupResult(r, null);
}
return null;
}
- 1.通過(guò)UserController.handleIncomingUser獲取的userId嘿棘,從getServiceMapLocked方法通過(guò)userId中獲取ServiceMap對(duì)象劲腿。這個(gè)對(duì)象保存了已經(jīng)啟動(dòng)過(guò)所有的Service對(duì)象。
- 1.1.ServiceMap保存如下幾種用于查詢映射結(jié)構(gòu):
final ArrayMap<ComponentName, ServiceRecord> mServicesByName = new ArrayMap<>();
final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>();
通過(guò)ComponentName也就是包名和類名查找ServiceRecord鸟妙;通過(guò)Intent意圖過(guò)濾找到ServiceRecord焦人』映常·
1.2.如果能夠獲取到,則直接獲取ServiceMap中的ServiceRecord對(duì)象花椭,并包裹成ServiceLookupResult對(duì)象返回忽匈。
2.如果Intent中的ComponentName不為空,ServiceMap則通過(guò)ComponentName查詢緩存ServiceRecord矿辽。
3.如果還是找不到丹允,且isBindExternal為false(此時(shí)就是false),則通過(guò)過(guò)濾條件從ServiceMap查找緩存ServiceRecord嗦锐。
4.如果設(shè)置了FLAG_EXTERNAL_SERVICE嫌松,且ServiceRecord找到了,但是此時(shí)ServiceRecord中的包名和調(diào)用方的包名不一致奕污,則把找到的緩存ServiceRecord設(shè)置為空萎羔。如果設(shè)置了FLAG_EXTERNAL_SERVICE這個(gè)flag,也就是設(shè)置了
android:externalService
這個(gè)xml標(biāo)簽碳默。這個(gè)標(biāo)簽代表了Service可以綁定調(diào)用方的進(jìn)程贾陷;因此這個(gè)標(biāo)志位支持跨進(jìn)程綁定但是不支持跨包綁定。-
5.如果找不到ServiceRecord嘱根,那么需要新建一個(gè)ServiceRecord髓废。
5.1.先通過(guò)PMS的resolveService方法,從PMS中獲取一個(gè)ResolveInfo對(duì)象该抒。這個(gè)對(duì)象能夠獲取安裝時(shí)候通過(guò)解析AndroidManifest.xml到的ServiceInfo對(duì)象慌洪。
5.2.并且isBindExternal為true。此時(shí)會(huì)封裝一個(gè)新的ServiceInfo凑保,并且通過(guò)Intent的setComponent冈爹,獲取此時(shí)真正需要啟動(dòng)Service對(duì)應(yīng)的包名和類名。在這里isBindExternal為false欧引,startService并不會(huì)走這個(gè)邏輯频伤。
5.3.因?yàn)榭赡軙?huì)在5.2的時(shí)候獲取真實(shí)需要啟動(dòng)的包名,此時(shí)再通過(guò)mServicesByName找一次是否能找到緩存的Service芝此。
5.4.到了這個(gè)步驟說(shuō)明真的找不到了ServiceRecord對(duì)象憋肖。先生成Intent.FilterComparison對(duì)象。把ComponentName作為key和ServiceRecord作為value保存到mServicesByName婚苹;把Intent.FilterComparison作為key岸更,ServiceRecord作為value保存到mServicesByIntent。
5.5.如果在mPendingServices隊(duì)列中發(fā)現(xiàn)了這個(gè)需要新生成的Service對(duì)象對(duì)應(yīng)的包名類名租副,就從mPendingServices中移除一樣的包名類名坐慰。
5.6.最后校驗(yàn)權(quán)限返回ServiceLookupResult。
ActiveServices startServiceInnerLocked
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();
}
String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
if (error != null) {
return new ComponentName("!!", error);
}
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用僧。如果bringUpServiceLocked返回了異常结胀,就返回一個(gè)特殊的ComponentName對(duì)象。
addToStarting為true责循,說(shuō)明此時(shí)是一個(gè)能夠啟動(dòng)的后臺(tái)服務(wù)糟港,則ServiceRecord添加到mStartingBackground中。如果mStartingBackground的數(shù)量為0院仿,則直接調(diào)用ServiceMap的rescheduleDelayedStartsLocked啟動(dòng)后臺(tái)服務(wù)秸抚。
ActiveServices bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired)
throws TransactionTooLargeException {
if (r.app != null && r.app.thread != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
if (!whileRestarting && mRestartingServices.contains(r)) {
return null;
}
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
if (r.delayed) {
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
bringDownServiceLocked(r);
return msg;
}
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
String hostingType = "service";
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
if (app != null && app.thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null;
} catch (TransactionTooLargeException e) {
} catch (RemoteException e) {
}
}
} else {
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) {
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (r.fgRequired) {
mAm.tempWhitelistUidLocked(r.appInfo.uid,
SERVICE_START_FOREGROUND_TIMEOUT, "fg-service-launch");
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r);
}
}
return null;
}
1.如果ServiceRecord已經(jīng)保存了app遠(yuǎn)程端的Binder對(duì)象,說(shuō)明該Service已經(jīng)啟動(dòng)過(guò)了歹垫,則直接執(zhí)行sendServiceArgsLocked執(zhí)行Service的其他聲明周期剥汤。
2.如果ServiceRecord的delay屬性為true,則從mDelayedStartList移除該ServiceRecord排惨,delay設(shè)置為true吭敢。說(shuō)明此時(shí)開(kāi)始啟動(dòng)服務(wù)了。
-
3.如果AndroidManifest中的service標(biāo)簽設(shè)置了
android:isolatedProcess
,說(shuō)明這個(gè)Service需要啟動(dòng)在另一個(gè)隔離的進(jìn)程中執(zhí)行暮芭。我們先只考慮false的情況鹿驼,此時(shí)說(shuō)明是app在app進(jìn)程中啟動(dòng)Service。- 3.1.getProcessRecordLocked獲取當(dāng)前App進(jìn)程的ProcessRecord辕宏,如果ProcessRecord不為空畜晰,則說(shuō)明該進(jìn)程已經(jīng)啟動(dòng)了。此時(shí)為ProcessRecord的addPackage后瑞筐,調(diào)用realStartServiceLocked 啟動(dòng)Service凄鼻。
-
4.如果
android:isolatedProcess
為true,說(shuō)明每一次啟動(dòng)Service都應(yīng)該是一個(gè)新的隔離進(jìn)程聚假。把ServiceRecord設(shè)置給app块蚌。那么app這個(gè)ProcessRecord對(duì)象就是空,此時(shí)permissionsReviewRequired就是false魔策。每執(zhí)行一次這個(gè)startProcessLocked方法匈子,說(shuō)明android:isolatedProcess
標(biāo)志為每一次都是啟動(dòng)app進(jìn)程對(duì)象。- 4.1.調(diào)用一次bringDownServiceLocked方法
- 4.2.mPendingServices如果不包含需要啟動(dòng)的ServiceRecord闯袒,則添加到mPendingService中保存虎敦。
realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final boolean newService = app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create");
mAm.updateLruProcessLocked(app, false, null);
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);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
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) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
// Cleanup.
if (newService) {
app.services.remove(r);
r.app = null;
}
// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.whitelistManager) {
app.whitelistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r);
}
}
}
- 1.啟動(dòng)Service前,先把ServiceRecord添加到ProcessRecord的services集合政敢,說(shuō)明這個(gè)Service正在運(yùn)行了其徙。bumpServiceExecutingLocked埋入Service的ANR消息,更新當(dāng)前App應(yīng)用的adj優(yōu)先級(jí)
- 2.跨進(jìn)程調(diào)用App端的ApplicationThread的scheduleCreateService方法喷户,創(chuàng)建Service對(duì)象唾那,執(zhí)行onCreate
- 3.如果創(chuàng)建的過(guò)程中失敗了,說(shuō)明可能App端要么死掉褪尝,要么就是創(chuàng)建過(guò)程發(fā)生了異常闹获,此時(shí)會(huì)調(diào)用serviceDoneExecutingLocked方法期犬,執(zhí)行Service的完成事務(wù)的任務(wù)。
- 4.如果發(fā)現(xiàn)保存已經(jīng)銷毀的Service對(duì)象集合mDestroyingServices并沒(méi)有這個(gè)Service避诽,就會(huì)再一次的嘗試啟動(dòng)龟虎。
- 5.requestServiceBindingLocked 執(zhí)行服務(wù)綁定的Connection對(duì)象。注意此時(shí)是startService沙庐,因此不會(huì)有任何掛載的Connection對(duì)象鲤妥。只有bindService才會(huì)執(zhí)行。
- 6.sendServiceArgsLocked 執(zhí)行Service發(fā)送數(shù)據(jù)
- 7.移除mDelayedStartList中的ServiceRecord
這幾個(gè)關(guān)鍵的步驟拱雏,讓我們依次的考察棉安,先來(lái)看看scheduleCreateService中做了什么。
bumpServiceExecutingLocked
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
boolean timeoutNeeded = true;
if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
&& (r.app != null) && (r.app.pid == android.os.Process.myPid())) {
timeoutNeeded = false;
}
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 (timeoutNeeded && r.app.executingServices.size() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
if (timeoutNeeded) {
scheduleServiceTimeoutLocked(r.app);
}
}
r.executeFg |= fg;
r.executeNesting++;
r.executingStart = now;
}
如果第一次啟動(dòng)就走第一個(gè)if的分支:
- 1.ProcessRecord的executingServices 正在執(zhí)行任務(wù)的Service集合添加ServiceRecord對(duì)象
- 2.執(zhí)行scheduleServiceTimeoutLocked ANR超時(shí)埋點(diǎn)铸抑。
scheduleServiceTimeoutLocked
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
能看到和BroadcastReceiver的ANR思路一樣贡耽,通過(guò)一個(gè)延時(shí)的Handler,如果達(dá)到時(shí)間了還沒(méi)有移除這個(gè)Handler消息則報(bào)ANR異常羡滑。
這里根據(jù)啟動(dòng)前臺(tái)和后臺(tái)分為兩種超時(shí)時(shí)間:
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
// How long the startForegroundService() grace period is to get around to
// calling startForeground() before we ANR + stop it.
static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
前臺(tái)分別是10秒菇爪,后臺(tái)服務(wù)不屬于后臺(tái)進(jìn)程組(判斷adj是否在SCHED_GROUP_BACKGROUND)是20秒,后臺(tái)服務(wù)屬于后臺(tái)進(jìn)程組 200秒柒昏。
ApplicationThread scheduleCreateService
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);
}
把數(shù)據(jù)封裝成CreateServiceData后凳宙,通過(guò)Handler調(diào)用如下方法:
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 = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
} catch (Exception e) {
}
try {
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,
ActivityManager.getService());
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) {
}
}
- 1.通過(guò)AppComponentFactory反射創(chuàng)建一個(gè)全新的Service對(duì)象
- 2.通過(guò)ContextImpl.createAppContext 創(chuàng)建一個(gè)新的Context。
- 3.獲取LoadedApk中的Application對(duì)象职祷,調(diào)用Service的attach方法綁定Context氏涩。
- 4.調(diào)用Service的onCreate方法
- 5.Service以ServiceRecord的token為key緩存到mServices這個(gè)Map對(duì)象中中
- 5.調(diào)用AMS的serviceDoneExecuting方法。
透三點(diǎn)的核心原理可以看我寫的的Application創(chuàng)建和BroadcastReceiver原理兩篇文章有梆。來(lái)看看Service中都做了什么是尖?
Service attach
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
attachBaseContext(context);
mThread = thread; // NOTE: unused - remove?
mClassName = className;
mToken = token;
mApplication = application;
mActivityManager = (IActivityManager)activityManager;
mStartCompatibility = getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.ECLAIR;
}
很簡(jiǎn)單就是保存了傳遞過(guò)來(lái)的參數(shù),值得注意的是這個(gè)IBinder對(duì)象其實(shí)就是指ServiceRecord對(duì)象泥耀。
接著執(zhí)行Service.onCreate這個(gè)空實(shí)現(xiàn)的方法饺汹。
AMS serviceDoneExecuting
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
本質(zhì)上還是調(diào)用了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) {
....
} else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
....
} else if (r.executeNesting != 1) {
....
}
}
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
Binder.restoreCallingIdentity(origId);
} else {
...
}
}
type是SERVICE_DONE_EXECUTING_ANON痰催,所不會(huì)做更多的處理兜辞。 最后執(zhí)行了serviceDoneExecutingLocked方法。
ActiveServices serviceDoneExecutingLocked
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) {
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
for (int i=r.app.executingServices.size()-1; i>=0; i--) {
if (r.app.executingServices.valueAt(i).executeFg) {
r.app.execServicesFg = true;
break;
}
}
}
if (inDestroying) {
mDestroyingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app, true);
}
r.executeFg = false;
if (r.tracker != null) {
r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
SystemClock.uptimeMillis());
if (finishing) {
r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
if (finishing) {
if (r.app != null && !r.app.persistent) {
r.app.services.remove(r);
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
}
r.app = null;
}
}
}
- 1.executeNesting 遞減一之后小于等于0夸溶,說(shuō)明該ServiceRecord只執(zhí)行了一次啟動(dòng)逸吵。接著移除executingServices中的ServiceRecord,說(shuō)明正在執(zhí)行的Service已經(jīng)處理完畢了缝裁。
- 2.如果executingServices大小為0扫皱,則移除ActivityManagerService.SERVICE_TIMEOUT_MSG這個(gè)Handler消息,也就是拆開(kāi)了ANR的消息
- 3.如果執(zhí)行的是結(jié)束Service的方法,則從ProcessRecord的services移除ServiceRecord韩脑。
ActiveServices sendServiceArgsLocked
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
boolean oomAdjusted) throws TransactionTooLargeException {
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++;
...
bumpServiceExecutingLocked(r, execInFg, "start");
if (!oomAdjusted) {
oomAdjusted = true;
mAm.updateOomAdjLocked(r.app, true);
}
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;
}
args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
}
ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
slice.setInlineCountLimit(4);
Exception caughtException = null;
try {
r.app.thread.scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
caughtException = e;
} catch (RemoteException e) {
caughtException = e;
} catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e);
caughtException = e;
}
...
}
- 1.遍歷所有保存在ServiceRecord.pendingStarts中的ServiceRecord.StartItem對(duì)象氢妈,把ServiceRecord.StartItem保存到ServiceRecord的deliveredStarts中,說(shuō)明這些數(shù)據(jù)正在分發(fā)扰才。
- 1.1.調(diào)用bumpServiceExecutingLocked方法繼續(xù)埋下ANR的Handler定時(shí)消息
- 1.2.更新當(dāng)前進(jìn)程的adj應(yīng)用優(yōu)先級(jí)
- 1.3.以ServiceRecord.StartItem的Intent,flag,id構(gòu)成用于在App端分發(fā)ServiceStartArgs對(duì)象允懂,并保存到slice這個(gè)ParceledListSlice<ServiceStartArgs>對(duì)象中.
- 1.4.跨進(jìn)程通信厕怜,調(diào)用ApplicationThread的scheduleServiceArgs方法衩匣。
ActivityThread scheduleServiceArgs
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List<ServiceStartArgs> list = args.getList();
for (int i = 0; i < list.size(); i++) {
ServiceStartArgs ssa = list.get(i);
ServiceArgsData s = new ServiceArgsData();
s.token = token;
s.taskRemoved = ssa.taskRemoved;
s.startId = ssa.startId;
s.flags = ssa.flags;
s.args = ssa.args;
sendMessage(H.SERVICE_ARGS, s);
}
}
這個(gè)方法不斷的循環(huán)遍歷List<ServiceStartArgs>分發(fā)SERVICE_ARGS消息,這個(gè)消息通過(guò)主線程的Looper調(diào)用handleServiceArgs粥航。
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) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
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) {
...
}
}
}
- 1.從mServices獲取到已經(jīng)實(shí)例化的Service對(duì)象琅捏,如果ServiceArgsData的taskRemoved為false(都為false,除非是進(jìn)程銷毀時(shí)候才會(huì)出現(xiàn)taskRemoved是true)递雀,則回調(diào)Service的onStartCommand柄延;否則則回調(diào)onTaskRemoved方法
- 2.QueuedWork調(diào)用waitToFinish方法,阻塞SharePreference把所有的數(shù)據(jù)寫入到磁盤中缀程。
- 3.serviceDoneExecuting 移除ANR超時(shí)消息
bindService 原理
bindService在開(kāi)發(fā)中用的不是很多搜吧,這里稍微提一下他的使用。
首先申明一個(gè)ServiceConnection對(duì)象杨凑,用于綁定服務(wù)端的Service滤奈。
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
MyBinder myBinder = MyBinder.Stub.asInterface(binder);
service = myBinder.getService();
int num = service.getRandomNumber();
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
Intent intent = new Intent(this, TestService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
調(diào)用bindService的方法綁定到某個(gè)Service中。當(dāng)服務(wù)端的service成功回調(diào)onBind方法撩满,我們只需要返回對(duì)應(yīng)的Binder對(duì)象蜒程。就能使用調(diào)用bindService的客戶端在ServiceConnection的onServiceConnected的回調(diào)中獲得Binder對(duì)象。
之后就能通過(guò)這個(gè)Binder調(diào)用本進(jìn)程或者其他進(jìn)程的的方法了伺帘。實(shí)際上我們可以把這個(gè)過(guò)程看成一個(gè)多對(duì)多的服務(wù)-客戶端模型昭躺。多個(gè)客戶端通過(guò)Binder向多服務(wù)端Service通信,每一次我們都可以通過(guò)ComponentName判斷不同服務(wù)返回來(lái)的Binder對(duì)象伪嫁。
bindService的入口 bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
handler, UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- 1.作為參數(shù)的ServiceConnection不能為空领炫。
- 2.通過(guò)LoadedApk的getServiceDispatcher方法把ServiceConnection轉(zhuǎn)化IServiceConnection對(duì)象。
- 3.調(diào)用AMS的bindService方法张咳。
LoadedApk getServiceDispatcher
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null) {
map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
這里面很簡(jiǎn)單帝洪,和BroadcastReceiver的思路很像。動(dòng)態(tài)注冊(cè)的BroadcastReceiver會(huì)封裝成一個(gè)ReceiverDispatcher晶伦,而這里把ServiceConnection封裝成LoadedApk.ServiceDispatcher對(duì)象碟狞。
并且會(huì)把ServiceDispatcher作為value,ServiceConnection作為key緩存一個(gè)map中婚陪。并且以context為key族沃,把這個(gè)臨時(shí)的map作為value緩存起來(lái)。這樣一個(gè)Context就映射有了多個(gè)ServiceDispatcher對(duì)象,也就可以注冊(cè)多個(gè)監(jiān)聽(tīng)被綁定Service狀態(tài)的監(jiān)聽(tīng)者了脆淹。
核心對(duì)象ServiceDispatcher的介紹
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
private final Context mContext;
private final Handler mActivityThread;
private final ServiceConnectionLeaked mLocation;
private final int mFlags;
private RuntimeException mUnbindLocation;
private boolean mForgotten;
private static class ConnectionInfo {
IBinder binder;
IBinder.DeathRecipient deathMonitor;
}
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
}
private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
= new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
mIServiceConnection = new InnerConnection(this);
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mLocation = new ServiceConnectionLeaked(null);
mLocation.fillInStackTrace();
mFlags = flags;
}
...
ServiceConnectionLeaked getLocation() {
return mLocation;
}
ServiceConnection getServiceConnection() {
return mConnection;
}
IServiceConnection getIServiceConnection() {
return mIServiceConnection;
}
....
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
public void death(ComponentName name, IBinder service) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 1, false));
} else {
doDeath(name, service);
}
}
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return;
}
} else {
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
mConnection.onNullBinding(name);
}
}
public void doDeath(ComponentName name, IBinder service) {
synchronized (this) {
ConnectionInfo old = mActiveConnections.get(name);
if (old == null || old.binder != service) {
// Death for someone different than who we last
// reported... just ignore it.
return;
}
mActiveConnections.remove(name);
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
mConnection.onServiceDisconnected(name);
}
private final class RunConnection implements Runnable {
RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
mDead = dead;
}
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final boolean mDead;
}
private final class DeathMonitor implements IBinder.DeathRecipient
{
DeathMonitor(ComponentName name, IBinder service) {
mName = name;
mService = service;
}
public void binderDied() {
death(mName, mService);
}
final ComponentName mName;
final IBinder mService;
}
}
這個(gè)類我們可以對(duì)照BroadcastReceiver的原理進(jìn)行對(duì)照學(xué)習(xí)常空。
- ServiceDispatcher.InnerConnection 這個(gè)InnerConnection對(duì)象是用于監(jiān)聽(tīng)被綁定服務(wù)的狀態(tài),是一個(gè)Binder對(duì)象盖溺,也就說(shuō)可以跨進(jìn)程監(jiān)聽(tīng)被綁定的服務(wù)狀態(tài)漓糙。
一旦ServiceConnection的聲明周期發(fā)生了變化,InnerConnection首先會(huì)得知狀態(tài)的變化烘嘱,從而回調(diào)ServiceDispatcher進(jìn)行處理昆禽。
- ServiceDispatcher 是整個(gè)Service分發(fā)ServiceConnection事件的核心。注意蝇庭,它持有3個(gè)關(guān)鍵對(duì)象:
- mIServiceConnection 代表當(dāng)前ServiceDispatcher對(duì)象對(duì)應(yīng)的Binder對(duì)象
- mActiveConnections 集合醉鳖。每一次當(dāng)一個(gè)新的Service返回了綁定成功的消息后,就會(huì)把這個(gè)Service的類名等信息保存到mActiveConnections中哮内。
- mConnection 就是bindService注冊(cè)進(jìn)來(lái)的監(jiān)聽(tīng)者盗棵,每當(dāng)被綁定的Service發(fā)生了變化,就會(huì)通過(guò)這個(gè)接口回調(diào)北发。
AMS bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId) throws TransactionTooLargeException {
...
synchronized(this) {
return mServices.bindServiceLocked(caller, token, service,
resolvedType, connection, flags, callingPackage, userId);
}
}
核心就是調(diào)用了ActiveServices的bindServiceLocked方法纹因。
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, final IServiceConnection connection, int flags,
String callingPackage, final int userId) throws TransactionTooLargeException {
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
ActivityRecord activity = null;
if (token != null) {
activity = ActivityRecord.isInStackLocked(token);
if (activity == null) {
return 0;
}
}
....
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, callerFg, isBindExternal, allowInstant);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;
boolean permissionsReviewRequired = false;
//此時(shí)config_permissionReviewRequired 是false
if (mAm.mPermissionReviewRequired) {
...
}
final long origId = Binder.clearCallingIdentity();
try {
...
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);
}
b.client.connections.add(c);
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
b.client.hasAboveClient = true;
}
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
s.whitelistManager = true;
}
if (s.app != null) {
updateServiceClientActivitiesLocked(s.app, c, true);
}
clist = mServiceConnections.get(binder);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
permissionsReviewRequired) != null) {
return 0;
}
}
if (s.app != null) {
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
s.app.treatLikeActivity = true;
}
if (s.whitelistManager) {
s.app.whitelistManager = true;
}
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
|| s.app.treatLikeActivity, b.client);
mAm.updateOomAdjLocked(s.app, true);
}
if (s.app != null && b.intent.received) {
try {
c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception e) {
}
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true);
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false);
}
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
} finally {
Binder.restoreCallingIdentity(origId);
}
return 1;
}
- 1.ServiceRecord調(diào)用retrieveAppBindingLocked 根據(jù)當(dāng)前的ServiceRecord,Intent 生成一個(gè)IntentBindRecord對(duì)象后,以Intent.FilterComparison為key琳拨,IntentBindRecord為value保存到ServiceRecord的bindings中瞭恰。如果bindings通過(guò)IntentFilter找到對(duì)應(yīng)存在的IntentBindRecord則直接獲取。
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
public AppBindRecord retrieveAppBindingLocked(Intent intent,
ProcessRecord app) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord i = bindings.get(filter);
if (i == null) {
i = new IntentBindRecord(this, filter);
bindings.put(filter, i);
}
AppBindRecord a = i.apps.get(app);
if (a != null) {
return a;
}
a = new AppBindRecord(this, i, app);
i.apps.put(app, a);
return a;
}
在從IntentBindRecord的apps集合中查找AppBindRecord對(duì)象从绘,找到返回寄疏,找不到則生成全新返回。
final ArrayMap<ProcessRecord, AppBindRecord> apps
= new ArrayMap<ProcessRecord, AppBindRecord>();
如果能夠從bindings集合僵井,通過(guò)意圖過(guò)濾找到對(duì)應(yīng)的IntentBindRecord陕截,又通過(guò)IntentBindRecord的apps集合,通過(guò)ProcessRecord找到AppBindRecord對(duì)象批什。
而AppBindRecord這個(gè)對(duì)象最終會(huì)保存了所有的IServiceConnection农曲。通過(guò)這樣的關(guān)系就能通過(guò)Intent意圖和ProcessRecord進(jìn)程對(duì)象找到需要發(fā)送綁定監(jiān)聽(tīng)對(duì)象。
2.retrieveServiceLocked 從ServiceMap或者PMS中解析出需要綁定或者啟動(dòng)的ServiceRecord對(duì)象驻债,并包裹成ServiceLookupResult對(duì)象返回乳规。
3.把IServiceConnection通過(guò)ConnectionRecord包裹起來(lái)。并且獲取ServiceRecord中的connections這個(gè)ArrayMap集合合呐。
final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
= new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
在每一個(gè)ServiceRecord中暮的,以IBinder對(duì)象為key(也就是IServiceConnection),并且保存以ConnectionRecord集合為value淌实。保存一個(gè)Binder對(duì)應(yīng)多個(gè)ServiceDispatcher的情況冻辩。
最后把這個(gè)包裝了IServiceConnection的ConnectionRecord保存到connections的value的list中猖腕。
4.AppBinderRecord的connections集合也保存了ConnectionRecord對(duì)象。
5.如果當(dāng)前調(diào)用bindService的ContextImpl是一個(gè)Activity恨闪,那么就會(huì)在對(duì)應(yīng)的ActivityToken的HashSet<ConnectionRecord>中保存ConnectionRecord倘感。
6.在ProcessRecord創(chuàng)建或者獲取ArraySet<ConnectionRecord>對(duì)象,并把新的ConnectionRecord保存到這個(gè)Set中咙咽。
7.同樣在ActiveServices中有一個(gè)和ServiceRecord相同的connections集合老玛。
8.如果打開(kāi)了Context.BIND_AUTO_CREATE這標(biāo)志位,說(shuō)明此時(shí)bindService執(zhí)行中發(fā)現(xiàn)Service沒(méi)有啟動(dòng)钧敞,則調(diào)用bringUpServiceLocked進(jìn)行啟動(dòng)Service蜡豹。如果bringUpServiceLocked成功的啟動(dòng)了Service,就不繼續(xù)走下面的邏輯犁享,直接返回了余素。
9.下面就是Service默認(rèn)是已經(jīng)創(chuàng)建,Service的進(jìn)程存活炊昆,且IntentBindRecord的receiver為true。則會(huì)調(diào)用ConnectionRecord中的IServiceConnection這個(gè)Binder對(duì)象的跨進(jìn)程方法connected威根,也就是調(diào)用ServiceDispatcher的InnerConnection的connected方法凤巨。
我們來(lái)考察一下之前在bringUpServiceLocked中忽略過(guò)的綁定Service邏輯,也就是在realStartServiceLocked調(diào)用的requestServiceBindingLocked方法洛搀。
requestServiceBindingLocked
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
break;
}
}
}
能看到實(shí)際上那個(gè)就是獲取ServiceRecord中所有的IntentBindRecord敢茁,調(diào)用requestServiceBindingLocked方法進(jìn)行綁定。
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
if (r.app == null || r.app.thread == null) {
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
} catch (TransactionTooLargeException e) {
...
} catch (RemoteException e) {
...
return false;
}
}
return true;
}
核心方法就是跨進(jìn)程調(diào)用ApplicationThread的scheduleBindService方法留美。
ActivityThread handleBindService
這個(gè)方法會(huì)通過(guò)ActivityThread主線程handler發(fā)送綁定服務(wù)的消息彰檬,也就是handleBindService
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManager.getService().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
...
}
}
}
- 1.調(diào)用Service的onBind方法,獲取從Service中返回的允許客戶端操作的Binder對(duì)象谎砾》瓯叮跨進(jìn)程調(diào)用AMS的publishService方法,把需要返回的Binder返回給客戶端景图。
- 2.如果從BindServiceData中判斷到當(dāng)前的Service需要重新綁定則回調(diào)onRebind方法较雕。調(diào)用serviceDoneExecuting方法告訴AMS已經(jīng)接受了當(dāng)前的執(zhí)行任務(wù)。從而拆下ANR消息挚币。
AMS publishService
public void publishService(IBinder token, Intent intent, IBinder service) {
...
synchronized(this) {
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
continue;
}
try {
c.conn.connected(r.name, service, false);
} catch (Exception e) {
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
此時(shí)就會(huì)獲得Intent的意圖亮蒋,通過(guò)ServiceRecord的bindings中找到IntentBindRecord,IntentBindRecord設(shè)置receiver為true妆毕。
遍歷ServiceRecord的connections集合中所有的ConnectionRecord慎玖,如果發(fā)現(xiàn)Service的Intent意圖過(guò)濾不匹配則進(jìn)入下一個(gè)loop中;如果符合意圖笛粘,則調(diào)用ConnectionRecord的IServiceConnection的connected方法趁怔。這個(gè)方法就會(huì)跨進(jìn)程調(diào)用的ServiceDisptacher中InnerConnection的connected方法,把從Service的onBind返回的Binder對(duì)象傳遞到InnerConnection中远舅。
serviceDoneExecutingLocked 執(zhí)行完成任務(wù)行為,拆除Service的ANR消息痕钢。
InnerConnection 接受connect的行為
public void connected(ComponentName name, IBinder service, boolean dead)
throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service, dead);
}
}
當(dāng)InnerConnection接受到了connected的調(diào)用图柏,這里就會(huì)調(diào)用ServiceDispatcher的connected,把IBinder傳遞過(guò)來(lái)任连。注意這個(gè)IBinder就是從Service的onBind方法返回的Binder對(duì)象蚤吹。
public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
doConnected(name, service, dead);
}
}
核心就是調(diào)用doConnected,或者調(diào)用RunConnection Runnable對(duì)象執(zhí)行其中的run方法随抠。
RunConnection run
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
這里根據(jù)mCommand來(lái)執(zhí)行doConnected進(jìn)行ServiceConnection的綁定回調(diào)還是解綁回調(diào)裁着。
這里是綁定,mCommand也為1拱她。我們直接看doConnected二驰。
ServiceDispatcher doConnected
public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return;
}
} else {
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (dead) {
mConnection.onBindingDied(name);
}
if (service != null) {
mConnection.onServiceConnected(name, service);
} else {
mConnection.onNullBinding(name);
}
}
1.把傳遞給客戶端的Binder 封裝到ConnectionInfo中。如果通過(guò)ComponentName查找到秉沼,本次發(fā)送給客戶端的Binder和上一次的對(duì)象一致則直接返回桶雀。
2.為當(dāng)前的Binder通過(guò)linkToDeath綁定Binder的死亡監(jiān)聽(tīng)。如果這個(gè)發(fā)送給客戶端操作的Binder對(duì)象死亡了唬复,則會(huì)回調(diào)DeathMonitor矗积,移除mActiveConnections中的對(duì)應(yīng)Service名字的ConnectionInfo。這樣就移除了還在活躍的Binder的緩存對(duì)象敞咧。
3.mActiveConnections 根據(jù)當(dāng)前傳遞過(guò)來(lái)的Service的ComponentName為key棘捣,保存ConnectionInfo。
4.如果上一次的Binder對(duì)象不為空則解綁死亡監(jiān)聽(tīng)休建,先回調(diào)onServiceDisconnected方法乍恐,告訴這個(gè)Binder已經(jīng)解開(kāi)了鏈接。如果此時(shí)Serice還是經(jīng)歷了stop的方法需要銷毀了测砂,還會(huì)執(zhí)行onBindingDied方法茵烈,告訴客戶端,遠(yuǎn)程端已經(jīng)死亡了邑彪。
5.如果是新的不同對(duì)象瞧毙,則會(huì)調(diào)用onServiceConnected分發(fā)Binder對(duì)象,告訴客戶端已經(jīng)綁定了寄症。
Service的銷毀
Service還能通過(guò)stopService結(jié)束當(dāng)前的服務(wù)宙彪。
private boolean stopServiceCommon(Intent service, UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
int res = ActivityManager.getService().stopService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to stop service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
核心就是調(diào)用AMS的stopService方法麦撵。而這個(gè)方法實(shí)際上就是調(diào)用ActiveServices的stopService方法鸿吆。
ActiveServices stopServiceLocked
private void stopServiceLocked(ServiceRecord service) {
...
bringDownServiceIfNeededLocked(service, false, false);
}
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
boolean hasConn) {
...
bringDownServiceLocked(r);
}
核心就是bringDownServiceLocked方法。
bringDownServiceLocked
private final void bringDownServiceLocked(ServiceRecord r) {
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
for (int i=0; i<c.size(); i++) {
ConnectionRecord cr = c.get(i);
cr.serviceDead = true;
try {
cr.conn.connected(r.name, null, true);
} catch (Exception e) {
}
}
}
if (r.app != null && r.app.thread != null) {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
if (ibr.hasBound) {
try {
bumpServiceExecutingLocked(r, false, "bring down unbind");
mAm.updateOomAdjLocked(r.app, true);
ibr.hasBound = false;
ibr.requested = false;
r.app.thread.scheduleUnbindService(r,
ibr.intent.getIntent());
} catch (Exception e) {
serviceProcessGoneLocked(r);
}
}
}
}
if (r.fgRequired) {
r.fgRequired = false;
r.fgWaiting = false;
mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
...
}
r.destroyTime = SystemClock.uptimeMillis();
final ServiceMap smap = getServiceMapLocked(r.userId);
ServiceRecord found = smap.mServicesByName.remove(r.name);
...
smap.mServicesByIntent.remove(r.intent);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r, 0, true);
for (int i=mPendingServices.size()-1; i>=0; i--) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
}
}
...
if (r.app != null) {
...
if (r.app.thread != null) {
updateServiceForegroundLocked(r.app, false);
try {
bumpServiceExecutingLocked(r, false, "destroy");
mDestroyingServices.add(r);
r.destroying = true;
mAm.updateOomAdjLocked(r.app, true);
r.app.thread.scheduleStopService(r);
} catch (Exception e) {
serviceProcessGoneLocked(r);
}
} else {
}
} else {
}
if (r.bindings.size() > 0) {
r.bindings.clear();
}
...
}
這個(gè)過(guò)程很簡(jiǎn)單望门,可以根據(jù)三個(gè)循環(huán)分為三個(gè)部分:
1.在銷毀之前篮迎,遍歷ServiceRecord中所有的InnerConnection遠(yuǎn)程鏈接男图,并且調(diào)用connected方法示姿,傳遞一個(gè)空的Binder對(duì)象,銷毀存儲(chǔ)在LoadedApk.ServiceDispatcher活躍的綁定監(jiān)聽(tīng)逊笆。
2.遍歷ServiceRecord所有的bindings存儲(chǔ)的綁定的IntentBindRecord栈戳。先調(diào)用bumpServiceExecutingLocked埋下一個(gè)ANR消息。并且跨進(jìn)程調(diào)用對(duì)應(yīng)進(jìn)程的scheduleUnbindService方法难裆,把IntentBindRecord中存儲(chǔ)的啟動(dòng)的意圖傳遞過(guò)去子檀。
3.如果是前臺(tái)的服務(wù)還會(huì)移除SERVICE_FOREGROUND_TIMEOUT_MSG,前臺(tái)服務(wù)執(zhí)行任務(wù)超時(shí)ANR乃戈。
4.如果進(jìn)程還存活褂痰,則bumpServiceExecutingLocked埋下銷毀Service的ANR。更新進(jìn)程的adj優(yōu)先級(jí)后症虑,跨進(jìn)程調(diào)用scheduleStopService方法缩歪。
我們來(lái)看看在ApplicationThread中的scheduleUnbindService和scheduleStopService。
ActivityThread handleUnbindService
scheduleUnbindService最后會(huì)調(diào)用scheduleUnbindService方法谍憔。
private void handleUnbindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
boolean doRebind = s.onUnbind(data.intent);
try {
if (doRebind) {
ActivityManager.getService().unbindFinished(
data.token, data.intent, doRebind);
} else {
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} catch (Exception e) {
}
}
}
從mServices緩存中獲取Service對(duì)象匪蝙,并執(zhí)行onUnbind方法回調(diào)。如果onUnbind返回true說(shuō)明需要重新綁定韵卤,則調(diào)用unbindFinished方法骗污;否則則調(diào)用serviceDoneExecuting完成當(dāng)前任務(wù)的執(zhí)行。
ActivityThread handleStopService
private void handleStopService(IBinder token) {
Service s = mServices.remove(token);
if (s != null) {
try {
s.onDestroy();
s.detachAndCleanUp();
Context context = s.getBaseContext();
if (context instanceof ContextImpl) {
final String who = s.getClassName();
((ContextImpl) context).scheduleFinalCleanup(who, "Service");
}
QueuedWork.waitToFinish();
try {
ActivityManager.getService().serviceDoneExecuting(
token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
} catch (RemoteException e) {
}
} catch (Exception e) {
}
} else {
}
}
- 1.調(diào)用Service的onDestroy方法
- 2.Service的detachAndCleanUp 銷毀保存在Service中的ServiceRecord這個(gè)Binder對(duì)象
- 3.QueuedWork 等待SP的寫入消息的落盤
- 4.serviceDoneExecuting 通知ActiveServices的移除銷毀ANR的Handler消息
總結(jié)
Service的啟動(dòng)原理實(shí)際上很簡(jiǎn)單沈条,我這邊分為startService和bindService兩個(gè)方法將進(jìn)行總結(jié)。
startService實(shí)際上和bindService執(zhí)行流程十分相似诅炉。只是bindService多執(zhí)行了幾個(gè)步驟蜡歹,直接上bindService和stopService的時(shí)序圖:
bindService 與 startService
bindService綁定服務(wù),如果在bindService方法就是BIND_AUTO_CREATE的標(biāo)志位涕烧,就會(huì)包含了startService的邏輯月而。這里就用BIND_AUTO_CREATE的邏輯來(lái)統(tǒng)一說(shuō)說(shuō)整個(gè)流程都做了什么。
-
1.在bindService進(jìn)入AMS之前议纯,就會(huì)調(diào)用LoadedApk.getServiceDispatcher獲取一個(gè)ServiceDispatcher對(duì)象父款。
- 1.1.而ServiceDispatcher這個(gè)對(duì)象包含了一個(gè)InnerConnection Binder對(duì)象。這個(gè)對(duì)象是用于直接溝通AMS的那邊的回調(diào)瞻凤,直接回調(diào)到ServiceConnection中憨攒。
- 1.2.ServiceDispatcher中本身就有mServices緩存,它緩存了已經(jīng)啟動(dòng)過(guò)的ServiceDispatcher阀参。是以當(dāng)前ContextImpl為value肝集,以
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>
為value的Map。這樣就會(huì)在同一個(gè)上下文中創(chuàng)建相同的服務(wù)分發(fā)者蛛壳。
-
2.進(jìn)入AMS后杏瞻,首先會(huì)通過(guò)
retrieveServiceLocked
從AMS中查找兩個(gè)級(jí)別的緩存所刀,一個(gè)是緩存在AMS中的緩存,一個(gè)是緩存在PMS的緩存捞挥。- 2.1.AMS的緩存的緩存中又分為兩個(gè)緩存浮创。一個(gè)是通過(guò)類名+包名查找ServiceRecord;一個(gè)是通過(guò)意圖過(guò)濾器查找Service砌函。
- 2.2.PMS中則是通過(guò)解析apk的AndroidManifest.xml的xml標(biāo)簽獲得的斩披。
3.如果發(fā)現(xiàn)ServiceRecord已經(jīng)綁定了ProcessRecord說(shuō)明已經(jīng)啟動(dòng)過(guò)了,則調(diào)用scheduleServiceArgs胸嘴,觸發(fā)Service的onStartCommand返回雏掠。
4.如果發(fā)現(xiàn)沒(méi)有綁定過(guò)則說(shuō)明需要啟動(dòng)過(guò),則scheduleCreateService劣像,調(diào)用ActivityThread的handleCreateService乡话,依次執(zhí)行Service的attach方法綁定ServiceRecord以及onCreate方法,并把新的Service緩存起來(lái)耳奕。
5.在AMS的
bindServiceLocked
中绑青,會(huì)把IServiceConnection綁定到ServiceRecord的ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
集合中。注意在IntentBindRecord集合中就保存了一個(gè)特殊的集合ArrayMap<ProcessRecord, AppBindRecord>
屋群,而AppBindRecord實(shí)際上就是持有了核心的ConnectionRecord集合闸婴。而ConnectionRecord就是正在的持有IServiceConnection。
弄的這么復(fù)雜芍躏,Google官方實(shí)際上指向做一件事:可以通過(guò)意圖確定當(dāng)前緩存的IServiceConnection 所指向的客戶端進(jìn)程邪乍,客戶端的監(jiān)聽(tīng)Service綁定接口對(duì)象。
6.
requestServiceBindingsLocked
方法會(huì)遍歷所有綁定在ServiceRecord的binding集合对竣,并且調(diào)用每一個(gè)ServiceRecord對(duì)應(yīng)的Service的onBind的方法庇楞。7.onBind返回 Service服務(wù)端允許客戶端操作的Binder對(duì)象,則調(diào)用AMS的publishService否纬。在AMS中則會(huì)查找ServiceRecord的bindings集合吕晌,遍歷每一個(gè)IServiceConnection.connected 嘗試回調(diào)在
bindService
方法中綁定的ServiceConnection接口。8.IServiceConnection Binder對(duì)象在客戶端實(shí)際上對(duì)應(yīng)就是
ServiceDispatcher
中的InnerConnection
對(duì)象临燃。這個(gè)對(duì)象在connected
方法會(huì)調(diào)用RunConnection
的run方法睛驳,他會(huì)調(diào)用ActivityThread的Handler中執(zhí)行doConnected
把服務(wù)端分發(fā)過(guò)來(lái)Binder緩存到mActiveConnections,最后回調(diào)ServiceConnection.onServiceConnected
9.當(dāng)啟動(dòng)和綁定都完成后膜廊,就會(huì)調(diào)用
sendServiceArgsLocked
方法乏沸。這個(gè)方法就是調(diào)用ActivityThread. scheduleServiceArgs
方法。而這個(gè)方法最終調(diào)用Service的onStartCommand方法溃论。注意這里分發(fā)的Intent就是之前啟動(dòng)service的Intent屎蜓。當(dāng)然onStartCommand會(huì)根據(jù)返回值在serviceDoneExecuting方法中決定了當(dāng)Service執(zhí)行完onStartCommand是否需要重啟:START_STICKY 如果Service調(diào)用了onStartCommand之后被銷毀,會(huì)重新啟動(dòng)钥勋,如果中間沒(méi)任何命令傳遞給Service炬转,此時(shí)Intent為null辆苔。
START_NOT_STICKY 如果Service調(diào)用了onStartCommand之后被銷毀,不會(huì)重啟扼劈。
START_REDELIVER_INTENT 如果Service調(diào)用了onStartCommand之后被銷毀驻啤,會(huì)重新啟動(dòng),如果中間沒(méi)任何命令傳遞給Service荐吵,此時(shí)Intent為初始數(shù)骑冗。
START_STICKY_COMPATIBILITY 兼容模式,不保證onStartCommand之后銷毀會(huì)重啟先煎。
在這個(gè)過(guò)程中又幾個(gè)比較重要的緩存對(duì)象:
Service銷毀
在bringDownServiceLocked
做了三件事情:
- 1.調(diào)用所有ServiceConnection的回調(diào)贼涩,回調(diào)onServiceDisconnected方法,并從活躍的Binder集合中移除
- 2.回調(diào)Service的onUnBind方法
- 3.回調(diào)Service的onDestroy方法和detachAndCleanUp銷毀ServiceRecord
Service 的ANR與注意
Service的ANR實(shí)際上是由bumpServiceExecutingLocked
方法埋下的一個(gè)超時(shí)的ANR薯蝎,超時(shí)時(shí)間根據(jù)是啟動(dòng)后臺(tái)服務(wù)還是前臺(tái)服務(wù):
- 前臺(tái)服務(wù)是10秒
- 后臺(tái)服務(wù) 不過(guò)進(jìn)程不是在ProcessList.SCHED_GROUP_BACKGROUND進(jìn)程組中是 20秒
- 后臺(tái)服務(wù) 不過(guò)進(jìn)程在ProcessList.SCHED_GROUP_BACKGROUND進(jìn)程組中是 200秒
當(dāng)每一個(gè)Service執(zhí)行完一個(gè)任務(wù)之后遥倦,都會(huì)執(zhí)行serviceDoneExecutingLocked方法,把ActiveServices中的Handler的ANR倒計(jì)時(shí)消息移除占锯。
有一點(diǎn)比較有意思的一點(diǎn)袒哥,啟動(dòng)服務(wù)有一個(gè)常見(jiàn)的問(wèn)題,當(dāng)通過(guò)startService啟動(dòng)Service的時(shí)候消略,會(huì)爆出錯(cuò)誤堡称。
Not allowed to start service Intent{xxxx}
禁止打開(kāi)后臺(tái)服務(wù)。在上面也有體現(xiàn):如果startService返回的包名不是正常的包名而是一個(gè)?
則會(huì)爆出這種錯(cuò)誤艺演。
if (forcedStandby || (!r.startRequested && !fgRequired)) {
// Before going further -- if this app is not allowed to start services in the
// background, then at this point we aren't going to let it period.
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
...
UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
能看到如果此時(shí)fgRequired為false也就是非前臺(tái)服務(wù)却紧,會(huì)走入getAppStartModeLocked的校驗(yàn)。
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
UidRecord uidRec = mActiveUids.get(uid);
if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
boolean ephemeral;
...
final int startMode = (alwaysRestrict)
? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
: appServicesRestrictedInBackgroundLocked(uid, packageName,
packageTargetSdk);
...
return startMode;
}
return ActivityManager.APP_START_MODE_NORMAL;
}
mActiveUids收集的是啟動(dòng)的活躍應(yīng)用進(jìn)程uid胎撤。
- uidRec為空啄寡,必定是沒(méi)有啟動(dòng)或者是后臺(tái)進(jìn)程
- uidRec.idle為true,說(shuō)明此時(shí)是啟動(dòng)過(guò)了但是呆在了后臺(tái)超過(guò)60秒哩照,從前臺(tái)變化為后臺(tái)進(jìn)程。
這兩個(gè)情況都會(huì)appServicesRestrictedInBackgroundLocked進(jìn)行校驗(yàn):
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
if (packageTargetSdk >= Build.VERSION_CODES.O) {
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
uid, packageName);
switch (appop) {
case AppOpsManager.MODE_ALLOWED:
// If force-background-check is enabled, restrict all apps that aren't whitelisted.
if (mForceBackgroundCheck &&
!UserHandle.isCore(uid) &&
!isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ true)) {
return ActivityManager.APP_START_MODE_DELAYED;
}
...
}
校驗(yàn)出了不在白名單中懒浮,就會(huì)返回APP_START_MODE_DELAYED飘弧。此時(shí)不是APP_START_MODE_NORMAL就會(huì)返回帶了?
的包名從而報(bào)錯(cuò)。
一般的砚著,我們還會(huì)作如下處理從startService改成startForegroundService次伶。但是這樣就又爆出了全新的錯(cuò)誤。
Context.startForegroundService() did not then call Service.startForeground()
android.app.ActivityThread$H.handleMessage(ActivityThread.java:2204)
寫高版本的service 稍不注意都會(huì)遇到這種情況稽穆。這是因?yàn)槟銢](méi)有在Service中使用startForeground方法冠王。如果我們超過(guò)10秒沒(méi)有一般我們都會(huì)使用startForeground啟動(dòng)一個(gè)通知,告訴用戶正在前臺(tái)運(yùn)行舌镶。
而startForeground實(shí)際上是移除超時(shí)ANR的行為柱彻。
但是有時(shí)候豪娜,就算startForeground還是會(huì)報(bào)錯(cuò),即使把時(shí)機(jī)盡可能的提前了哟楷,放在了onCreate中瘤载,還是會(huì)報(bào)錯(cuò)了。
我們能夠看到實(shí)際上這個(gè)過(guò)程中每當(dāng)執(zhí)行完Service的onStartCommand卖擅,就會(huì)等待SP寫入到磁盤的阻塞鸣奔,也有可能是這個(gè)時(shí)候的寫入時(shí)間過(guò)長(zhǎng)了導(dǎo)致的ANR,詳情可看SharedPreferences源碼解析。
另一種可能就是因?yàn)檎麄€(gè)流程都是在主線程中執(zhí)行的惩阶,看看主線程有沒(méi)有其他太過(guò)耗時(shí)的行為挎狸,導(dǎo)致來(lái)不及移除前臺(tái)服務(wù)的ANR消息。
后記
到這里Service已經(jīng)全部解析了断楷,接下來(lái)我們來(lái)看看四大組件最后一個(gè)ContentProvider锨匆。