Android Framework AMS(08)service组件分析-2(startService和StopService关键流程分析)

news/2024/10/21 19:14:48/

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:上一章节主要解读应用层service组件启动的2种方式startService和bindService,以及从APP层到AMS调用之间的打通。本章节主要关注service组件启动方式的一种:startService启动方式,分析关键API为service组件的startServicestopService方法。

我们从AMS.startService和AMS.stopService分别来分析,分析的主要流程为:

接下来开始详细解读。

1 AMS.startService流程解读(onCreate、onStartCommand)

AMS.startService代码实现如下:

//ActivityManagerService@Overridepublic ComponentName startService(IApplicationThread caller, Intent service,String resolvedType, int userId) {// 检查调用者是否是隔离的进程,如果不是,则抛出安全异常enforceNotIsolatedCaller("startService");synchronized(this) {final int callingPid = Binder.getCallingPid();final int callingUid = Binder.getCallingUid();final long origId = Binder.clearCallingIdentity();ComponentName res = mServices.startServiceLocked(caller, service,resolvedType, callingPid, callingUid, userId);Binder.restoreCallingIdentity(origId);return res;}}//...

这里调用了ActivityService的startServiceLocked方法,代码实现如下:

//ActivityService//关键流程:step1ComponentName startServiceLocked(IApplicationThread caller,Intent service, String resolvedType,int callingPid, int callingUid, int userId) {// 判断调用者是否在前台运行final boolean callerFg;if (caller != null) {// 获取调用者的应用记录final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);// 判断调用者是否在前台运行,如果不是后台非交互线程组,则认为是前台callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;} else {// 如果没有调用者,也认为是前台callerFg = true;}// 检索服务,如果服务不存在或者没有权限,则返回相应的结果ServiceLookupResult res = retrieveServiceLocked(service, resolvedType,callingPid, callingUid, userId, true, callerFg);// 如果服务记录为空,说明服务不存在或者没有权限,返回错误信息if (res.record == null) {return new ComponentName("!", res.permission != null? res.permission : "private to package");}// 获取服务记录ServiceRecord r = res.record;// 检查用户是否存在if (!mAm.getUserManagerLocked().exists(r.userId)) {return null;}// 检查调用者是否有权限授予URI权限NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(callingUid, r.packageName, service, service.getFlags(), null, r.userId);// 如果服务已经在重启计划中,取消重启if (unscheduleServiceRestartLocked(r, callingUid, false)) {}// 更新服务最后活跃的时间r.lastActivity = SystemClock.uptimeMillis();// 设置服务启动请求为真r.startRequested = true;// 设置服务不是延迟停止的r.delayedStop = false;// 添加一个新的启动项到服务的待启动列表中r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),service, neededGrants));// 获取服务映射对象final ServiceMap smap = getServiceMap(r.userId);boolean addToStarting = false;// 如果调用者不是前台,服务应用记录为空,并且用户已启动,则进行以下操作if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {// 获取服务要运行的进程记录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;}}// 调用内部方法来实际启动服务return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);}//关键流程:step2ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,ServiceRecord r, boolean callerFg, boolean addToStarting) {// 获取服务状态跟踪器ProcessStats.ServiceState stracker = r.getTracker();// 如果服务状态跟踪器存在,设置服务为已启动状态,并更新内存因素和最后活动时间if (stracker != null) {stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);}// 设置服务的callStart标志为false,表示服务尚未调用 onStartCommandr.callStart = false;synchronized (r.stats.getBatteryStats()) {r.stats.startRunningLocked();}// 关键方法:实际启动服务,如果启动失败,返回错误信息String error = bringUpServiceLocked(r, service.getFlags(), callerFg, 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() + BG_START_TIMEOUT;// 如果是第一个启动的后台服务,重新调度延迟启动的服务if (first) {smap.rescheduleDelayedStarts();}} else if (callerFg) {// 如果调用者在前台,确保服务不是正在启动的后台服务smap.ensureNotStartingBackground(r);}// 返回服务的组件名称return r.name;}//关键流程:step3private final String bringUpServiceLocked(ServiceRecord r,int intentFlags, boolean execInFg, boolean whileRestarting) {// 如果服务的应用记录不为空且应用线程不为空,说明服务已经在运行,直接发送服务参数if (r.app != null && r.app.thread != null) {sendServiceArgsLocked(r, execInFg, false);return null;}// 如果服务不在重启中,并且重启延迟时间大于0,则不启动服务if (!whileRestarting && r.restartDelay > 0) {return null;}// 如果服务在重启中,从重启服务列表中移除该服务if (mRestartingServices.remove(r)) {clearRestartingIfNeededLocked(r);}// 如果服务是延迟启动的,从延迟启动列表中移除该服务,并设置服务不再延迟if (r.delayed) {getServiceMap(r.userId).mDelayedStartList.remove(r);r.delayed = false;}// 如果用户未启动,关闭服务并返回if (mAm.mStartedUsers.get(r.userId) == null) {bringDownServiceLocked(r);return msg;}try {// 设置包停止状态为非停止状态AppGlobals.getPackageManager().setPackageStoppedState(r.packageName, false, r.userId);} catch (RemoteException e) {//...}// 判断服务是否运行在隔离进程中final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;final String procName = r.processName;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.versionCode, mAm.mProcessStats);//关键方法:实际启动服务realStartServiceLocked(r, app, execInFg);return null;} catch (RemoteException e) {//...}}} else {// 如果服务运行在隔离进程中,尝试获取隔离进程记录app = r.isolatedProc;}// 如果进程记录为空,尝试启动新进程if (app == null) {//这里是不是眼熟,和startActivity的思路是一致的,创建进程。if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,"service", r.name, false, isolated, false)) == null) {bringDownServiceLocked(r);return msg;}// 如果服务运行在隔离进程中,保存隔离进程记录if (isolated) {r.isolatedProc = app;}}// 如果服务不在待处理列表中,添加到待处理列表if (!mPendingServices.contains(r)) {mPendingServices.add(r);}// 如果服务已经请求停止,取消停止请求if (r.delayedStop) {r.delayedStop = false;if (r.startRequested) {stopServiceLocked(r);}}return null;}//关键流程:step4private 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();// 将服务添加到应用的服务体系表中app.services.add(r);// 增加服务执行的计数,并根据是否在前台执行来更新状态bumpServiceExecutingLocked(r, execInFg, "create");// 更新进程的最近最少使用(LRU)状态mAm.updateLruProcessLocked(app, false, null);// 更新内存调整mAm.updateOomAdjLocked();boolean created = false;try {// 同步电池统计数据的更新synchronized (r.stats.getBatteryStats()) {r.stats.startLaunchedLocked();}// 确保包的dex文件已经优化mAm.ensurePackageDexOpt(r.serviceInfo.packageName);// 强制进程状态至少为服务状态app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);// 关键方法1:通过应用线程调度服务的创建app.thread.scheduleCreateService(r, r.serviceInfo,mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),app.repProcState);r.postNotification();// 标记服务已创建created = true;} catch (DeadObjectException e) {//...} finally {// 如果服务未创建成功,进行清理操作if (!created) {app.services.remove(r);r.app = null;// 安排服务重启scheduleServiceRestartLocked(r, false);return;}}// 请求服务的绑定requestServiceBindingsLocked(r, execInFg);// 更新服务客户端活动updateServiceClientActivitiesLocked(app, null, true);// 如果服务请求启动并且需要调用 onStartCommand,添加一个启动项if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),null, null));}// 关键方法2:发送服务参数,回调执行 onStartCommandsendServiceArgsLocked(r, execInFg, true);// 如果服务是延迟启动的,从延迟启动列表中移除if (r.delayed) {getServiceMap(r.userId).mDelayedStartList.remove(r);r.delayed = false;}// 如果服务已经请求延迟停止,取消延迟停止请求if (r.delayedStop) {r.delayedStop = false;if (r.startRequested) {stopServiceLocked(r);}}}//...

