一 概述
Service 的启动流程还是比较简单的,不像 Activity 那么复杂,相关联的类和方法也少了很多,不像 Activity 启动流程里面走着走着就会迷失方向,在之前两篇文章我们主要分析了 Activity 的启动流程,今天我们主要来探索 Service 的启动过程。
Service 是 Android 四大组件,地位仅次于 Activity,Activity 位于前台向用户展示界面;Service 位于后台不可见,但是它承担了大部分的的数据处理工作,主要为其他组件提供后台服务,监控其他组件的运行状态。下面我们来具体分析。
分析的系统源码为 android 12 。
涉及代码如下:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java
frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/java/android/app/Service.java
二 APP发起启动请求
2.1 时序图
2.2 ContextImpl.startService
frameworks/base/core/java/android/app/ContextImpl.java
@Override
public ComponentName startService(Intent service) {
warnIfCallingFromSystemProcess();// 系统进程启动 service 的话,打印 log
// 第二个参数为 requireForeground,默认为 false 表示启动非前台服务,
// 区别于 startForegroundService
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) {
validateServiceIntent(service);// 对 Intent 的属性进行检查和准备
service.prepareToLeaveProcess(this);
// Binder 跨进程调用到 AMS
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " +
cn.getClassName());
}
}
return cn;
}
需要注意的是 startService 和 startForegroundService 差别是入参 requireForeground 的值,其他代码逻辑完全一样。
默认情况下目标 Service 会以后台服务的方式进行启动。与前台服务相比,后台服务不会在下拉通知栏显示通知,同时优先级较低,当系统出现内存不足情况时容易被回收。
validateServiceIntent() 对参数 Intent 进行合法性检查,确保其中与 Service 启动的相关属性值不为 null。此外,Android 5.0 后强制要求 Service 必须通过显式 Intent 启动,否则会直接抛出异常
当由于权限、安全性等问题导致 Service 无法正常启动时,返回值 cn 的成员变量 mPackage 会被设置为 “!”、“?” 等特殊值,此时应用进程会进行处理并抛出对应的异常
三 AMS处理启动请求
3.1 ActivityManagerService.startService
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
int userId) throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
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;
}
}
startService() 获取客户端进程的 callingPid 与 callingUid,然后将它们连同其它参数传递给 ActiveServices 对象的 startServiceLocked() 进行处理。
ActivityManagerService 把 Service 的所有事务都交给 ActiveServices 处理。
3.2 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 {
// 倒数第二个参数是 allowBackgroundActivityStarts,默认
// 为 false, 表示不允许后台 Activity 启动 Service
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid,
fgRequired, callingPackage, callingFeatureId, userId, false, null);
}
继续调用 startServiceLocked,倒数第二个参数 allowBackgroundActivityStarts,默认为 false,表示不允许后台 Activity 启动 Service。
继续调用:
ComponentName startServiceLocked(IApplicationThread caller, Intent service,
String resolvedType, int callingPid, int callingUid, boolean fgRequired,
String callingPackage, @Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts,
@Nullable IBinder backgroundActivityStartsToken)
throws TransactionTooLargeException {
final boolean callerFg;
if (caller != null) {
// 从 mLruProcesses 列表中找出指定进程
final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
// 关键点1:callerFg 用于标记发起端进程是前台还是后台,
// 当发起方进程不等于SCHED_GROUP_BACKGROUND
// 或者发起方为空,则 callerFg= true,否则为 false
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
// 关键点2:从 ServiceMap 中根据 ComponentName 查找 ServiceRecord,不存在的话就创建
// 并封装成 ServiceLookupResult, 见 # 3.2.1
ServiceLookupResult res = retrieveServiceLocked(service, null, resolvedType,
callingPackage, callingPid, callingUid, userId, true, callerFg,
false, false);
// 获取 ServiceRecord,并构建
ServiceRecord r = res.record;
......
// 是否后台启动, Android 8.0+ 有后台启动限制
final boolean bgLaunch = !mAm.isUidActiveLOSP(r.appInfo.uid);
boolean forcedStandby = false;
// 如果后台启动 Service,且 app 有后台启动限制,则 forcedStandby 设置为 true
if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
forcedStandby = true;
}
// 如果是 startForegroundService 启动前台服务,检查前台启动操作权限是否允许
if (fgRequired) {
final int mode = mAm.mAppOpsService.checkOperation(
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
case AppOpsManager.MODE_DEFAULT:
// All okay.
break;
case AppOpsManager.MODE_IGNORED:
// Not allowed, fall back to normal start service
// failing siliently. if background check restricts that.
fgRequired = false;
forceSilentAbort = true;
break;
}
}
// 如果是后台启动或者启动非前台服务,检查是否允许后台启动,如果不能的话返回 null
if (forcedStandby || (!r.startRequested && !fgRequired)) {
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
if (allowed == ActivityManager.APP_START_MODE_DELAYED ||
forceSilentAbort) {
// In this case we are silently disabling the app, to disrupt as
// little as possible existing apps.
return null;
}
if (forcedStandby) {
if (fgRequired) {
return null;
}
}
// This app knows it is in the new model where this operation is not
// allowed, so tell it what has happened.
UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
// Android 8.0 之前启动前台服务不需要调用 startForegroundService(), 即 fgRequired 为 false
if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
fgRequired = false;
}
NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
// 权限检查 permission review
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
callingUid, service, callerFg, userId)) {
return null;
}
......
// 设置 ServiceRecord 启动参数, pendingStarts 中添加启动项 StartItem
r.lastActivity = SystemClock.uptimeMillis();
// startRequested 是 ServiceRecord 类的一个 boolean 类型的成员变量,该值为 true 表示 Service
// 是通过 startService 方式(而不是 bindService 方式)启动的
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
if (fgRequired) {
// 如果是 Android 8.0+ 调用的 startForegroundService() 启动前台服务的话,
// 更新 ServiceState
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(),
r.lastActivity);
}
mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService),
AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true);
}
// 获取 ServiceMap
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;//重点变量
// 如果“ caller app 不是前台应用”、“目标 Service 不是前台服务”
// “目标 Service 处于未运行状态”
// “发起请求的用户已经启动”,以上条件均满足则进入此分支,判断目标 Service 是否需要
// 延迟启动,否则,将调用 startServiceInnerLocked() 立即启动目标 Service
if (!callerFg && !fgRequired && r.app == null &&
mAm.mUserController.hasStartedUserState(r.userId)) {
// 从进程列表中获取启动 Service 所在的进程
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName,
r.appInfo.uid, false);
// 当目标 Service 所属的进程尚未创建,或者已创建但优先级较低时
//(即 proc.curProcState 的值
// 大于常量10,注意它的取值越小反而表示进程优先级越高
if (proc == null ||
proc.getCurProcState() > ActivityManager.PROCESS_STATE_RECEIVER) {
// 如果 delayed 为 true,延迟启动
if (r.delayed) {
return r.name;
}
// 如果后台启动服务数超过 mMaxStartingBackground,则延迟启动
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
// addToStarting 设置为 true
addToStarting = true;
} else if (proc.getCurProcState<