赞
踩
系列博文:
Android service 启动篇之 startService
Android service 启动篇之 bindService
Android service 启动篇之 startForegroundService
基于版本:Android O
Android基础总结之六:Sevice 中是应用端对于service 使用的总结,其中看到启动service 需要的接口有startService 和bindService。在Android O 中又添加了一个接口api——startForegroundService。本篇主要围绕对两个start service接口以及中间有可能触发ANR的异常进行解析。
上层启动service 直接接口在Context 中:
- @Override
- public ComponentName startService(Intent service) {
- warnIfCallingFromSystemProcess();
- return startServiceCommon(service, false, mUser);
- }
-
- @Override
- public ComponentName startForegroundService(Intent service) {
- warnIfCallingFromSystemProcess();
- return startServiceCommon(service, true, mUser);
- }
- @Override
- public ComponentName startServiceAsUser(Intent service, UserHandle user) {
- return startServiceCommon(service, false, user);
- }
-
- @Override
- public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
- return startServiceCommon(service, true, user);
- }
之前我们知道的是在启动一个service 的时候需要调用接口startService 或者bindService,为什么这里多了Foreground service?
在官方文档 Android 8.0 行为变更 中有这样一段话:
Android 8.0 有一项复杂功能;系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即 Context.startForegroundService()
,以在前台启动新服务。
在系统创建服务后,应用有五秒的时间来调用该服务的 startForeground()
方法以显示新服务的用户可见通知。
如果应用在此时间限制内未调用 startForeground()
,则系统将停止服务并声明此应用为 ANR。
回过头来对比下startService 和startForegroundService ,主要区别就是第二个参数,如果是前台服务,第二个参数为true。这里留意下,下面进一步解析时会用到。这两个函数最终调用的地方是相同的,都是函数startServiceCommon() :
- 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();
- }
- }
看到这里大概猜到 Android 中service 详解 其中的几个问题都是从这里抛出来的。
根本原因是AMS 调用startService 的返回值ComponentName 不是我们想要的,也就是说后面的处理肯定会创建一个ComponentName,package name 为 ! 、!! 和 ? 三个中的一个,而class name 会作为异常message 抛出。
还有一点,通过函数validateServiceIntent() 可以看到如果SDK 版本大于L 的,要求service 不能隐式启动。
- private void validateServiceIntent(Intent service) {
- if (service.getComponent() == null && service.getPackage() == null) {
- if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
- IllegalArgumentException ex = new IllegalArgumentException(
- "Service Intent must be explicit: " + service);
- throw ex;
- } else {
- Log.w(TAG, "Implicit intents with startService are not safe: " + service
- + " " + Debug.getCallers(2, 3));
- }
- }
- }
总结:
1、service 启动入口startService 和startForegroundService,其中startForegroundService 为O 版本才出现的。(bindService 下一篇介绍)
2、两个接口最终调用的地方是相同的,都是AMS 的startService,对于foreground service 参数requireForeground 为true。
从上面Context 中startServiceCommon() 接口确定下startService 传入的参数:
确定参数后就可以放心进入source code 了:
- 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;
- }
- }
省略掉之前判断的条件,该函数最终调用的应该是ActiveServices 中的startServiceLocked,参数都是直传的,多加了callingPid,callingUid。
函数比较多,我们这里分步来解析。
- final boolean callerFg;
- if (caller != null) {
- final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
- if (callerApp == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller
- + " (pid=" + callingPid
- + ") when starting service " + service);
- }
- callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
- } else {
- callerFg = true;
- }
这个callerFg 标记当前caller app 是前台还是后台。
- ServiceLookupResult res =
- retrieveServiceLocked(service, resolvedType, callingPackage,
- callingPid, callingUid, userId, true, callerFg, false);
- if (res == null) {
- return null;
- }
- if (res.record == null) {
- return new ComponentName("!", res.permission != null
- ? res.permission : "private to package");
- }
注意最后一个参数,判断是否是bind external service,如果该service 可以运行在外部进程中,那么servcie 在注册的时候需要置上flag FLAG_EXTERNAL_SERVICE。这样bindService 的时候将最后一个参数传入为true,就可以实现external service。
- if (r == null && !isBindExternal) {
- Intent.FilterComparison filter = new Intent.FilterComparison(service);
- r = smap.mServicesByIntent.get(filter);
- if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by intent: " + r);
- }
- if (r != null && (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 (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Whoops, can't use existing external service");
- }
如果service 为FLAG_EXTERNAL_SERVICE,在startService() 的时候isBindExternal 为false,走的是上面一个case,如果是bindService(),最后走的是后面一个case,变量 r 最终为null,需要后面重现生成。
- ComponentName name = new ComponentName(
- sInfo.applicationInfo.packageName, sInfo.name);
- if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) {
- if (isBindExternal) {
- if (!sInfo.exported) {
- throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
- " is not exported");
- }
- if ((sInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) == 0) {
- throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " + name +
- " is not an isolatedProcess");
- }
- // Run the service under the calling package's application.
- ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
- callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
- if (aInfo == null) {
- throw new SecurityException("BIND_EXTERNAL_SERVICE failed, " +
- "could not resolve client package " + callingPackage);
- }
- 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 {
- throw new SecurityException("BIND_EXTERNAL_SERVICE required for " +
- name);
- }
详细code 这里暂不做分析,需要知道service 所有信息是在这里获取的,包括service 所需的permission check 也是在这里进行。如果出现异常,会导致该函数的返回值为null,或者是ServiceRecord 为null。那如果ServiceRecord 为null,就会出现code 中的package name 为 "!",最终会导致 java.lang.SecurityException: Not allowed to start service
- if (fgRequired) {
- final int mode = mAm.getAppOpsManager().checkOpNoThrow(
- 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.
- Slog.w(TAG, "startForegroundService not allowed due to app op: service "
- + service + " to " + r.shortInstanceName
- + " from pid=" + callingPid + " uid=" + callingUid
- + " pkg=" + callingPackage);
- fgRequired = false;
- forceSilentAbort = true;
- break;
- default:
- return new ComponentName("!!", "foreground not allowed as per app op");
- }
- }
如果是启动一个前台service,需要确认该service 是否有作为前台service 的权限。如果没有权限,则会就会出现code 中的package name 为 "!!",最终会导致 java.lang.SecurityException: Unable to start service
这个函数主要判断当前应用是否可以唤醒后台服务,这个函数还是有些东西的。
- final int startMode = (alwaysRestrict)
- ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
- : appServicesRestrictedInBackgroundLocked(uid, packageName,
- packageTargetSdk);
这里传入的alwaysRestrict 为false,需要通过函数appServicesRestrictedInBackgroundLocked 进一步确认:
- int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
- // Persistent app?
- if (mPackageManagerInt.isPackagePersistent(packageName)) {
- if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "App " + uid + "/" + packageName
- + " is persistent; not restricted in background");
- }
- return ActivityManager.APP_START_MODE_NORMAL;
- }
-
- // Non-persistent but background whitelisted?
- if (uidOnBackgroundWhitelist(uid)) {
- if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "App " + uid + "/" + packageName
- + " on background whitelist; not restricted in background");
- }
- return ActivityManager.APP_START_MODE_NORMAL;
- }
-
- // Is this app on the battery whitelist?
- if (isOnDeviceIdleWhitelistLocked(uid)) {
- if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "App " + uid + "/" + packageName
- + " on idle whitelist; not restricted in background");
- }
- return ActivityManager.APP_START_MODE_NORMAL;
- }
-
- // None of the service-policy criteria apply, so we apply the common criteria
- return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
- }
这些条件可以创建条件让应用满足启动后台服务,如果一般应用,这些条件都无法满足了。
在该应用不满足上面 3.4.1 条件时,会继续调用appRestrictedInBackgroundLocked()
- int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
- // Apps that target O+ are always subject to background check
- if (packageTargetSdk >= Build.VERSION_CODES.O) {
- if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
- }
- return ActivityManager.APP_START_MODE_DELAYED_RIGID;
- }
- // ...and legacy apps get an AppOp check
- int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
- uid, packageName);
- if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
- }
- switch (appop) {
- case AppOpsManager.MODE_ALLOWED:
- return ActivityManager.APP_START_MODE_NORMAL;
- case AppOpsManager.MODE_IGNORED:
- return ActivityManager.APP_START_MODE_DELAYED;
- default:
- return ActivityManager.APP_START_MODE_DELAYED_RIGID;
- }
如果SDK 版本大于等于Android O,直接放回APP_START_MODE_DELAYED_RIGID,也就是O 以上版本的应用在不满足上面3.4.1 中的条件时,是不允许启动后台服务的。
不过庆幸的是,对于Android O 之前版本的应用,会通过AppOpsManager 确认是否可以启动后台服务,而AppOpsManager 中默认是允许的。
回归到ActiveServices 中,如果不让启动后台服务,或者Android O版本的应用,会进入下面的case :
- if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
- Slog.w(TAG, "Background start not allowed: service "
- + service + " to " + r.name.flattenToShortString()
- + " from pid=" + callingPid + " uid=" + callingUid
- + " pkg=" + callingPackage);
- if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
- // In this case we are silently disabling the app, to disrupt as
- // little as possible existing apps.
- 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.mActiveUids.get(r.appInfo.uid);
- return new ComponentName("?", "app is in background uid " + uidRec);
- }
最终出现了package name为 "?" 的ComponentName。
从而抛出java.lang.IllegalStateException: Not allowed to start service Intent(java.lang.IllegalStateException: Not allowed to start service Intent)
- if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
- if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) {
- Slog.i(TAG, "startForegroundService() but host targets "
- + r.appInfo.targetSdkVersion + " - not requiring startForeground()");
- }
- fgRequired = 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));
回归到ActiveServices中,这里有些对于ServiceRecord 的赋值,后面处理的时候很重要。
例如后面在bringUpServiceLocked() 中需要知道有没有pendingStarts。
另外,对于版本小于O 的service apk,都将其作为后台service 启动;
这个函数是start service 的核心处理部分,在这之前的都是一些条件的过滤。
- 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 (DEBUG_DELAYED_SERVICE) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r, here);
- } else if (DEBUG_DELAYED_STARTS) {
- Slog.v(TAG_SERVICE, "Starting background (first=" + first + "): " + r);
- }
- if (first) {
- smap.rescheduleDelayedStartsLocked();
- }
- } else if (callerFg || r.fgRequired) {
- smap.ensureNotStartingBackgroundLocked(r);
- }
-
- return r.name;
代码不是很多,但是里面的信息却不少,我们来分步解析。
Service的start是由函数startServiceInnerLocked完成,而startServiceInnerLocked则是调用bringUpServiceLocked完成Service的start,每次startService都会往ServiceRecord的pendingStarts里填加一项StartItem,即使是被放入Delayed List的Service启动。bringUpServiceLocked做的事就是拉起Service。
- if (r.app != null && r.app.thread != null) {
- sendServiceArgsLocked(r, execInFg, false);
- return null;
- }
如果r.app 也就是ServiceRecord 和thread 已经不为null,也就是说该service 已经create,再次调用startService() 函数的时候,会直接调用sendServiceArgsLocked(),这里暂时不介绍,下面会详细说明。
- if (!whileRestarting && mRestartingServices.contains(r)) {
- // If waiting for a restart, then do nothing.
- return null;
- }
这里whileRestarting 是传进来的,如果从startService 调用bring up,那么这个值为false,此时不用继续执行,等待restart 处理进来;如果这个值是从restart 调用的bring up,那么这个值为true,也就是进入了restart 流程,会继续往下执行。
- if (mRestartingServices.remove(r)) {
- clearRestartingIfNeededLocked(r);
- }
如果从restart 调用的bring up,上面参数whileRestaring 为true,会继续执行代码。这里如果restart 开始执行,状态就都需要clear,不需要在处于restart 状态。
- if (r.delayed) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (bring up): " + r);
- getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
- r.delayed = false;
- }
需要直接start servicce,不在需要delayed 。
- if (!isolated) {
- app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
- if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
- + " app=" + app);
- if (app != null && app.thread != null) {
- try {
- app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
- realStartServiceLocked(r, app, execInFg);
- return null;
- } catch (TransactionTooLargeException e) {
- throw e;
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception when starting service " + r.shortName, e);
- }
- }
- } else {
- app = r.isolatedProc;
- if (WebViewZygote.isMultiprocessEnabled()
- && r.serviceInfo.packageName.equals(WebViewZygote.getPackageName())) {
- hostingType = "webview_service";
- }
- }
如果service 的ProcessRecord 已经创建了,会直接调用realStartServiceLocked(),进入start service 的最终流程。下面详细解析这个函数。
如果ProcessRecord 还没有创建,那就会跳过上面这一段流程,继续往下执行。
- if (app == null && !permissionsReviewRequired) {
- if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
- hostingType, r.name, false, isolated, false)) == null) {
- ...
- }
- ...
- }
-
- ...
-
- if (!mPendingServices.contains(r)) {
- mPendingServices.add(r);
- }
如果app 为null,也就是service 还没有create,会调用AMS 中startProcessLocked() 创建,这个函数比较长,可以自行跟一下source code,主要是通过startProcessLocked() 创建进程,并加入到mPendingServices,等待attachApplicationLocked后再startService。
- if (r.delayedStop) {
- // Oh and hey we've already been asked to stop!
- r.delayedStop = false;
- if (r.startRequested) {
- if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
- "Applying delayed stop (in bring up): " + r);
- stopServiceLocked(r);
- }
- }
如果之前有stop service 请求,这里会直接stop。
至此,bringUpServiceLocked() 函数解析完,主要确定ProcessRecord 是否创建完成,通过函数realStartServiceLocked()进入启动流程或者通过startProcessLocked()进入创建流程。这个函数的返回值如果不为null,外面会有exception 抛出:
- String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
- if (error != null) {
- return new ComponentName("!!", error);
- }
下面对其中碰到的两个函数进行进一步解析:sendServiceArgsLocked 和 realStartServiceLocked。
3.6.1.1 sendServiceArgsLocked()
从代码中可以看到,如果进入bringUpServiceLocked(),发现service 已经create,这个时候会直接进入sendServiceArgsLocked函数,也就是说startService() 剩下来的处理都是在这里。
- final int N = r.pendingStarts.size();
- if (N == 0) {
- return;
- }
里面过滤一下,确认有service 需要start。
bumpServiceExecutingLocked(r, execInFg, "start");
这里最后一个参数是引入start 流程,后面还会碰到create
- private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
- if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
- + why + " of " + r + " in app " + r.app);
- else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
- + why + " of " + r.shortName);
- 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 (r.app.executingServices.size() == 1) {
- scheduleServiceTimeoutLocked(r.app);
- }
- }
- } else if (r.app != null && fg && !r.app.execServicesFg) {
- r.app.execServicesFg = true;
- scheduleServiceTimeoutLocked(r.app);
- }
- r.executeFg |= fg;
- r.executeNesting++;
- r.executingStart = now;
- }
上面bringUpServiceLocked() 最开始的时候说过,就是将DelayList 中的service 一个一个的拉起。
在这里会拉起一个timeout,一般的后台服务,默认是20秒。如果被触发,那么就只有ANR 等待了。当然,如果状态正常,这个ANR 的schedule 是需要取消的,下面会分析到。
如果等待的是一个前台服务:
- 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;
- }
- }
会拉起一个前台服务的timeout,默认时间为 5 秒(在Android P 时改成10秒,一直延续到R)。如果被触发,那么就只有ANR 等待了。
如果该service 还没有进入fg,则会立即产生个 ANR 的schedule(炸弹),后面紧接着需要进入start 流程,即会调用service 的onStartCommand。也就是要求一个等待的service 在以fg service 启动时,必须要在5 秒内调用startForeground,这里就通过代码的方式回答了第一节中官方的一段话。而也是在startForeground调用的时候才会拆除之前埋下的ANR炸弹(5s timeout)。详细看接口startForeground。
继续分析,接着会创建一个ServiceStartArgs:
args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
为了后面的启动:
r.app.thread.scheduleServiceArgs(r, slice);
app.thread是Service所在进程的IApplicationThread Binder对象,用于AMS的SystemServer进程到Client App端的跨进程调用,IApplicationThread的实现是在ActivityThread的内部类ApplicationThread,AMS -> ActivityThread的调用通过IApplicationThread,ActivityThread -> AMS的调用就是ActivityManagerNative,这样就打通了一条从AMS到ActivityThread的跨进程调用之路。
scheduleServiceArgs在ActivityThread里的对应就是ActivityThread.handleServiceArgs,这就执行到了我们所熟悉的onStartCommand。
- private void handleServiceArgs(ServiceArgsData data) {
- Service s = mServices.get(data.token);
- if (s != null) {
- try {
- ...
- 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();
- }
- } catch (Exception e) {
- ...
- }
- }
- }
onStartCommand后会调用AMS.serviceDoneExecuting 进行收尾工作,也是在这里取消了ANR 的schedule,拆除了这个ANR 炸弹(20s timeout)。
至此可以解释两个我们对于Service的认知:
sendServiceArgsLocked之后,pendingStarts里的StartItem就被加入到了deliveredStarts里,等待后续stopService或者Service restart的时候用。
3.6.1.2 realStartServiceLocked()
-
- private final void realStartServiceLocked(ServiceRecord r,
- ProcessRecord app, boolean execInFg) throws RemoteException {
- if (app.thread == null) {
- throw new RemoteException();
- }
- if (DEBUG_MU)
- Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
- + ", ProcessRecord.uid = " + app.uid);
- r.app = app;
- r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
- // create service
- 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 {
- ...
- ...
-
- 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 (r.whitelistManager) {
- app.whitelistManager = true;
- }
-
- // bind service
- requestServiceBindingsLocked(r, execInFg);
-
- updateServiceClientActivitiesLocked(app, null, true);
-
- ...
-
- // start service
- sendServiceArgsLocked(r, execInFg, true);
-
- ...
- }
上面sendServiceArgsLocked() 是在service 已经被创建的情况下触发,这里是第一次start service时候,此时service 还没有被create。此时会调用 bumpServiceExecutingLocked(r, execInFg, "create");
接着:
- app.thread.scheduleCreateService(r, r.serviceInfo,
- mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
- app.repProcState);
这里的app.thread 在上面 3.6.1.1 中已经解释过。这里主要是调用了scheduleCreateService(),最终触发的是我们熟悉的onCreate()。
bindService() 最后也会进入这个函数,会通过:
- requestServiceBindingsLocked(r, execInFg);
-
- updateServiceClientActivitiesLocked(app, null, true);
详细看 Android service 启动篇之 bindService
接着:
sendServiceArgsLocked(r, execInFg, true);
同样这里也会有这个调用,通过 3.6.1.1 我么知道,这里会拉起一个timeout,最终调用的熟悉的onStartCommand()。
注意:
bind service 的时候也会进入该函数,但是 3.5节中变量是没有赋值,所以最终进入函数也会return。
详细看 Android service 启动篇之 bindService
至此,startService 的整个过程大概分析完成。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。