前言
我们已经了解了BroadcastReceiver的原理,我们再来看看四大组件之一的Service是怎么启动的,以及怎么运行的原理。
如果遇到什么问题可以来到https://www.jianshu.com/p/c4927c0b80a9本文下进行交流
正文
启动Service的入口就是startService和bindService方法。我们先来看看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();
}
}
此时调用的就是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是一个ActiveServices对象。这个对象是在AMS的构造函数中初始化好的。
这里调用了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;
}
核心流程有如下三个:
- 1.retrieveServiceLocked 从ActiveServices中获取ServiceLookupResult 需要启动Service对象
- 2.往ServiceRecord对象的pendingStarts几个中添加一个ServiceRecord.StartItem对象。而这个对象就是之后Service声明周期中onCommandStart的回调参数
- 3.startServiceInnerLocked 执行Service的启动的流程。
注意这里addToStarting是一个比较关键的判断,addToStarting默认为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) {
}
如果此时不是启动前台服务,则需要进一步进行处理。如果ProcessRecord为空或者curProcState大于PROCESS_STATE_RECEIVER这个优先级数值;也就是优先级更小。
为了避免此时App应用是没有任何的前台ui,或者App应用还没有声明。避免有的App通过startService进行应用的包活或者拉起应用。就会进行如下能够存在的最大后台服务数量,则放入mDelayedStartList中进行延时启动后台服务,现在直接返回了。
不然则说明能够允许启动后台服务, 就设置为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.通过UserController.handleIncomingUser获取的userId,从getServiceMapLocked方法通过userId中获取ServiceMap对象。这个对象保存了已经启动过所有的Service对象。
- 1.1.ServiceMap保存如下几种用于查询映射结构:
final ArrayMap mServicesByName = new ArrayMap<>();
final ArrayMap mServicesByIntent = new ArrayMap<>();
通过ComponentName也就是包名和类名查找ServiceRecord;通过Intent意图过滤找到ServiceRecord。·
1.2.如果能够获取到,则直接获取ServiceMap中的ServiceRecord对象,并包裹成ServiceLookupResult对象返回。
2.如果Intent中的ComponentName不为空,ServiceMap则通过ComponentName查询缓存ServiceRecord。
3.如果还是找不到,且isBindExternal为false(此时就是false),则通过过滤条件从ServiceMap查找缓存ServiceRecord。
4.如果设置了FLAG_EXTERNAL_SERVICE,且ServiceRecord找到了,但是此时ServiceRecord中的包名和调用方的包名不一致,则把找到的缓存ServiceRecord设置为空。如果设置了FLAG_EXTERNAL_SERVICE这个flag,也就是设置了
android:externalService
这个xml标签。这个标签代表了Service可以绑定调用方的进程;因此这个标志位支持跨进程绑定但是不支持跨包绑定。-
5.如果找不到ServiceRecord,那么需要新建一个ServiceRecord。
5.1.先通过PMS的resolveService方法,从PMS中获取一个ResolveInfo对象。这个对象能够获取安装时候通过解析AndroidManifest.xml到的ServiceInfo对象。
5.2.并且isBindExternal为true。此时会封装一个新的ServiceInfo,并且通过Intent的setComponent,获取此时真正需要启动Service对应的包名和类名。在这里isBindExternal为false,startService并不会走这个逻辑。
5.3.因为可能会在5.2的时候获取真实需要启动的包名,此时再通过mServicesByName找一次是否能找到缓存的Service。
5.4.到了这个步骤说明真的找不到了ServiceRecord对象。先生成Intent.FilterComparison对象。把ComponentName作为key和ServiceRecord作为value保存到mServicesByName;把Intent.FilterComparison作为key,ServiceRecord作为value保存到mServicesByIntent。
5.5.如果在mPendingServices队列中发现了这个需要新生成的Service对象对应的包名类名,就从mPendingServices中移除一样的包名类名。
5.6.最后校验权限返回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返回了异常,就返回一个特殊的ComponentName对象。
addToStarting为true,说明此时是一个能够启动的后台服务,则ServiceRecord添加到mStartingBackground中。如果mStartingBackground的数量为0,则直接调用ServiceMap的rescheduleDelayedStartsLocked启动后台服务。
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已经保存了app远程端的Binder对象,说明该Service已经启动过了,则直接执行sendServiceArgsLocked执行Service的其他声明周期。
2.如果ServiceRecord的delay属性为true,则从mDelayedStartList移除该ServiceRecord,delay设置为true。说明此时开始启动服务了。
-
3.如果AndroidManifest中的service标签设置了
android:isolatedProcess
,说明这个Service需要启动在另一个隔离的进程中执行。我们先只考虑false的情况,此时说明是app在app进程中启动Service。- 3.1.getProcessRecordLocked获取当前App进程的ProcessRecord,如果ProcessRecord不为空,则说明该进程已经启动了。此时为ProcessRecord的addPackage后,调用realStartServiceLocked 启动Service。
-
4.如果
android:isolatedProcess
为true,说明每一次启动Service都应该是一个新的隔离进程。把ServiceRecord设置给app。那么app这个ProcessRecord对象就是空,此时permissionsReviewRequired就是false。每执行一次这个startProcessLocked方法,说明android:isolatedProcess
标志为每一次都是启动app进程对象。- 4.1.调用一次bringDownServiceLocked方法
- 4.2.mPendingServices如果不包含需要启动的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.启动Service前,先把ServiceRecord添加到ProcessRecord的services集合,说明这个Service正在运行了。bumpServiceExecutingLocked埋入Service的ANR消息,更新当前App应用的adj优先级
- 2.跨进程调用App端的ApplicationThread的scheduleCreateService方法,创建Service对象,执行onCreate
- 3.如果创建的过程中失败了,说明可能App端要么死掉,要么就是创建过程发生了异常,此时会调用serviceDoneExecutingLocked方法,执行Service的完成事务的任务。
- 4.如果发现保存已经销毁的Service对象集合mDestroyingServices并没有这个Service,就会再一次的尝试启动。
- 5.requestServiceBindingLocked 执行服务绑定的Connection对象。注意此时是startService,因此不会有任何挂载的Connection对象。只有bindService才会执行。
- 6.sendServiceArgsLocked 执行Service发送数据
- 7.移除mDelayedStartList中的ServiceRecord
这几个关键的步骤,让我们依次的考察,先来看看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;
}
如果第一次启动就走第一个if的分支:
- 1.ProcessRecord的executingServices 正在执行任务的Service集合添加ServiceRecord对象
- 2.执行scheduleServiceTimeoutLocked ANR超时埋点。
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思路一样,通过一个延时的Handler,如果达到时间了还没有移除这个Handler消息则报ANR异常。
这里根据启动前台和后台分为两种超时时间:
// 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;
前台分别是10秒,后台服务不属于后台进程组(判断adj是否在SCHED_GROUP_BACKGROUND)是20秒,后台服务属于后台进程组 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);
}
把数据封装成CreateServiceData后,通过Handler调用如下方法:
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.通过AppComponentFactory反射创建一个全新的Service对象
- 2.通过ContextImpl.createAppContext 创建一个新的Context。
- 3.获取LoadedApk中的Application对象,调用Service的attach方法绑定Context。
- 4.调用Service的onCreate方法
- 5.Service以ServiceRecord的token为key缓存到mServices这个Map对象中中
- 5.调用AMS的serviceDoneExecuting方法。
透三点的核心原理可以看我写的的Application创建和BroadcastReceiver原理两篇文章。来看看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;
}
很简单就是保存了传递过来的参数,值得注意的是这个IBinder对象其实就是指ServiceRecord对象。
接着执行Service.onCreate这个空实现的方法。
AMS serviceDoneExecuting
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
本质上还是调用了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,所不会做更多的处理。 最后执行了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,说明该ServiceRecord只执行了一次启动。接着移除executingServices中的ServiceRecord,说明正在执行的Service已经处理完毕了。
- 2.如果executingServices大小为0,则移除ActivityManagerService.SERVICE_TIMEOUT_MSG这个Handler消息,也就是拆开了ANR的消息
- 3.如果执行的是结束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 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 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对象,把ServiceRecord.StartItem保存到ServiceRecord的deliveredStarts中,说明这些数据正在分发。
- 1.1.调用bumpServiceExecutingLocked方法继续埋下ANR的Handler定时消息
- 1.2.更新当前进程的adj应用优先级
- 1.3.以ServiceRecord.StartItem的Intent,flag,id构成用于在App端分发ServiceStartArgs对象,并保存到slice这个ParceledListSlice
对象中. - 1.4.跨进程通信,调用ApplicationThread的scheduleServiceArgs方法。
ActivityThread scheduleServiceArgs
public final void scheduleServiceArgs(IBinder token, ParceledListSlice args) {
List 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);
}
}
这个方法不断的循环遍历List
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获取到已经实例化的Service对象,如果ServiceArgsData的taskRemoved为false(都为false,除非是进程销毁时候才会出现taskRemoved是true),则回调Service的onStartCommand;否则则回调onTaskRemoved方法
- 2.QueuedWork调用waitToFinish方法,阻塞SharePreference把所有的数据写入到磁盘中。
- 3.serviceDoneExecuting 移除ANR超时消息
bindService 原理
bindService在开发中用的不是很多,这里稍微提一下他的使用。
首先申明一个ServiceConnection对象,用于绑定服务端的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);
调用bindService的方法绑定到某个Service中。当服务端的service成功回调onBind方法,我们只需要返回对应的Binder对象。就能使用调用bindService的客户端在ServiceConnection的onServiceConnected的回调中获得Binder对象。
之后就能通过这个Binder调用本进程或者其他进程的的方法了。实际上我们可以把这个过程看成一个多对多的服务-客户端模型。多个客户端通过Binder向多服务端Service通信,每一次我们都可以通过ComponentName判断不同服务返回来的Binder对象。
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.作为参数的ServiceConnection不能为空。
- 2.通过LoadedApk的getServiceDispatcher方法把ServiceConnection转化IServiceConnection对象。
- 3.调用AMS的bindService方法。
LoadedApk getServiceDispatcher
public final IServiceConnection getServiceDispatcher(ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null;
ArrayMap 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();
}
}
这里面很简单,和BroadcastReceiver的思路很像。动态注册的BroadcastReceiver会封装成一个ReceiverDispatcher,而这里把ServiceConnection封装成LoadedApk.ServiceDispatcher对象。
并且会把ServiceDispatcher作为value,ServiceConnection作为key缓存一个map中。并且以context为key,把这个临时的map作为value缓存起来。这样一个Context就映射有了多个ServiceDispatcher对象,也就可以注册多个监听被绑定Service状态的监听者了。
核心对象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 mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference(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 mActiveConnections
= new ArrayMap();
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;
}
}
这个类我们可以对照BroadcastReceiver的原理进行对照学习。
- ServiceDispatcher.InnerConnection 这个InnerConnection对象是用于监听被绑定服务的状态,是一个Binder对象,也就说可以跨进程监听被绑定的服务状态。
一旦ServiceConnection的声明周期发生了变化,InnerConnection首先会得知状态的变化,从而回调ServiceDispatcher进行处理。
- ServiceDispatcher 是整个Service分发ServiceConnection事件的核心。注意,它持有3个关键对象:
- mIServiceConnection 代表当前ServiceDispatcher对象对应的Binder对象
- mActiveConnections 集合。每一次当一个新的Service返回了绑定成功的消息后,就会把这个Service的类名等信息保存到mActiveConnections中。
- mConnection 就是bindService注册进来的监听者,每当被绑定的Service发生了变化,就会通过这个接口回调。
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);
}
}
核心就是调用了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;
//此时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 clist = s.connections.get(binder);
if (clist == null) {
clist = new ArrayList();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
if (activity != null) {
if (activity.connections == null) {
activity.connections = new HashSet();
}
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();
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调用retrieveAppBindingLocked 根据当前的ServiceRecord,Intent 生成一个IntentBindRecord对象后,以Intent.FilterComparison为key,IntentBindRecord为value保存到ServiceRecord的bindings中。如果bindings通过IntentFilter找到对应存在的IntentBindRecord则直接获取。
final ArrayMap bindings
= new ArrayMap();
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对象,找到返回,找不到则生成全新返回。
final ArrayMap apps
= new ArrayMap();
如果能够从bindings集合,通过意图过滤找到对应的IntentBindRecord,又通过IntentBindRecord的apps集合,通过ProcessRecord找到AppBindRecord对象。
而AppBindRecord这个对象最终会保存了所有的IServiceConnection。通过这样的关系就能通过Intent意图和ProcessRecord进程对象找到需要发送绑定监听对象。
2.retrieveServiceLocked 从ServiceMap或者PMS中解析出需要绑定或者启动的ServiceRecord对象,并包裹成ServiceLookupResult对象返回。
3.把IServiceConnection通过ConnectionRecord包裹起来。并且获取ServiceRecord中的connections这个ArrayMap集合。
final ArrayMap> connections
= new ArrayMap>();
在每一个ServiceRecord中,以IBinder对象为key(也就是IServiceConnection),并且保存以ConnectionRecord集合为value。保存一个Binder对应多个ServiceDispatcher的情况。
最后把这个包装了IServiceConnection的ConnectionRecord保存到connections的value的list中。
4.AppBinderRecord的connections集合也保存了ConnectionRecord对象。
5.如果当前调用bindService的ContextImpl是一个Activity,那么就会在对应的ActivityToken的HashSet
中保存ConnectionRecord。 6.在ProcessRecord创建或者获取ArraySet
对象,并把新的ConnectionRecord保存到这个Set中。 7.同样在ActiveServices中有一个和ServiceRecord相同的connections集合。
8.如果打开了Context.BIND_AUTO_CREATE这标志位,说明此时bindService执行中发现Service没有启动,则调用bringUpServiceLocked进行启动Service。如果bringUpServiceLocked成功的启动了Service,就不继续走下面的逻辑,直接返回了。
9.下面就是Service默认是已经创建,Service的进程存活,且IntentBindRecord的receiver为true。则会调用ConnectionRecord中的IServiceConnection这个Binder对象的跨进程方法connected,也就是调用ServiceDispatcher的InnerConnection的connected方法。
我们来考察一下之前在bringUpServiceLocked中忽略过的绑定Service逻辑,也就是在realStartServiceLocked调用的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;
}
}
}
能看到实际上那个就是获取ServiceRecord中所有的IntentBindRecord,调用requestServiceBindingLocked方法进行绑定。
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;
}
核心方法就是跨进程调用ApplicationThread的scheduleBindService方法。
ActivityThread handleBindService
这个方法会通过ActivityThread主线程handler发送绑定服务的消息,也就是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.调用Service的onBind方法,获取从Service中返回的允许客户端操作的Binder对象。跨进程调用AMS的publishService方法,把需要返回的Binder返回给客户端。
- 2.如果从BindServiceData中判断到当前的Service需要重新绑定则回调onRebind方法。调用serviceDoneExecuting方法告诉AMS已经接受了当前的执行任务。从而拆下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 clist = r.connections.valueAt(conni);
for (int i=0; i
此时就会获得Intent的意图,通过ServiceRecord的bindings中找到IntentBindRecord,IntentBindRecord设置receiver为true。
遍历ServiceRecord的connections集合中所有的ConnectionRecord,如果发现Service的Intent意图过滤不匹配则进入下一个loop中;如果符合意图,则调用ConnectionRecord的IServiceConnection的connected方法。这个方法就会跨进程调用的ServiceDisptacher中InnerConnection的connected方法,把从Service的onBind返回的Binder对象传递到InnerConnection中。
serviceDoneExecutingLocked 执行完成任务行为,拆除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);
}
}
当InnerConnection接受到了connected的调用,这里就会调用ServiceDispatcher的connected,把IBinder传递过来。注意这个IBinder就是从Service的onBind方法返回的Binder对象。
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);
}
}
核心就是调用doConnected,或者调用RunConnection Runnable对象执行其中的run方法。
RunConnection run
public void run() {
if (mCommand == 0) {
doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
}
这里根据mCommand来执行doConnected进行ServiceConnection的绑定回调还是解绑回调。
这里是绑定,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中。如果通过ComponentName查找到,本次发送给客户端的Binder和上一次的对象一致则直接返回。
2.为当前的Binder通过linkToDeath绑定Binder的死亡监听。如果这个发送给客户端操作的Binder对象死亡了,则会回调DeathMonitor,移除mActiveConnections中的对应Service名字的ConnectionInfo。这样就移除了还在活跃的Binder的缓存对象。
3.mActiveConnections 根据当前传递过来的Service的ComponentName为key,保存ConnectionInfo。
4.如果上一次的Binder对象不为空则解绑死亡监听,先回调onServiceDisconnected方法,告诉这个Binder已经解开了链接。如果此时Serice还是经历了stop的方法需要销毁了,还会执行onBindingDied方法,告诉客户端,远程端已经死亡了。
5.如果是新的不同对象,则会调用onServiceConnected分发Binder对象,告诉客户端已经绑定了。
Service的销毁
Service还能通过stopService结束当前的服务。
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();
}
}
核心就是调用AMS的stopService方法。而这个方法实际上就是调用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 c = r.connections.valueAt(conni);
for (int i=0; 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();
}
...
}
这个过程很简单,可以根据三个循环分为三个部分:
1.在销毁之前,遍历ServiceRecord中所有的InnerConnection远程链接,并且调用connected方法,传递一个空的Binder对象,销毁存储在LoadedApk.ServiceDispatcher活跃的绑定监听。
2.遍历ServiceRecord所有的bindings存储的绑定的IntentBindRecord。先调用bumpServiceExecutingLocked埋下一个ANR消息。并且跨进程调用对应进程的scheduleUnbindService方法,把IntentBindRecord中存储的启动的意图传递过去。
3.如果是前台的服务还会移除SERVICE_FOREGROUND_TIMEOUT_MSG,前台服务执行任务超时ANR。
4.如果进程还存活,则bumpServiceExecutingLocked埋下销毁Service的ANR。更新进程的adj优先级后,跨进程调用scheduleStopService方法。
我们来看看在ApplicationThread中的scheduleUnbindService和scheduleStopService。
ActivityThread handleUnbindService
scheduleUnbindService最后会调用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对象,并执行onUnbind方法回调。如果onUnbind返回true说明需要重新绑定,则调用unbindFinished方法;否则则调用serviceDoneExecuting完成当前任务的执行。
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.调用Service的onDestroy方法
- 2.Service的detachAndCleanUp 销毁保存在Service中的ServiceRecord这个Binder对象
- 3.QueuedWork 等待SP的写入消息的落盘
- 4.serviceDoneExecuting 通知ActiveServices的移除销毁ANR的Handler消息
总结
Service的启动原理实际上很简单,我这边分为startService和bindService两个方法将进行总结。
startService实际上和bindService执行流程十分相似。只是bindService多执行了几个步骤,直接上bindService和stopService的时序图:
bindService 与 startService
bindService绑定服务,如果在bindService方法就是BIND_AUTO_CREATE的标志位,就会包含了startService的逻辑。这里就用BIND_AUTO_CREATE的逻辑来统一说说整个流程都做了什么。
-
1.在bindService进入AMS之前,就会调用LoadedApk.getServiceDispatcher获取一个ServiceDispatcher对象。
- 1.1.而ServiceDispatcher这个对象包含了一个InnerConnection Binder对象。这个对象是用于直接沟通AMS的那边的回调,直接回调到ServiceConnection中。
- 1.2.ServiceDispatcher中本身就有mServices缓存,它缓存了已经启动过的ServiceDispatcher。是以当前ContextImpl为value,以
ArrayMap
为value的Map。这样就会在同一个上下文中创建相同的服务分发者。
-
2.进入AMS后,首先会通过
retrieveServiceLocked
从AMS中查找两个级别的缓存,一个是缓存在AMS中的缓存,一个是缓存在PMS的缓存。- 2.1.AMS的缓存的缓存中又分为两个缓存。一个是通过类名+包名查找ServiceRecord;一个是通过意图过滤器查找Service。
- 2.2.PMS中则是通过解析apk的AndroidManifest.xml的xml标签获得的。
3.如果发现ServiceRecord已经绑定了ProcessRecord说明已经启动过了,则调用scheduleServiceArgs,触发Service的onStartCommand返回。
4.如果发现没有绑定过则说明需要启动过,则scheduleCreateService,调用ActivityThread的handleCreateService,依次执行Service的attach方法绑定ServiceRecord以及onCreate方法,并把新的Service缓存起来。
5.在AMS的
bindServiceLocked
中,会把IServiceConnection绑定到ServiceRecord的ArrayMap
集合中。注意在IntentBindRecord集合中就保存了一个特殊的集合bindings ArrayMap
,而AppBindRecord实际上就是持有了核心的ConnectionRecord集合。而ConnectionRecord就是正在的持有IServiceConnection。
弄的这么复杂,Google官方实际上指向做一件事:可以通过意图确定当前缓存的IServiceConnection 所指向的客户端进程,客户端的监听Service绑定接口对象。
6.
requestServiceBindingsLocked
方法会遍历所有绑定在ServiceRecord的binding集合,并且调用每一个ServiceRecord对应的Service的onBind的方法。7.onBind返回 Service服务端允许客户端操作的Binder对象,则调用AMS的publishService。在AMS中则会查找ServiceRecord的bindings集合,遍历每一个IServiceConnection.connected 尝试回调在
bindService
方法中绑定的ServiceConnection接口。8.IServiceConnection Binder对象在客户端实际上对应就是
ServiceDispatcher
中的InnerConnection
对象。这个对象在connected
方法会调用RunConnection
的run方法,他会调用ActivityThread的Handler中执行doConnected
把服务端分发过来Binder缓存到mActiveConnections,最后回调ServiceConnection.onServiceConnected
9.当启动和绑定都完成后,就会调用
sendServiceArgsLocked
方法。这个方法就是调用ActivityThread. scheduleServiceArgs
方法。而这个方法最终调用Service的onStartCommand方法。注意这里分发的Intent就是之前启动service的Intent。当然onStartCommand会根据返回值在serviceDoneExecuting方法中决定了当Service执行完onStartCommand是否需要重启:START_STICKY 如果Service调用了onStartCommand之后被销毁,会重新启动,如果中间没任何命令传递给Service,此时Intent为null。
START_NOT_STICKY 如果Service调用了onStartCommand之后被销毁,不会重启。
START_REDELIVER_INTENT 如果Service调用了onStartCommand之后被销毁,会重新启动,如果中间没任何命令传递给Service,此时Intent为初始数。
START_STICKY_COMPATIBILITY 兼容模式,不保证onStartCommand之后销毁会重启。
在这个过程中又几个比较重要的缓存对象:
Service销毁
在bringDownServiceLocked
做了三件事情:
- 1.调用所有ServiceConnection的回调,回调onServiceDisconnected方法,并从活跃的Binder集合中移除
- 2.回调Service的onUnBind方法
- 3.回调Service的onDestroy方法和detachAndCleanUp销毁ServiceRecord
Service 的ANR与注意
Service的ANR实际上是由bumpServiceExecutingLocked
方法埋下的一个超时的ANR,超时时间根据是启动后台服务还是前台服务:
- 前台服务是10秒
- 后台服务 不过进程不是在ProcessList.SCHED_GROUP_BACKGROUND进程组中是 20秒
- 后台服务 不过进程在ProcessList.SCHED_GROUP_BACKGROUND进程组中是 200秒
当每一个Service执行完一个任务之后,都会执行serviceDoneExecutingLocked方法,把ActiveServices中的Handler的ANR倒计时消息移除。
有一点比较有意思的一点,启动服务有一个常见的问题,当通过startService启动Service的时候,会爆出错误。
Not allowed to start service Intent{xxxx}
禁止打开后台服务。在上面也有体现:如果startService返回的包名不是正常的包名而是一个?
则会爆出这种错误。
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);
}
}
能看到如果此时fgRequired为false也就是非前台服务,会走入getAppStartModeLocked的校验。
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收集的是启动的活跃应用进程uid。
- uidRec为空,必定是没有启动或者是后台进程
- uidRec.idle为true,说明此时是启动过了但是呆在了后台超过60秒,从前台变化为后台进程。
这两个情况都会appServicesRestrictedInBackgroundLocked进行校验:
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;
}
...
}
校验出了不在白名单中,就会返回APP_START_MODE_DELAYED。此时不是APP_START_MODE_NORMAL就会返回带了?
的包名从而报错。
一般的,我们还会作如下处理从startService改成startForegroundService。但是这样就又爆出了全新的错误。
Context.startForegroundService() did not then call Service.startForeground()
android.app.ActivityThread$H.handleMessage(ActivityThread.java:2204)
写高版本的service 稍不注意都会遇到这种情况。这是因为你没有在Service中使用startForeground方法。如果我们超过10秒没有一般我们都会使用startForeground启动一个通知,告诉用户正在前台运行。
而startForeground实际上是移除超时ANR的行为。
但是有时候,就算startForeground还是会报错,即使把时机尽可能的提前了,放在了onCreate中,还是会报错了。
我们能够看到实际上这个过程中每当执行完Service的onStartCommand,就会等待SP写入到磁盘的阻塞,也有可能是这个时候的写入时间过长了导致的ANR,详情可看SharedPreferences源码解析。
另一种可能就是因为整个流程都是在主线程中执行的,看看主线程有没有其他太过耗时的行为,导致来不及移除前台服务的ANR消息。
后记
到这里Service已经全部解析了,接下来我们来看看四大组件最后一个ContentProvider。