这一条调用关系线下来,从调用关系上依次为:

  1. startServiceLocked
  2. startServiceInnerLocked
  3. bringUpServiceLocked
  4. realStartServiceLocked

最后的realStartServiceLocked才是实际启动服务的方法,主要作用是确保服务在正确的进程中被创建和启动。它涉及到与应用程序线程的通信,服务状态的更新,以及服务生命周期的管理。代码中的scheduleCreateService方法用于请求应用程序线程创建服务,requestServiceBindingsLocked方法用于请求服务的绑定(下一节会涉及),sendServiceArgsLocked方法用于发送服务的参数。ServiceRecord对象表示一个服务的记录,它包含了服务的状态和配置信息。ProcessRecord对象表示一个进程的记录,它包含了进程的状态和配置信息。到这里我们主要关注2个关键方法:

  • scheduleCreateService(调用service的onCreate)
  • sendServiceArgsLocked(调用到service的onStartCommand)

1.1 scheduleCreateService相关流程解读(startService到onCreate)

这里实际上是以startService到service组件调用onCreate的流程分析为目的。代码实现如下:


//ActivityThread//ApplicationThreadpublic 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);}//消息处理private class H extends Handler {//...public void handleMessage(Message msg) {switch (msg.what) {case CREATE_SERVICE:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");handleCreateService((CreateServiceData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;//...}}//...}//...private void handleCreateService(CreateServiceData data) {// 取消调度GC Idler,以确保在服务创建期间不会进行垃圾回收,影响服务启动性能unscheduleGcIdler();// 获取服务所在应用的LoadedApk对象,它包含了应用的加载信息LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);Service service = null;try {// 获取ClassLoader对象,用于加载服务类java.lang.ClassLoader cl = packageInfo.getClassLoader();// 加载服务类并创建实例service = (Service) cl.loadClass(data.info.name).newInstance();} catch (Exception e) {//...}try {ContextImpl context = ContextImpl.createAppContext(this, packageInfo);context.setOuterContext(service);// 创建应用程序实例Application app = packageInfo.makeApplication(false, mInstrumentation);// 服务attach到上下文环境service.attach(context, this, data.info.name, data.token, app,ActivityManagerNative.getDefault());// 调用服务的onCreate()生命周期方法service.onCreate();// 将服务实例存储在映射中,以便后续访问mServices.put(data.token, service);// 通知AMS服务已执行完成try {ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);} catch (RemoteException e) {//...}} catch (Exception e) {//...}}

