本文小编为大家详细介绍“ActivityManagerService之Service怎么启动”,内容详细,步骤清晰,细节处理妥当,希望这篇“ActivityManagerService之Service怎么启动”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
启动 Service
Service 的启动最终会调用如下方法
// ContextImpl.java
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
// 从 Android 5.0 ,必须使用显式 Intent 启动 Service
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
// 通过 AMS 启动 Service
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
// ... 处理异常结果 ...
}
// 成功启动后,返回已启动的 Service 组件名
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
Service 最终是通过 AMS 进行启动的,一旦启动成功,会返回 Service 的组件名,通过这个返回结果,可以判断 Service 是否启动成功,这一点往往被很多开发者忽略。
AMS 最终会调用 ActiveService#startServiceLocked() 来启动 Service
ActivityManagerService 把 Service 的所有事务都交给 ActiveServices 处理。
// ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired,
String callingPackage, @Nullable String callingFeatureId, final int userId,
boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
throws TransactionTooLargeException {
// 调用方是否处于前台
final boolean callerFg;
if (caller != null) {
final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + callingPid
+ ") when starting service " + service);
}
callerFg = callerApp.mState.getSetSchedGroup() != ProcessList.SCHED_GROUP_BACKGROUND;
} else {
callerFg = true;
}
// 1. 查询 Service
// 其实这是是从缓存获取 ServiceRecord,或者建立 ServiceRecord 并缓存
ServiceLookupResult res =
retrieveServiceLocked(service, null, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false, false);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
// 从查询的结果中获取 Service 记录
ServiceRecord r = res.record;
// 2. 对 Service 启动施加限制
// ...
if (forcedStandby || (!r.startRequested && !fgRequired)) {
// Service 所在的进程处于后台,是无法启动 Service
final int allowed = mAm.getAppStartModeLOSP(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.shortInstanceName
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage + " startFg?=" + fgRequired);
// ...
UidRecord uidRec = mAm.mProcessList.getUidRecordLOSP(r.appInfo.uid);
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
// ...
// 3. 进入下一步 Service 启动过程
return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
allowBackgroundActivityStarts, backgroundActivityStartsToken);
}
首先为 Service 在服务端建立一个记录 ServiceRecord 并缓存起来,这个过程比较简单,读者自行分析。
然后,在 Service 启动之前,施加一些限制,代码中展示了一段后台 app 无法启动 Service 的限制,但是也省略了其他限制的代码,有兴趣的读者可以自行分析。
本文旨在分析 Service 的启动流程,对于一些小细节,限于篇幅原因,就不细致分析,请读者自行研读代码。
最后进入下一步的启动的流程
Service 的启动,会调用好几个类似的函数,但是每一个函数最做了一部分功能,这样就可以把一个庞大的函数分割为几个小的函数,代码阅读性更高,我们要学习这种做法。
private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
int callingUid, int callingPid, boolean fgRequired, boolean callerFg,
boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
throws TransactionTooLargeException {
// ...
// 1. 更新 ServiceRecord 数据
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.fgRequired = fgRequired;
// 保存即将发送给 Service 的参数
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants, callingUid));
// 授予 app 启动前台 Service 的 app op 权限
if (fgRequired) {
// ...
}
// 下面一段,确定 addToStarting 的值
final ServiceMap smap = getServiceMapLocked(r.userId);
boolean addToStarting = false;
// 注意这里的判断条件
// !callerFg 表示调用方不处于前台
// !fgRequired 表示启动的是 非前台Service
// r.app == null 表示 Service 还没有启动过
if (!callerFg && !fgRequired && r.app == null
&& mAm.mUserController.hasStartedUserState(r.userId)) {
ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid);
if (proc == null || proc.mState.getCurProcState() > PROCESS_STATE_RECEIVER) {
// app 没有创建,或者已经创建,但是在后台没有运行任何四大组件
// ...
// 延时Service不在这里启动,直接返回
if (r.delayed) {
return r.name;
}
// 如果目前要启动非前台Service超时过了最大数量的,那么当前这个Service,要设置为延时 Service
// 而延时 Service 不在这里启动,因此直接返回
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
// Something else is starting, delay!
Slog.i(TAG_SERVICE, "Delaying start of: " + r);
smap.mDelayedStartList.add(r);
r.delayed = true;
return r.name;
}
addToStarting = true;
} else if (proc.mState.getCurProcState() >= ActivityManager.PROCESS_STATE_SERVICE) {
// app 处于后台,但是只运行了 service 和 receiver
addToStarting = true;
}
}
// allowBackgroundActivityStarts 目前为 false
if (allowBackgroundActivityStarts) {
r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken);
}
// 2. 继续下一阶段的启动流程
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
}
现在没有 Service 的启动限制了,是时候正式启动了,首先更新 ServiceRecord 数据,这里要注意,使用 ServiceRecord#pendingStarts 保存了要发送给 Service 的参数。
接下来有一段关于延时 Service 以及监听 后台Service 相关的代码,这是为了优化 Service 启动过多的情况,而做出的一个优化。对于系统优化的开发者,你可能要重点关注一下,本文先不管这个优化功能。
然后继续看下一步的启动流程
// ActiveServices.java
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
synchronized (mAm.mProcessStats.mLock) {
final ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
}
}
// 是否调用 onStart()
r.callStart = false;
final int uid = r.appInfo.uid;
final String packageName = r.name.getPackageName();
final String serviceName = r.name.getClassName();
FrameworkStatsLog.write(FrameworkStatsLog.SERVICE_STATE_CHANGED, uid, packageName,
serviceName, FrameworkStatsLog.SERVICE_STATE_CHANGED__STATE__START);
mAm.mBatteryStatsService.noteServiceStartRunning(uid, packageName, serviceName);
// 1. 拉起 Service
String error = bringUpServiceLocked(r, service.getFlags(), callerFg,
false /* whileRestarting */,
false /* permissionsReviewRequired */,
false /* packageFrozen */,
true /* enqueueOomAdj */);
/* Will be a no-op if nothing pending */
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
if (error != null) {
return new ComponentName("!!", error);
}
// 优化后台Service启动过多的情况
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() 拉起 Service
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
boolean enqueueOomAdj)
throws TransactionTooLargeException {
// 1. 如果 Service 已经启动过一次,直接发送发送参数给 Service 即可
// 因为只有 Service 启动过,r.app 才不为 null
if (r.app != null && r.app.getThread() != null) {
sendServiceArgsLocked(r, execInFg, false);
return null;
}
// ...
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
final String procName = r.processName;
HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
ProcessRecord app;
if (!isolated) {
// 1. Service 进程存在,但是 Service 还没有启动过,那么通知宿主进程启动 Service
// 由于前面已经判断过 r.app 不为 null 的情况,所以这里处理的就是 Service 没有启动过的情况
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid);
if (app != null) { // 进程粗在
final IApplicationThread thread = app.getThread();
final int pid = app.getPid();
final UidRecord uidRecord = app.getUidRecord();
if (thread != null) { // attach application 已经完成
try {
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,
mAm.mProcessStats);
realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
enqueueOomAdj);
return null;
}
// ...
}
}
} else {
// ...
}
// 3. Service 所在的进程没有运行,那么要 fork 一个进程
if (app == null && !permissionsReviewRequired && !packageFrozen) {
// TODO (chriswailes): Change the Zygote policy flags based on if the launch-for-service
// was initiated from a notification tap or not.
if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
hostingRecord, ZYGOTE_POLICY_FLAG_EMPTY, false, isolated)) == null) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad";
Slog.w(TAG, msg);
bringDownServiceLocked(r, enqueueOomAdj);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
// 对于前台 Service 的 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);
}
// 3.1 mPendingServices 保存正在等待进程起来的 Service
// 进程起来后,执行 attach application 过程时,会自动启动这个 Service
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
// ...
}
return null;
}
拉起一个 Service 要分好几种情况
如果 Service 已经启动过,那么直接发送参数给 Service 去执行任务即可。这是最简单的一种情况。
如果 Service 没有启动过,但是 Service 的宿主进程是存在的,那么通知宿主进程创建 Service,然后发送参数给它。
如果 Service 的宿主进程不存在,那么得先 fork 一个进程,然后用 mPendingServices 保存这个等待进程启动的 Service。当进程起来后,在执行 attach application 的过程中,AMS 会自动完成 Service 的启动流程。
第3种情况,明显是包含前面两种情况,因此下面直接分析这个过程。
宿主进程的启动
Service 的宿主进程起来后,在执行 attach application 的过程中,AMS 会自动启动那些等待进程起来的 Service,如下
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// ...
try {
// ...
// 进程初始化
if (app.getIsolatedEntryPoint() != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(
app.getIsolatedEntryPoint(), app.getIsolatedEntryPointArgs());
} else if (instr2 != null) {
thread.bindApplication(processName, appInfo, providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap);
} else {
thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap);
}
// ...
} catch (Exception e) {
// ...
return false;
}
// ...
if (!badApp) {
try {
// 启动等待进程的 Service
didSomething |= mServices.attachApplicationLocked(app, processName);
checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
}
}
// ...
return true;
}
最终调用 ActiveServices#attachApplicationLocked() 完成 Service 的启动
// ActiveServices.java
boolean attachApplicationLocked(ProcessRecord proc, String processName)
throws RemoteException {
boolean didSomething = false;
// mPendingServices 保存的就是那些等待进程起来的 Service
if (mPendingServices.size() > 0) {
ServiceRecord sr = null;
try {
// 遍历 mPendingServices ,启动属于该进程的所有 Service
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
// 过滤掉不属于这个进程的 Service
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue;
}
final IApplicationThread thread = proc.getThread();
final int pid = proc.getPid();
final UidRecord uidRecord = proc.getUidRecord();
mPendingServices.remove(i);
i--;
proc.addPackage(sr.appInfo.packageName, sr.appInfo.longVersionCode,
mAm.mProcessStats);
// 启动 Service
realStartServiceLocked(sr, proc, thread, pid, uidRecord, sr.createdFromFg,
true);
didSomething = true;
if (!isServiceNeededLocked(sr, false, false)) {
bringDownServiceLocked(sr, true);
}
mAm.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
}
} catch (RemoteException e) {
// ...
}
}
// 处理进程重启而需要重启的 Service
if (mRestartingServices.size() > 0) {
// ...
}
return didSomething;
}
终于,我们看到了我们想看到的东西,先从 mPendingServices 中过滤掉不属于进程的 Service,然后启动它
// ActiveServices.java
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
boolean enqueueOomAdj) throws RemoteException {
// ...
// 注意,r.app 的值才不为 null,也就是 ServiceRecord#app 不为 null
// 因此可以通过 r.app 判断 Service 是否已经启动过
r.setProcess(app, thread, pid, uidRecord);
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
final ProcessServiceRecord psr = app.mServices;
final boolean newService = psr.startService(r);
// 注意,这里实现了 Service 超时的功能
bumpServiceExecutingLocked(r, execInFg, "create", null /* oomAdjReason */);
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(psr, /* oomAdj= */ false);
// Force an immediate oomAdjUpdate, so the client app could be in the correct process state
// before doing any service related transactions
mAm.enqueueOomAdjTargetLocked(app);
mAm.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
boolean created = false;
try {
// ...
// 1. 通知宿主进程创建Service
thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.mState.getReportedProcState());
r.postNotification();
created = true;
// ...
} catch (DeadObjectException e) {
// ...
} finally {
if (!created) {
// ...
}
}
// ...
// 2. 发送参数给 Service
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
 
以上就是ActivityManagerService之Service怎么启动的详细内容,更多关于ActivityManagerService之Service怎么启动的资料请关注九品源码其它相关文章!