基础知识
完整的客户端生命周期:onCreate() → onStartCommand() → stopService → onDestroy()
如果存在多个client启动同一个service, 只需一个client便可以stop该服务
ServiceRecord的一些属性
boolean startRequested; // 是否是start方式启动,首次在startServiceInnerLocked中赋值
boolean fgRequired; // 是否是前台service,在startServiceInnerLocked中赋值
long lastActivity; // service的上次活跃时间,在startServiceInnerLocked或bindServiceLocked中赋值
boolean delayedStop; //首次启动或绑定赋值为false,stopServiceLocked中如果delayed则赋值为true
// start() arguments which been delivered.
final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
// start() arguments that haven't yet been delivered.
// startServiceInnerLocked 中会添加,即sendServiceArgsLocked之前添加
final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
final Runnable restarter; // used to schedule retries of starting the service
boolean delayed; // are we waiting to start this service in the background?
ServiceMap介绍
继承自Handler,每个用户空间都有对应的ServiceMap对象
final int mUserId; //对应用户空间的id
// 通过ComponentName保存的service map
final ArrayMap<ComponentName, ServiceRecord> mServicesByInstanceName = new ArrayMap<>();
// 通过intent保存的service map
final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>();
final ArrayList<ServiceRecord> mDelayedStartList = new ArrayList<>();
ActiveServices的一些属性
private ArrayMap<ServiceRecord, ArrayList<Runnable>> mPendingBringups = new ArrayMap<>();
final ArrayList<ServiceRecord> mPendingServices = new ArrayList<>();
final ArrayList<ServiceRecord> mRestartingServices = new ArrayList<>();
startService的流程
app端流程
app端调用startService方法最终会调用ContextImpl的startServiceCommon
// requireForeground表示是否启动前台service
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// binder到system server端执行
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
// 根据system server端返回的特殊packageName抛出不同的异常
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 ServiceStartNotAllowedException.newInstance(requireForeground,
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
8-10 是进程不存在时才执行,且中间省略了进程创建的流程
12-16 Service的onCreate流程
11-17 是Service不存在时才执行,即service存在app端只用执行onStartCommand方法
18-23 Service的onStartCommand流程
system server端流程
AMS.startService:
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage,
String callingFeatureId, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
}
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
// system server端service相关的流程都交给ActiveServices类处理
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, callingFeatureId, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
ActiveServices.startServiceLocked
- 参数解释:
- caller: 发起startService进程对应的IApplicationThread对象
- service:要启动的service的intent
- callingPid:调用方进程id
- callingUid:调用方uid
- fgRequired:要启动的service是否是前台
- callingPackage:调用方包名
- allowBackgroundActivityStarts: 这里为false
- backgroundActivityStartsToken:这里为null
- userId:当前用户id
- 流程
- 获取caller是否处于前台,赋值callerFg
- retrieveServiceLocked 检索得到Service实例
- 一些前台或后台启动的权限校验
- 非前台caller&非前台service ,procState在PROCESS_STATE_SERVICE之上或进程不存在,则设置addToStarting为true,startServiceInnerLocked 方法中会用到这个变量
- 非前台caller&非前台service,procState在PROCESS_STATE_RECEIVER之上或进程不存在,如果mStartingBackground 列表大小超过mMaxStartingBackground,则当前service添加到mDelayedStartList列表,当前service延迟启动,mMaxStartingBackground值若没有通过属性设置,低内存设备为1,否则为8
- 调用startServiceInnerLocked
- 返回null
- 没有查到要启动的service
- userId不存在
- mAllowStartForeground
- APP_START_MODE_DELAYED || forceSilentAbort
- 不在电池优化白名单的前台service(service app在后台)
- 返回特殊包名
- 调用方和被调用方不允许建立连接,ServiceLookupResult中ServiceRecord为null,返回包名为"!"的componentName
"Service lookup failed: "+ "association not allowed between packages " + callingPackage + " and " + name.getPackageName(); - 不允许后台启动,返回包名为"?", "app is in background uid " + uidRec
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;
// app端startService调用过来的caller都不为null
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller);
// 通过IApplicationThread对象获取system server端进程实例,进程不存在则抛出安全异常
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + callingPid
+ ") when starting service " + service);
}
// 获取caller是否在前台
callerFg = callerApp.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
// 通过PendingIntent的INTENT_SENDER_FOREGROUND_SERVICE启动时,也判定caller为前台
callerFg = true;
}
// 拿到要启动的service的信息,通过pms查询缓存起来,权限校验
ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
// 没有查到要启动的service,直接返回null
if (res == null) {
return null;
}
// 没有对应的service record,返回包名为"!"的componentName
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
// 拿到system server端代表service的实例
ServiceRecord r = res.record;
// 前台service的限制
setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, userId,
allowBackgroundActivityStarts);
// userId不存在则直接返回null
if (!mAm.mUserController.exists(r.userId)) {
Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
return null;
}
// If we're starting indirectly (e.g. from PendingIntent), figure out whether
// we're launching into an app in a background state. This keys off of the same
// idleness state tracking as e.g. O+ background service start policy.
// 判断要启动的service所在app是否处于非活跃状态,如果进程的procState < 8,则在后台超过1min则会进入idle状态。
final boolean bgLaunch = !mAm.isUidActiveLOSP(r.appInfo.uid);
// If the app has strict background restrictions, we treat any bg service
// start analogously to the legacy-app forced-restrictions case, regardless
// of its target SDK version.
boolean forcedStandby = false;
// 如果service所在app处于后台状态且该app不在电池优化白名单(系统app默认在),将forcedStandby赋值为true
if (bgLaunch && appRestrictedAnyInBackground(r.appInfo.uid, r.packageName)) {
forcedStandby = true;
}
// S上新增代码
if (fgRequired) {
logFgsBackgroundStart(r);
if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
String msg = "startForegroundService() not allowed due to "
+ "mAllowStartForeground false: service "
+ r.shortInstanceName;
Slog.w(TAG, msg);
showFgsBgRestrictedNotificationLocked(r);
logFGSStateChangeLocked(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED,
0);
if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, callingUid)) {
throw new ForegroundServiceStartNotAllowedException(msg);
}
return null;
}
}
// If this is a direct-to-foreground start, make sure it is allowed as per the app op.
// ops权限校验
// If this isn't a direct-to-foreground start, check our ability to kick off an
// arbitrary service
// 1. 要启动的不是前台service
// 2.service对应的app不活跃且不在电池优化白名单
// 则需要进行后台启动限制校验
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.
// 获取service所在app是否允许启动后台service
final int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// android o+后台启动都会打印这个log
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.shortInstanceName
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage + " startFg?=" + fgRequired);
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) {
// This is an O+ app, but we might be here because the user has placed
// it under strict background restrictions. Don't punish the app if it's
// trying to do the right thing but we're denying it for that reason.
// 1. service所在app处于后台,2. service为前台service 3. app不在电池优化白名单
// 返回null
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.
// 不允许后台启动,返回包名为"?"的component
UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
// At this point we've applied allowed-to-start policy based on whether this was
// an ordinary startService() or a startForegroundService(). Now, only require that
// the app follow through on the startForegroundService() -> startForeground()
// contract if it actually targets O+.
if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
fgRequired = false;
}
// The package could be frozen (meaning it's doing surgery), defer the actual
// start until the package is unfrozen.
// 延迟service的启动和绑定,直到package解冻。S上新增的逻辑
if (deferServiceBringupIfFrozenLocked(r, service, callingPackage, callingFeatureId,
callingUid, callingPid, fgRequired, callerFg, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, false, null)) {
return null;
}
// If permissions need a review before any of the app components can run,
// we do not start the service and launch a review activity if the calling app
// is in the foreground passing it a pending intent to start the service when
// review is completed.
// XXX This is not dealing with fgRequired!
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage, callingFeatureId,
callingUid, service, callerFg, userId, false, null)) {
return null;
}
return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
allowBackgroundActivityStarts, backgroundActivityStartsToken);
}
ActiveServices.retrieveServiceLocked
首先通过intent或component尝试从service map中获取实例,不存在则创建新的service实例并put到service map中。
- 检索 service,存在则获取,不存在则创建
- startServiceInnerLocked
- 如果addToStarting 为true,添加Service到mStartingBackground列表,并设置service的startingBgTimeout 时间为15s后
- 返回null的情况
- 校验包可见性失败,打印Unable to start service " + service + " U=" + userId + “: not found”
- 没有缓存service且从pms中查询不到,“Unable to start service " + service + " U=” + userId +": not found"
- 返回的ServiceLookupResult中ServiceRecord为null:
- 检查调用方和被调用方能否建立联系,不能则返回的ServiceLoockupResult中service为null
- service未向外暴露,exported属性为false
- 相关权限校验未过
private ServiceLookupResult retrieveServiceLocked(Intent service,
String instanceName, String resolvedType, String callingPackage,
int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal,
boolean allowInstant) {
ServiceRecord r = null;
// 获取userId
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId,
/* allowAll= */false, getAllowMode(service, callingPackage),
/* name= */ "service", callingPackage);
// 获取对应用户空间的service map
ServiceMap smap = getServiceMapLocked(userId);
final ComponentName comp;
if (instanceName == null) {
// 通过intent获取componentName
comp = service.getComponent();
} else {
final ComponentName realComp = service.getComponent();
if (realComp == null) {
throw new IllegalArgumentException("Can't use custom instance name '" + instanceName
+ "' without expicit component in Intent");
}
// instanceName不为空,重组ComponetName
comp = new ComponentName(realComp.getPackageName(),
realComp.getClassName() + ":" + instanceName);
}
// ComponentName不为null,先通过component查询是否有对应的service
if (comp != null) {
r = smap.mServicesByInstanceName.get(comp);
}
// isBindExternal 表示必须通过外部绑定,这里为false
// 通过component查询不到,则通过intent去查询
if (r == null && !isBindExternal && instanceName == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
if (r != null) {
// Compared to resolveService below, the ServiceRecord here is retrieved from
// ServiceMap so the package visibility doesn't apply to it. We need to filter it.
// 校验缓存的service的包可见性,S上新增
if (mAm.getPackageManagerInternal().filterAppAccess(r.packageName, callingUid,
userId)) {
Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId
+ ": not found");
return null;
}
// 如果设置了FLAG_EXTERNAL_SERVICE且是外部调用,不允许复用缓存的service
if ((r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
// If an external service is running within its own package, other packages
// should not bind to that instance.
r = null;
}
}
// 如果没有缓存或不允许复用
if (r == null) {
try {
int flags = ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
if (allowInstant) {
flags |= PackageManager.MATCH_INSTANT;
}
// 从pms中查询
ResolveInfo rInfo = mAm.getPackageManagerInternal().resolveService(service,
resolvedType, flags, userId, callingUid);
ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;
// 查询不到,返回null,打印相关log
if (sInfo == null) {
Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
": not found");
return null;
}
if (instanceName != null
&& (sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
throw new IllegalArgumentException("Can't use instance name '" + instanceName
+ "' with non-isolated service '" + sInfo.name + "'");
}
// 封装componentName
ComponentName className = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
ComponentName name = comp != null ? comp : className;
// 检查调用方和被调用方能否建立联系,不能则返回的ServiceLoockupResult中service为null
if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid,
name.getPackageName(), sInfo.applicationInfo.uid)) {
String msg = "association not allowed between packages "
+ callingPackage + " and " + name.getPackageName();
Slog.w(TAG, "Service lookup failed: " + msg);
return new ServiceLookupResult(null, msg);
}
// Store the defining packageName and uid, as they might be changed in
// the ApplicationInfo for external services (which run with the package name
// and uid of the caller).
String definingPackageName = sInfo.applicationInfo.packageName;
int definingUid = sInfo.applicationInfo.uid;
// FLAG_EXTERNAL_SERVICE 相关校验
.........
if (userId > 0) {
// 非主用户空间,要启动的service是单例
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)
&& mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
userId = 0;
smap = getServiceMapLocked(0);
// Bypass INTERACT_ACROSS_USERS permission check
final long token = Binder.clearCallingIdentity();
try {
ResolveInfo rInfoForUserId0 =
mAm.getPackageManagerInternal().resolveService(service,
resolvedType, flags, userId, callingUid);
if (rInfoForUserId0 == null) {
Slog.w(TAG_SERVICE,
"Unable to resolve service " + service + " U=" + userId
+ ": not found");
return null;
}
// 重新获取snfo
sInfo = rInfoForUserId0.serviceInfo;
} finally {
Binder.restoreCallingIdentity(token);
}
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
// 通过Componet再获取一次Service
r = smap.mServicesByInstanceName.get(name);
// start或bind时createIfNeede均为true
if (r == null && createIfNeeded) {
final Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
final ServiceRestarter res = new ServiceRestarter();
// 第一次启动创建Service
r = new ServiceRecord(mAm, className, name, definingPackageName,
definingUid, filter, sInfo, callingFromFg, res);
res.setService(r);
// 将当前service实例通过intent和component put到service map中
smap.mServicesByInstanceName.put(name, r);
smap.mServicesByIntent.put(filter, r);
// Make sure this component isn't in the pending list.
// 因为正在启动service,所以将当前service信息从pending列表中移除
for (int i=mPendingServices.size()-1; i>=0; i--) {
final ServiceRecord pr = mPendingServices.get(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.instanceName.equals(name)) {
mPendingServices.remove(i);
}
}
for (int i = mPendingBringups.size() - 1; i >= 0; i--) {
final ServiceRecord pr = mPendingBringups.keyAt(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.instanceName.equals(name)) {
mPendingBringups.removeAt(i);
}
}
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
}
if (r != null) {
r.mRecentCallingPackage = callingPackage;
r.mRecentCallingUid = callingUid;
try {
r.mRecentCallerApplicationInfo =
mAm.mContext.getPackageManager().getApplicationInfoAsUser(callingPackage,
0, UserHandle.getUserId(callingUid));
} catch (PackageManager.NameNotFoundException e) {
}
// 一些各种权限校验
if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName,
r.appInfo.uid)) {
String msg = "association not allowed between packages "
+ callingPackage + " and " + r.packageName;
Slog.w(TAG, "Service lookup failed: " + msg);
return new ServiceLookupResult(null, msg);
}
if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
resolvedType, r.appInfo)) {
return new ServiceLookupResult(null, "blocked by firewall");
}
if (mAm.checkComponentPermission(r.permission,
callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
if (!r.exported) {
Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " that is not exported from uid " + r.appInfo.uid);
return new ServiceLookupResult(null, "not exported from uid "
+ r.appInfo.uid);
}
Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires " + r.permission);
return new ServiceLookupResult(null, r.permission);
} else if (Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
&& callingUid != Process.SYSTEM_UID) {
// Hotword detection must run in its own sandbox, and we don't even trust
// its enclosing application to bind to it - only the system.
// TODO(b/185746653) remove this special case and generalize
Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requiring permission " + r.permission
+ " can only be bound to from the system.");
return new ServiceLookupResult(null, "can only be bound to "
+ "by the system.");
} else if (r.permission != null && callingPackage != null) {
final int opCode = AppOpsManager.permissionToOpCode(r.permission);
if (opCode != AppOpsManager.OP_NONE && mAm.getAppOpsManager().checkOpNoThrow(
opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: Accessing service " + r.shortInstanceName
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires appop " + AppOpsManager.opToName(opCode));
return null;
}
}
return new ServiceLookupResult(r, null);
}
return null;
}
ActiveServices.startServiceInnerLocked
private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
int callingUid, int callingPid, boolean fgRequired, boolean callerFg,
boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
throws TransactionTooLargeException {
NeededUriGrants neededGrants = mAm.mUgmInternal.checkGrantUriPermissionFromIntent(
service, callingUid, r.packageName, r.userId);
//取消service重启相关的调度
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));
.......
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
// 调用者处于后台,启动后台service,且service对应的进程未赋值或不存在
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
// service对应进程不存在或procState > 11
if (proc == null || proc.mState.getCurProcState() > PROCESS_STATE_RECEIVER) {
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
} else if (proc.mState.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
addToStarting = true;
}
}
if (allowBackgroundActivityStarts) {
r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken);
}
// 调用重载方法
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
ActiveServices.startServiceInnerLocked
返回packageName为"!!"情况,bringUpServiceLocked返回不为null
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
r.callStart = false;
final int uid = r.appInfo.uid;
final String packageName = r.name.getPackageName();
final String serviceName = r.name.getClassName();
// 真正拉起service的地方
String error = bringUpServiceLocked(r, service.getFlags(), callerFg,
false /* whileRestarting */,
false /* permissionsReviewRequired */,
false /* packageFrozen */,
true /* enqueueOomAdj */);
/* Will be a no-op if nothing pending */
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
if (error != null) {
return new ComponentName("!!", error);
}
// start方式后台启动
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;
}
ActiveServices.bringUpServiceLocked
- 若Service已经存在,则直接通过sendServiceArgsLocked 让客户端Service回调onStartCommand方法
- 从restart list中移除当前service; 取消service的delay ;设置package的stop状态为false
- 进程存在则直接调用realStartServiceLocked去继续下面的操作
- 进程不存在,创建进程,并把service添加到mPendingServices,等创建进程时再start
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
boolean enqueueOomAdj)
throws TransactionTooLargeException {
//service的app已经被赋值,说明被启动过,thread不为空代表进程存在
// 直接post app端执行onStartCommand逻辑
// 没有错误信息,返回null
if (r.app != null && r.app.getThread() != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
// Service正在重启,直接返回
if (!whileRestarting && mRestartingServices.contains(r)) {
// If waiting for a restart, then do nothing.
return null;
}
// We are now bringing the service up, so no longer in the
// restarting state.
// 当前正在拉起service,从重启列表中移除当前service
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
// 正在启动,移除delay相关信息
if (r.delayed) {
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
// Make sure that the user who owns this service is started. If not,
// we don't want to allow it to run.
// user 状态有问题,返回错误信息
if (!mAm.mUserController.hasStartedUserState(r.userId)) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": user " + r.userId + " is stopped";
Slog.w(TAG, msg);
bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
// 正在启动service,package状态不能为stopped
// Service is now being launched, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
// 进程启动会用到,表明启动进程的原因
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;
// 不是孤岛service
if (!isolated) {
// 获取service所在进程实例
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
// service所在进程存在,直接执行app端service的onCreate前期处理
if (app != null) {
final IApplicationThread thread = app.getThread();
final int pid = app.getPid();
final UidRecord uidRecord = app.getUidRecord();
if (thread != null) {
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,
mAm.mProcessStats);
realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
enqueueOomAdj);
return null;
} catch (TransactionTooLargeException e) {
throw e;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortInstanceName, e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
}
} else {
app = r.isolatedProc;
if (WebViewZygote.isMultiprocessEnabled()
&& r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
hostingRecord = HostingRecord.byWebviewZygote(r.instanceName);
}
if ((r.serviceInfo.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
hostingRecord = HostingRecord.byAppZygote(r.instanceName, r.definingPackageName,
r.definingUid);
}
}
// Not running -- get it started, and enqueue this service record
// to be executed when the app comes up.
// 进程不存在,先去拉起进程
if (app == null && !permissionsReviewRequired && !packageFrozen) {
// TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
// was initiated from a notification tap or not.
// app短期crash多次,返回null
if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (r.fgRequired) {
mAm.tempAllowlistUidLocked(r.appInfo.uid,
SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
"fg-service-launch",
TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
r.mRecentCallingUid);
}
// service放入pending列表,等进程启动后处理
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r, enqueueOomAdj);
}
}
return null;
}
ActiveServices.realStartServiceLocked
- 真正启动Service的地方,拉起app的service实例,bindservice也会调到这个方法
- 给service实例设置app,restartTime,lastActivity等
- 更新oomadj,reason为OOM_ADJ_REASON_START_SERVICE
- 告知app create service,执行Service的onCreate方法,并post"create"超时消息
- 告知app start service,执行Service的onStartCommand方法,并post “start”超时消息
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
boolean enqueueOomAdj) throws RemoteException {
if (thread == null) {
throw new RemoteException();
}
// 给service设置进程,代表当前servce执行了onCreate方法
r.setProcess(app, thread, pid, uidRecord);
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
// 获取当前进程的所有service信息
final ProcessServiceRecord psr = app.mServices;
// 将当前service添加到ProcessServiceRecord中
final boolean newService = psr.startService(r);
// 超时逻辑
bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
// 更新ams的lru list
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(psr, /* oomAdj= */ false);
// Force an immediate oomAdjUpdate, so the client app could be in the correct process state
// before doing any service related transactions
// 更新进程优先级
mAm.enqueueOomAdjTargetLocked(app);
mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
boolean created = false;
try {
final int uid = r.appInfo.uid;
final String packageName = r.name.getPackageName();
final String serviceName = r.name.getClassName();
mAm.mBatteryStatsService.noteServiceStartLaunch(uid, packageName, serviceName);
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
// post app端去执行create service流程
thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.mState.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
if (!created) {
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying, false);
// Cleanup.
if (newService) {
psr.stopService(r);
r.setProcess(null, null, 0, null);
}
// Retry.
if (!inDestroying) {
scheduleServiceRestartLocked(r, false);
}
}
}
if (r.allowlistManager) {
psr.mAllowlistManager = true;
}
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(psr, null, true);
if (newService && created) {
psr.addBoundClientUidsOfNewService(r);
}
// If the service is in the started state, and there are no
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
null, null, 0));
}
// post app端去执行onStartCommand流程
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
if (r.delayedStop) {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
stopServiceLocked(r, enqueueOomAdj);
}
}
}
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) {
// If somehow we got a dummy null intent in the middle,
// then skip it. DO NOT skip a null intent when it is
// the only one in the list -- this is to support the
// onStartCommand(null) case.
continue;
}
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
if (si.neededGrants != null) {
mAm.mUgmInternal.grantUriPermissionUncheckedFromIntent(si.neededGrants,
si.getUriPermissionsLocked());
}
mAm.grantImplicitAccess(r.userId, si.intent, si.callingId,
UserHandle.getAppId(r.appInfo.uid)
);
bumpServiceExecutingLocked(r, execInFg, "start", null /* oomAdjReason */);
if (r.fgRequired && !r.fgWaiting) {
if (!r.isForeground) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Launched service must call startForeground() within timeout: " + r);
}
scheduleServiceForegroundTransitionTimeoutLocked(r);
} else {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Service already foreground; no new timeout: " + r);
}
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));
}
if (!oomAdjusted) {
mAm.enqueueOomAdjTargetLocked(r.app);
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
slice.setInlineCountLimit(4);
Exception caughtException = null;
try {
r.app.getThread().scheduleServiceArgs(r, slice);
} catch (TransactionTooLargeException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Transaction too large for " + args.size()
+ " args, first: " + args.get(0).args);
Slog.w(TAG, "Failed delivering service starts", e);
caughtException = e;
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take care of this.
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while sending args: " + r);
Slog.w(TAG, "Failed delivering service starts", e);
caughtException = e;
} catch (Exception e) {
Slog.w(TAG, "Unexpected exception", e);
caughtException = e;
}
if (caughtException != null) {
// Keep nesting count correct
final boolean inDestroying = mDestroyingServices.contains(r);
for (int i = 0, size = args.size(); i < size; i++) {
serviceDoneExecutingLocked(r, inDestroying, inDestroying, true);
}
/* Will be a no-op if nothing pending */
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
if (caughtException instanceof TransactionTooLargeException) {
throw (TransactionTooLargeException)caughtException;
}
}
}
三、stopService的流程
如果存在多个client启动同一个service, 只需一个client便可以stop该服务
1、Service外部stop
stopServiceLocked
如果service是delay的,则设置service的delayedStop 为true,在Service被拉起的时候stop
2、service 内部stop