这段代码的主要作用是创建服务实例并初始化服务的上下文环境。它涉及到类加载、服务实例化、上下文环境的设置以及服务生命周期的管理(主要是onCreate)。代码中的CreateServiceData对象包含了创建服务所需的所有信息,如服务信息、兼容性信息等。ContextImpl对象表示服务的上下文环境,它提供了服务所需的各种资源和信息。Service对象是服务的实际实例,它实现了服务的具体功能。

1.2 sendServiceArgsLocked相关流程分析(startService到onStartCommand)

这里实际上是以startService到service组件调用onStartCommand的流程分析为目的。代码实现如下:

//ActivityServiceprivate final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,boolean oomAdjusted) {final int N = r.pendingStarts.size();if (N == 0) {return;}while (r.pendingStarts.size() > 0) {try {// 从待处理列表中取出第一个启动项ServiceRecord.StartItem si = r.pendingStarts.remove(0);// 如果启动项的Intent为空,并且不是唯一的启动项,则跳过处理if (si.intent == null && N > 1) {continue;}// 记录启动项的交付时间si.deliveredTime = SystemClock.uptimeMillis();// 将启动项添加到已交付列表中r.deliveredStarts.add(si);// 增加启动项的交付次数si.deliveryCount++;// 如果启动项需要授予URI权限,进行授权if (si.neededGrants != null) {mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,si.getUriPermissionsLocked());}// 增加服务执行的计数,并根据是否在前台执行来更新状态bumpServiceExecutingLocked(r, execInFg, "start");// 如果服务的OOM优先级尚未调整,则进行调整if (!oomAdjusted) {oomAdjusted = true;mAm.updateOomAdjLocked(r.app);}// 设置启动服务的标志int flags = 0;if (si.deliveryCount > 1) {flags |= Service.START_FLAG_RETRY;}if (si.doneExecutingCount > 0) {flags |= Service.START_FLAG_REDELIVERY;}// 关键方法:传递应用线程调度服务的启动参数,发送消息启动服务r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);} catch (Exception e) {//...break;}}}

这段代码的主要作用是处理服务的启动参数,并将这些参数发送给服务。它涉及到服务启动项的处理、URI权限的授权、服务执行计数的增加以及服务启动参数的调度。代码中的ServiceRecord对象表示一个服务的记录,它包含了服务的状态和配置信息。ServiceRecord.StartItem对象表示一个服务启动项,它包含了启动服务所需的参数。最后调用scheduleServiceArgs发送消息,代码实现如下:

//ActivityThread//ApplicationThreadpublic final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,int flags ,Intent args) {ServiceArgsData s = new ServiceArgsData();s.token = token;s.taskRemoved = taskRemoved;s.startId = startId;s.flags = flags;s.args = args;sendMessage(H.SERVICE_ARGS, s);}//消息处理private class H extends Handler {//...public void handleMessage(Message msg) {switch (msg.what) {case SERVICE_ARGS:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");handleServiceArgs((ServiceArgsData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;//...}}//...}//...private void handleServiceArgs(ServiceArgsData data) {// 根据服务的token获取服务实例Service s = mServices.get(data.token);if (s != null) {try {// 如果有启动参数Intent,设置它的ClassLoader为服务的ClassLoader,并准备进入进程if (data.args != null) {data.args.setExtrasClassLoader(s.getClassLoader());data.args.prepareToEnterProcess();}// 定义服务启动命令的返回结果变量int res;// 如果服务是因为任务栈被移除而启动的,调用onTaskRemoved方法if (!data.taskRemoved) {//关键方法:调用服务的onStartCommand方法,并传递启动参数res = s.onStartCommand(data.args, data.flags, data.startId);} else {// 如果服务是因为任务栈被移除而启动的,调用onTaskRemoved方法s.onTaskRemoved(data.args);// 设置返回结果为任务移除完成res = Service.START_TASK_REMOVED_COMPLETE;}// 等待队列中的工作完成QueuedWork.waitToFinish();// 关键方法:通知AMS已经完成try {ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);} catch (RemoteException e) {//...}// 确保JIT(即时编译)被启用ensureJitEnabled();} catch (Exception e) {//...}}}

这段代码的主要作用是接收服务的启动参数,调用服务的onStartCommand方法,并处理服务执行完成后的清理工作。它涉及到服务实例的获取、启动参数的处理、服务方法的调用以及服务执行状态的反馈。代码中的ServiceArgsData对象包含了服务启动所需的所有参数,如启动Intent、启动标志、启动ID等。

2 AMS.stopService流程解读(onDestroy)

AMS.stopService代码实现如下:

//ActivityManagerService@Overridepublic int stopService(IApplicationThread caller, Intent service,String resolvedType, int userId) {enforceNotIsolatedCaller("stopService");//...synchronized(this) {return mServices.stopServiceLocked(caller, service, resolvedType, userId);}}

这里调用了ActivityService的stopServiceLocked方法,代码实现如下:

//ActivityService//关键流程:step1int stopServiceLocked(IApplicationThread caller, Intent service,String resolvedType, int userId) {// 获取调用者的进程记录final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);//...// 查找要停止的服务记录ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false);// 如果找到了服务记录,并且记录不为空if (r != null && r.record != null) {final long origId = Binder.clearCallingIdentity();try {// 关键方法:调用停止服务的内部方法stopServiceLocked(r.record);} finally {Binder.restoreCallingIdentity(origId);}// 返回1表示服务成功停止return 1;}// 如果服务记录为空,返回-1表示服务未找到return -1;}//关键流程:step2private void stopServiceLocked(ServiceRecord service) {// 如果服务是延迟停止的,设置延迟停止标志并返回if (service.delayed) {service.delayedStop = true;return;}// 同步电池统计数据的更新synchronized (service.stats.getBatteryStats()) {// 停止服务的电池统计数据service.stats.stopRunningLocked();}// 标记服务不再被请求启动service.startRequested = false;// 如果服务有状态跟踪器,设置服务为未启动状态if (service.tracker != null) {service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),SystemClock.uptimeMillis());}// 标记服务的onStartCommand方法不再被调用service.callStart = false;// 如果需要,执行服务的停止逻辑bringDownServiceIfNeededLocked(service, false, false);}//关键流程:step3private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn) {// 检查服务是否仍然需要如果服务仍然需要,例如服务正在运行或者有待处理的启动请求,则不停止服务并直接返回if (isServiceNeeded(r, knowConn, hasConn)) {return;}// 如果服务在待处理列表中,说明服务的启动请求还在处理中,因此不停止服务if (mPendingServices.contains(r)) {return;}// 如果服务不再需要且不在待处理列表中,则停止服务bringDownServiceLocked(r);}//关键流程:step4private final void bringDownServiceLocked(ServiceRecord r) {// 通知所有绑定到该服务的客户端,服务已经死亡for (int conni = r.connections.size() - 1; conni >= 0; conni--) {ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);for (int i = 0; i < c.size(); i++) {ConnectionRecord cr = c.get(i);// 标记服务为死亡状态cr.serviceDead = true;try {// 通知客户端服务已经死亡cr.conn.connected(r.name, null);} catch (Exception e) {//...}}}// 如果服务已经被应用bind,通知应用服务已经被unbind// 本次分析不涉及bind和unbind操作,因此忽略即可if (r.app != null && r.app.thread != null) {for (int i = r.bindings.size() - 1; i >= 0; i--) {IntentBindRecord ibr = r.bindings.valueAt(i);if (ibr.hasBound) {try {// 增加服务执行的计数,并根据是否在前台执行来更新状态bumpServiceExecutingLocked(r, false, "bring down unbind");// 更新内存调整mAm.updateOomAdjLocked(r.app);// 标记服务为未绑定状态ibr.hasBound = false;// 通知应用服务已经被解绑r.app.thread.scheduleUnbindService(r, ibr.intent.getIntent());} catch (Exception e) {// 异常处理代码...serviceProcessGoneLocked(r);}}}}// 记录服务销毁的时间r.destroyTime = SystemClock.uptimeMillis();// 获取服务映射对象final ServiceMap smap = getServiceMap(r.userId);// 从服务映射中移除服务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);}}// 取消服务的通知r.cancelNotification();// 标记服务不在前台r.isForeground = false;// 重置前台服务的IDr.foregroundId = 0;// 重置前台通知r.foregroundNoti = null;// 清除已交付的启动请求r.clearDeliveredStartsLocked();// 清除待处理的启动请求r.pendingStarts.clear();// 如果服务所属的应用还存在if (r.app != null) {// 同步电池统计数据的更新synchronized (r.stats.getBatteryStats()) {r.stats.stopLaunchedLocked();}// 从应用的服务列表中移除服务r.app.services.remove(r);// 如果应用线程还存在,更新服务的前台状态if (r.app.thread != null) {updateServiceForegroundLocked(r.app, false);try {// 增加服务执行的计数,并根据是否在前台执行来更新状态bumpServiceExecutingLocked(r, false, "destroy");// 添加服务到正在销毁的服务列表中mDestroyingServices.add(r);// 标记服务为正在销毁状态r.destroying = true;// 更新内存调整mAm.updateOomAdjLocked(r.app);// 关键方法:通知应用销毁服务r.app.thread.scheduleStopService(r);} catch (Exception e) {// 异常处理代码...}}}// 清除服务的绑定if (r.bindings.size() > 0) {r.bindings.clear();}// 如果服务有重启器,设置服务为nullif (r.restarter instanceof ServiceRestarter) {((ServiceRestarter) r.restarter).setService(null);}int memFactor = mAm.mProcessStats.getMemFactorLocked();long now = SystemClock.uptimeMillis();// 如果服务有状态跟踪器,设置服务为未启动和未绑定状态if (r.tracker != null) {r.tracker.setStarted(false, memFactor, now);r.tracker.setBound(false, memFactor, now);// 如果服务的执行嵌套计数为0,清除当前所有者if (r.executeNesting == 0) {r.tracker.clearCurrentOwner(r, false);r.tracker = null;}}// 确保服务不在启动的后台服务列表中smap.ensureNotStartingBackground(r);}

这一条调用关系线下来,从调用关系上依次为:

  1. stopServiceLocked
  2. stopServiceLocked
  3. bringDownServiceIfNeededLocked
  4. bringDownServiceLocked

最后的bringDownServiceLocked才是实际关闭服务的方法,它的作用是关闭服务并执行相关的清理工作。它涉及到服务绑定的清理(如果bind则执行unbind操作,主要针对bindservice操作,本次分析不涉及)、服务执行计数的更新、服务状态的更新、服务通知的取消以及服务销毁逻辑的调用。接下来我们主要关注对应startService的通知应用销毁服务的关键方法:scheduleStopService,代码实现如下:

//ActivityThread//ApplicationThreadpublic final void scheduleStopService(IBinder token) {sendMessage(H.STOP_SERVICE, token);}//消息处理private class H extends Handler {//...public void handleMessage(Message msg) {switch (msg.what) {case STOP_SERVICE:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");handleStopService((IBinder)msg.obj);maybeSnapshot();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;//...}}//...}//...private void handleStopService(IBinder token) {Service s = mServices.remove(token);if (s != null) {try {// 关键方法:调用服务的onDestroy生命周期方法s.onDestroy();// 获取服务的上下文环境Context context = s.getBaseContext();// 如果上下文环境是ContextImpl的实例,安排最终的清理工作if (context instanceof ContextImpl) {final String who = s.getClassName();// 安排清理服务关联的资源和数据((ContextImpl) context).scheduleFinalCleanup(who, "Service");}// 等待队列中的工作完成,确保所有异步任务完成QueuedWork.waitToFinish();// 通知ActivityManager服务已经执行完成停止操作try {ActivityManagerNative.getDefault().serviceDoneExecuting(token, SERVICE_DONE_EXECUTING_STOP, 0, 0);} catch (RemoteException e) {//...}} catch (Exception e) {//...}}}

这段代码的主要作用是处理服务的停止请求,包括调用服务的onDestroy方法、清理服务关联的资源和数据,以及通知AMS服务已经停止。代码中的mServices是一个保存服务实例的映射,它使用服务的token作为键。代码中的ContextImpl是Android中上下文环境的实现类,它提供了额外的功能,如安排最终的清理工作。

至此,我们就分析清楚了2个关键流程:

下一章节,我们专注分析bindService启动及停止相关流程,以及如何执行到组件的回调,尤其是bind和unbind。


http://www.ppmy.cn/news/1540876.html

相关文章

深入解析缓存与数据库数据不一致问题

缓存层是提高系统响应速度和扩展性的关键组件。然而&#xff0c;缓存层的引入也带来了数据一致性的挑战。 当数据库中的数据发生变化时&#xff0c;如何确保这些变化能够及时且准确地反映到缓存中&#xff0c;是确保用户体验和系统可靠性的重要问题。 1. 数据一致性 首先&am…

go压缩的使用

基础&#xff1a;使用go创建一个zip func base(path string) {// 创建 zip 文件zipFile, err : os.Create("test.zip")if err ! nil {panic(err)}defer zipFile.Close()// 创建一个新的 *Writer 对象zipWriter : zip.NewWriter(zipFile)defer zipWriter.Close()// 创…

原理代码解读:基于DiT结构视频生成模型的ControlNet

Diffusion Models视频生成-博客汇总 前言:相比于基于UNet结构的视频生成模型,DiT结构的模型最大的劣势在于生态不够完善,配套的ControlNet、IP-Adapter等开源权重不多,导致难以落地。最近DiT-based 5B的ControlNet开源了,相比于传统的ControlNet有不少改进点,这篇博客将从…

RabbitMQ 作为消息中间件,实现了支付消息的异步发送和接收, 同步和异步相比 响应速度具体比较

在支付场景中&#xff0c;使用 RabbitMQ 实现消息的异步发送和接收与同步处理相比&#xff0c;响应速度和整体系统性能会有显著的不同。以下是同步和异步方式在响应速度上的详细比较&#xff1a; 1. 同步处理方式 在同步模式下&#xff0c;支付消息的处理流程通常是&#xf…

如何将 ECharts 图表插入 HTML Canvas

在 Web 开发中&#xff0c;数据可视化是一个常见且重要的需求。ECharts 是一个强大的图表库&#xff0c;而 HTML5 Canvas 则提供了灵活的绘图能力。今天&#xff0c;我们将探讨如何将这两者结合起来&#xff0c;实现将 ECharts 生成的图表插入到 HTML Canvas 中的特定位置。 为…

docker 文件目录迁移

文章参考 du -hs /var/lib/docker/ 命令查看磁盘使用情况。 du -hs /var/lib/docker/docker system df命令&#xff0c;类似于Linux上的df命令&#xff0c;用于查看Docker的磁盘使用情况: rootnn0:~$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 7 2 122.2…

【微信小程序_11_全局配置】

摘要:本文介绍了微信小程序全局配置文件 app.json 中的常用配置项,重点阐述了 window 节点的各项配置,包括导航栏标题文字、背景色、标题颜色,窗口背景色、下拉刷新样式以及上拉触底距离等。通过这些配置可实现小程序窗口外观的个性化设置,提升用户体验。 微信小程序_11_全…

智能听诊器:宠物健康管理的得力助手

随着科技的进步&#xff0c;智能听诊器已经成为宠物健康管理领域的一项革命性发明。它不仅能够实时监测宠物的心跳、呼吸频率和节律等关键生理指标&#xff0c;而且通过高精度的传感器捕捉到宠物心跳的微小变化和呼吸频率的微妙差异&#xff0c;为宠物主人提供了实时的健康数据…