Android Framework AMS(09)service组件分析-3(bindService和unbindService关键流程分析)

server/2024/10/19 3:27:51/

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


本章关键点总结 & 说明:

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

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

接下来开始详细解读。

1 AMS.bindService流程解读(onCreate、onBind)

AMS.bindService代码实现如下:

//ActivityManagerServicepublic int bindService(IApplicationThread caller, IBinder token,Intent service, String resolvedType,IServiceConnection connection, int flags, int userId) {// 检查调用者是否是隔离的进程,如果不是,则抛出安全异常enforceNotIsolatedCaller("bindService");//...synchronized(this) {return mServices.bindServiceLocked(caller, token, service, resolvedType,connection, flags, userId);}}

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

//ActivityService//关键流程:step1int bindServiceLocked(IApplicationThread caller, IBinder token,Intent service, String resolvedType,IServiceConnection connection, int flags, int userId) {// 获取请求绑定服务的客户端应用记录final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);//...// 如果token不为空,尝试获取对应的Activity记录ActivityRecord activity = null;if (token != null) {activity = ActivityRecord.isInStackLocked(token);//...}// 获取客户端为服务绑定设置的标签和PendingIntentint clientLabel = 0;PendingIntent clientIntent = null;// 如果调用者是系统进程,尝试获取客户端Intent和标签if (callerApp.info.uid == Process.SYSTEM_UID) {try {clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT);} catch (RuntimeException e) {}if (clientIntent != null) {clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);if (clientLabel != 0) {// 如果设置了客户端标签,创建一个新的Intent用于服务绑定service = service.cloneFilter();}}}// 如果设置了BIND_TREAT_LIKE_ACTIVITY标志,检查调用者是否有MANAGE_ACTIVITY_STACKS权限if ((flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,"BIND_TREAT_LIKE_ACTIVITY");}// 判断调用者是否在前台运行final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;// 查找服务记录ServiceLookupResult res =retrieveServiceLocked(service, resolvedType,Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);// 如果服务记录为空或未找到服务,返回0或-1if (res == null) {return 0;}if (res.record == null) {return -1;}ServiceRecord s = res.record;// 清除调用者的身份信息,以便在操作过程中不泄露调用者的信息final long origId = Binder.clearCallingIdentity();try {// 如果服务需要重启,取消重启计划if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {}// 如果设置了BIND_AUTO_CREATE标志,更新服务最后活跃的时间if ((flags & Context.BIND_AUTO_CREATE) != 0) {s.lastActivity = SystemClock.uptimeMillis();if (!s.hasAutoCreateConnections()) {ProcessStats.ServiceState stracker = s.getTracker();if (stracker != null) {stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),s.lastActivity);}}}// 启动与服务的关联mAm.startAssociationLocked(callerApp.uid, callerApp.processName,s.appInfo.uid, s.name, s.processName);// 检索服务的应用绑定记录AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);// 创建新的连接记录ConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent);// 获取连接的BinderIBinder binder = connection.asBinder();// 获取服务的连接列表ArrayList<ConnectionRecord> clist = s.connections.get(binder);if (clist == null) {clist = new ArrayList<ConnectionRecord>();s.connections.put(binder, clist);}// 将连接记录添加到服务的连接列表中clist.add(c);b.connections.add(c);// 如果有Activity记录,将其添加到Activity的连接列表中if (activity != null) {if (activity.connections == null) {activity.connections = new HashSet<ConnectionRecord>();}activity.connections.add(c);}b.client.connections.add(c);// 如果设置了BIND_ABOVE_CLIENT标志,标记客户端有高于自身的服务绑定if ((c.flags & Context.BIND_ABOVE_CLIENT) != 0) {b.client.hasAboveClient = true;}// 如果服务的应用记录不为空,更新服务的客户端活动if (s.app != null) {updateServiceClientActivitiesLocked(s.app, c, true);}// 获取全局服务连接列表clist = mServiceConnections.get(binder);if (clist == null) {clist = new ArrayList<ConnectionRecord>();mServiceConnections.put(binder, clist);}clist.add(c);// 如果设置了BIND_AUTO_CREATE标志,启动服务if ((flags & Context.BIND_AUTO_CREATE) != 0) {s.lastActivity = SystemClock.uptimeMillis();//关键方法:拉起服务if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {return 0;}}// 如果服务的应用记录不为空,根据标志更新服务的属性if (s.app != null) {if ((flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {s.app.treatLikeActivity = true;}// 更新服务的最近最少使用状态和内存调整mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities|| s.app.treatLikeActivity, b.client);mAm.updateOomAdjLocked(s.app);}// 如果服务的应用记录不为空且Intent已接收,连接客户端if (s.app != null && b.intent.received) {try {c.conn.connected(s.name, b.intent.binder);} catch (Exception e) {// 异常处理代码...}// 如果Intent只有一个绑定且需要重新绑定,请求服务绑定if (b.intent.apps.size() == 1 && b.intent.doRebind) {requestServiceBindingLocked(s, b.intent, callerFg, true);}} else if (!b.intent.requested) {// 如果Intent未请求,请求服务绑定requestServiceBindingLocked(s, b.intent, callerFg, false);}// 确保服务不在启动的后台服务列表中getServiceMap(s.userId).ensureNotStartingBackground(s);} finally {// 恢复调用者的身份信息Binder.restoreCallingIdentity(origId);}// 返回1表示服务绑定成功return 1;}//关键流程:step2private 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) {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;}//关键流程:step3private 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);// 关键方法:通过应用线程调度服务的创建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));}// 发送服务参数,回调执行 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.   bindServiceLocked 
  2. bringUpServiceLocked
  3. realStartServiceLocked  

  

最后的realStartServiceLocked才是实际启动服务的方法,主要作用是确保服务在正确的进程中被创建和启动。它涉及到与应用程序线程的通信,服务状态的更新,以及服务生命周期的管理。代码中的scheduleCreateService方法用于请求应用程序线程创建服务,requestServiceBindingsLocked方法用于请求服务的绑定。到这里我们主要关注2个关键方法:

  • scheduleCreateService(调用service的onCreate)
  • requestServiceBindingsLocked(调用到service的onBind)

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

这里实际上是以bindService到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 requestServiceBindingsLocked相关流程分析(bindService到onBind)

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

//ActivityService//关键流程:step1private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) {// 遍历服务记录中的所有绑定记录for (int i = r.bindings.size() - 1; i >= 0; i--) {// 获取服务的一个绑定记录IntentBindRecord ibr = r.bindings.valueAt(i);// 请求服务与客户端的绑定// 如果绑定失败,则中断循环,不再请求后续的绑定if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {break;}}}//关键流程:step2private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,boolean execInFg, boolean rebind) {if (r.app == null || r.app.thread == null) {return false;}// 如果服务尚未请求绑定,或者这是一次重新绑定,并且有待绑定的客户端if ((!i.requested || rebind) && i.apps.size() > 0) {try {// 增加服务执行的计数,并根据是否在前台执行来更新状态bumpServiceExecutingLocked(r, execInFg, "bind");// 强制服务所在进程的状态至少为服务状态r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);// 关键方法:通过服务的应用线程,调度服务的绑定操作r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,r.app.repProcState);// 如果这不是重新绑定,则标记该服务的绑定已被请求if (!rebind) {i.requested = true;}// 标记服务已被绑定,且设置不需要重新绑定的标志i.hasBound = true;i.doRebind = false;} catch (RemoteException e) {return false;}}return true;}

这里我们主要关注requestServiceBindingLocked方法,他的主要作用是检查服务是否能够被绑定(即服务及其应用线程是否存在),如果是,则通过服务的应用线程调度服务的绑定操作。代码中的IntentBindRecord对象包含了服务绑定的详细信息,如绑定的Intent、客户端信息等。整理下,关键步骤如下:

  1. 检查服务及其应用线程是否存在。
  2. 如果服务尚未请求绑定或这是一次重新绑定,且有待绑定的客户端,则继续处理。
  3. 增加服务执行的计数,并根据是否在前台执行来更新状态。
  4. 强制服务所在进程的状态至少为服务状态。
  5. 关键方法:通过服务的应用线程调度服务的绑定操作。
  6. 如果这不是重新绑定,则标记该服务的绑定已被请求,并标记服务已被绑定。

接下来我们主要解读步骤5,scheduleBindService主要是发送消息,代码实现如下:

//ActivityThread//ApplicationThreadpublic final void scheduleBindService(IBinder token, Intent intent,boolean rebind, int processState) {updateProcessState(processState, false);BindServiceData s = new BindServiceData();s.token = token;s.intent = intent;s.rebind = rebind;sendMessage(H.BIND_SERVICE, s);}//消息处理private class H extends Handler {//...public void handleMessage(Message msg) {switch (msg.what) {case BIND_SERVICE:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");handleBindService((BindServiceData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;//...}}//...}//...private void handleBindService(BindServiceData data) {Service s = mServices.get(data.token);// 如果服务实例不为空,继续处理绑定请求if (s != null) {try {// 设置Intent的类加载器为服务的类加载器,以便能正确解析其中的Serializable和Parcelable对象data.intent.setExtrasClassLoader(s.getClassLoader());// 准备Intent以进入当前进程data.intent.prepareToEnterProcess();// 尝试处理服务绑定try {// 如果这不是重新绑定,调用服务的onBind方法并发布服务的IBinder给客户端if (!data.rebind) {// 关键方法:执行service组件的onBind操作IBinder binder = s.onBind(data.intent);// 发布服务,使客户端能够与服务进行通信ActivityManagerNative.getDefault().publishService(data.token, data.intent, binder);} else {// 如果是重新绑定,调用服务的onRebind方法s.onRebind(data.intent);// 通知AMS服务重新绑定操作已完成ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);}ensureJitEnabled();} catch (RemoteException ex) {//...}} catch (Exception e) {//...}}}

这段代码的主要作用是处理服务的绑定请求,包括调用服务的onBind或onRebind方法,并发布服务的IBinder给客户端。代码中的BindServiceData对象包含了服务绑定请求所需的所有信息,如服务的token、Intent、是否为重新绑定等。

2 AMS.unbindService流程解读(onUnBind、onDestroy)

AMS.unbindService代码实现如下:

//ActivityManagerServicepublic boolean unbindService(IServiceConnection connection) {synchronized (this) {return mServices.unbindServiceLocked(connection);}}

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

//ActivityService//关键流程:step1boolean unbindServiceLocked(IServiceConnection connection) {IBinder binder = connection.asBinder();// 从全局服务连接映射中获取与该Binder相关联的连接记录列表ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);// 如果连接记录列表为空,说明没有找到相应的服务连接,返回falseif (clist == null) {return false;}final long origId = Binder.clearCallingIdentity();try {// 遍历连接记录列表,解绑所有相关服务while (clist.size() > 0) {// 获取列表中的第一个连接记录ConnectionRecord r = clist.get(0);// 关键方法:解除服务连接removeConnectionLocked(r, null, null);// 如果列表中的第一个连接记录仍然是r,说明没有被移除,手动移除它if (clist.size() > 0 && clist.get(0) == r) {clist.remove(0);}// 如果服务绑定记录的服务应用不为空,更新相关设置if (r.binding.service.app != null) {// 如果设置了BIND_TREAT_LIKE_ACTIVITY标志,更新服务应用的属性if ((r.flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {r.binding.service.app.treatLikeActivity = true;// 更新服务应用的最近最少使用状态mAm.updateLruProcessLocked(r.binding.service.app,r.binding.service.app.hasClientActivities|| r.binding.service.app.treatLikeActivity, null);}// 更新服务应用的内存调整mAm.updateOomAdjLocked(r.binding.service.app);}}} finally {Binder.restoreCallingIdentity(origId);}return true;}//关键流程:step2void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {IBinder binder = c.conn.asBinder();// 获取服务绑定记录AppBindRecord b = c.binding;// 获取服务记录ServiceRecord s = b.service;// 获取服务的连接列表ArrayList<ConnectionRecord> clist = s.connections.get(binder);// 如果连接列表不为空,移除对应的连接记录if (clist != null) {clist.remove(c);// 如果连接列表为空,从服务的连接映射中移除该Binder的条目if (clist.size() == 0) {s.connections.remove(binder);}}// 从服务绑定记录的连接列表中移除连接记录b.connections.remove(c);// 如果连接记录有关联的活动记录,且不是跳过的活动记录,则移除该连接记录if (c.activity != null && c.activity != skipAct) {if (c.activity.connections != null) {c.activity.connections.remove(c);}}// 如果连接记录绑定的服务应用不是跳过的应用记录,则移除该连接记录if (b.client != skipApp) {b.client.connections.remove(c);// 如果设置了BIND_ABOVE_CLIENT标志,更新服务应用是否有高于自身的服务绑定if ((c.flags & Context.BIND_ABOVE_CLIENT) != 0) {b.client.updateHasAboveClientLocked();}// 如果服务应用不为空,更新服务应用的客户端活动if (s.app != null) {updateServiceClientActivitiesLocked(s.app, c, true);}}// 从全局服务连接映射中移除连接记录clist = mServiceConnections.get(binder);if (clist != null) {clist.remove(c);// 如果连接列表为空,从全局服务连接映射中移除该Binder的条目if (clist.size() == 0) {mServiceConnections.remove(binder);}}// 停止服务应用和客户端应用之间的关联mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);// 如果服务绑定记录的连接列表为空,则从服务Intent的绑定应用列表中移除该应用if (b.connections.size() == 0) {b.intent.apps.remove(b.client);}// 如果服务没有死亡,执行进一步的清理操作if (!c.serviceDead) {// 如果服务应用不为空,且没有其他绑定的应用,执行服务的unbind操作if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0&& b.intent.hasBound) {try {// 增加服务执行的计数,并根据是否在前台执行来更新状态bumpServiceExecutingLocked(s, false, "unbind");// 如果服务应用的进程状态小于等于接收者状态,更新服务应用的最近最少使用状态if (b.client != s.app && (c.flags & Context.BIND_WAIVE_PRIORITY) == 0&& s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {mAm.updateLruProcessLocked(s.app, false, null);}// 更新服务应用的内存调整mAm.updateOomAdjLocked(s.app);// 标记服务Intent没有绑定的应用b.intent.hasBound = false;b.intent.doRebind = false;// 关键方法:通知服务应用执行unbind操作s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());} catch (Exception e) {//...serviceProcessGoneLocked(s);}}// 如果设置了BIND_AUTO_CREATE标志,且没有其他自动创建的绑定,则关闭服务if ((c.flags & Context.BIND_AUTO_CREATE) != 0) {boolean hasAutoCreate = s.hasAutoCreateConnections();// 如果没有其他自动创建的绑定,则更新服务的状态跟踪器if (!hasAutoCreate) {if (s.tracker != null) {s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),SystemClock.uptimeMillis());}}// 如果需要,执行服务的关闭逻辑bringDownServiceIfNeededLocked(s, true, hasAutoCreate);}}}

这里我们关注removeConnectionLocked方法,它的主要作用是移除服务连接,包括从服务的连接映射中移除连接记录、更新服务应用的客户端活动、执行服务的unbind操作以及关闭服务。代码中的ConnectionRecord对象包含了服务连接的详细信息,AppBindRecord对象包含了服务绑定的详细信息。到这里我们主要关注2个关键方法:

  • scheduleUnbindService(调用service的onUnbind)
  • bringDownServiceIfNeededLocked(调用到service的onDestroy)

2.1 scheduleUnbindService相关流程解读(unbindservice到onUnbind)

这里实际上是以unbindService到service组件调用onUnbind的流程分析为目的。这里主要是通过scheduleUnbindService方法发送消息,处理解绑操作。该方法代码实现如下:

//ActivityThread//ApplicationThreadpublic final void scheduleUnbindService(IBinder token, Intent intent) {BindServiceData s = new BindServiceData();s.token = token;s.intent = intent;sendMessage(H.UNBIND_SERVICE, s);}//消息处理private class H extends Handler {//...public void handleMessage(Message msg) {switch (msg.what) {case UNBIND_SERVICE:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");handleUnbindService((BindServiceData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;//...}}//...}//...private void handleUnbindService(BindServiceData data) {Service s = mServices.get(data.token);if (s != null) {try {// 设置Intent的类加载器为服务的类加载器,以便能正确解析其中的Serializable和Parcelable对象data.intent.setExtrasClassLoader(s.getClassLoader());// 准备Intent以进入当前进程data.intent.prepareToEnterProcess();// 调用服务的onUnbind方法,询问服务是否需要重新绑定boolean doRebind = s.onUnbind(data.intent);// 如果服务需要重新绑定,通知ActivityManager服务解绑已完成,并标记为需要重新绑定if (doRebind) {ActivityManagerNative.getDefault().unbindFinished(data.token, data.intent, doRebind);} else {// 如果服务不需要重新绑定,通知ActivityManager服务解绑操作已完成ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);}} catch (Exception e) {//...}}}

handleUnbindService方法的主要作用是处理服务的解绑请求,包括调用服务的onUnbind方法,并根据服务的响应通知ActivityManager服务解绑已完成代码中的BindServiceData对象包含了服务解绑请求所需的所有信息,如服务的token、Intent等。

2.2 bringDownServiceIfNeededLocked相关流程解读(unbindservice到onDestroy)

这里实际上是以unbindService到service组件调用onDestroy的流程分析为目的。这里主要是通过bringDownServiceIfNeededLocked方法进行destroy相关操作。

注意:针对仅通过 bindService() 绑定的服务,在执行 unbindService() 操作时,onDestroy() 方法不一定会被调用。针对bind方式启动的service组件。onDestroy() 方法是否会被调用一般取决于以下条件:

  • 所有绑定都已解除:如果服务只通过 bindService() 绑定,并且所有绑定都已解除(即没有任何 ServiceConnection 再与该服务绑定),那么服务将被销毁,onDestroy() 方法会被调用。
  • 服务未延迟停止:如果服务没有设置延迟停止的标志(例如,没有在 onUnbind() 方法中返回 true),那么在所有绑定都解除后,服务将直接停止,onDestroy() 方法会被调用。
  • 如果服务在 onUnbind() 方法中返回 true,表示服务希望在解绑后重新绑定,那么服务不会立即销毁,onDestroy() 方法也不会被调用。在这种情况下,如果服务在未来被重新绑定,onBind() 方法将再次被调用。

总结来说,对于仅通过 bindService() 绑定的服务,如果所有绑定都已解除,并且没有其他机制(如 onUnbind() 返回 true)阻止服务销毁,那么 onDestroy() 方法会被调用。这是服务生命周期的一部分,确保服务在不再需要时能够正确地清理资源。

有了这个了解后,我们继续分析bringDownServiceIfNeededLocked方法,代码实现如下:

//ActivityService//关键流程:step1private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn, boolean hasConn) {// 检查服务是否仍然需要如果服务仍然需要,例如服务正在运行或者有待处理的启动请求,则不停止服务并直接返回if (isServiceNeeded(r, knowConn, hasConn)) {return;}// 如果服务在待处理列表中,说明服务的启动请求还在处理中,因此不停止服务if (mPendingServices.contains(r)) {return;}// 如果服务不再需要且不在待处理列表中,则停止服务bringDownServiceLocked(r);}//关键流程:step2private 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);}

这里最后的bringDownServiceLocked才是实际关闭服务的方法,它的作用是关闭服务并执行相关的清理工作。它涉及到服务绑定的清理(如果bind则执行unbind操作,主要针对bindservice操作,本次分析不涉及)、服务执行计数的更新、服务状态的更新、服务通知的取消以及服务销毁逻辑的调用。接下来我们关注unbindService的通知应用销毁服务的关键方法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个关键流程:

结合上一章中分析的2个关键流程:

  • AMS.startService->service组件onCreate、onStartCommand
  • AMS.stopService->service组件onDestroy

目前已经对service组件的生命周期和AMS中service组件相关流程有一定的了解。


http://www.ppmy.cn/server/132929.html

相关文章

Android JNI调用.c文件

Android JNI调用.c文件 1.创建Android项目,创建一个jni目录来存放.c代码 2.CMakeLists.txt cmake_minimum_required(VERSION 3.10.2) project("MyApplication")add_library(native-lib SHARED native-lib.c)find_library(log-lib log)target_link_libraries

开发一个微信小程序要多少钱?

在当今数字化时代&#xff0c;微信小程序成为众多企业和个人拓展业务、提供服务的热门选择。那么&#xff0c;开发一个微信小程序究竟需要多少钱呢&#xff1f; 开发成本主要取决于多个因素。首先是功能需求的复杂程度。如果只是一个简单的信息展示小程序&#xff0c;功能仅限…

简单实现通过电脑操作手机

通过电脑操作手机&#xff0c;支持单击&#xff0c;拖抓事件&#xff0c;延时有1-2秒。 具体步骤&#xff1a; 1、从手机截图到sdcard 2、将图片导出到PC 3、从PC加载展示图片 4、开启定时器 5、设置点击、滚动事件 1、 private static void takeScreenshot(String path)…

linux使用nmcli 管理wifi的命令

在 Linux 系统中&#xff0c;nmcli 是 NetworkManager 的命令行工具&#xff0c;常用于管理网络连接&#xff0c;包括 WiFi。下面是一些常见的使用 nmcli 管理 WiFi 的命令。 1. 显示所有可用的 WiFi 网络 nmcli dev wifi list这个命令会列出当前可以扫描到的 WiFi 网络及其信…

Docker镜像的使用

目录 前提条件 Docker命令图 镜像命令的使用 列出镜像列表 搜索镜像 拉取镜像 查看镜像占用存储空间 删除镜像 制作镜像 从已经创建容器的创建镜像 从Dockerfile中构建镜像 保存与加载镜像 发布镜像 1.命名空间和镜像仓库准备 2.登录阿里云Docker Registry 3.给…

洛谷 P1803:凌乱的yyy / 线段覆盖 ← 贪心算法

【题目来源】https://www.luogu.com.cn/problem/P1803【题目背景】 快 noip 了&#xff0c;yyy 很紧张&#xff01;【题目来源】 现在各大 oj 上有 n 个比赛&#xff0c;每个比赛的开始、结束的时间点是知道的。 yyy 认为&#xff0c;参加越多的比赛&#xff0c;noip 就能考的越…

【docker】mysql8.0 的 docker 安装

安装 指定mysql 的安装版本8.0.18 拉取镜像 docker pull mysql:8.0。18创建目录 mkdir -p /opt/docker_volumn/mysql/conf mkdir -p /opt/docker_volumn/mysql/log mkdir -p /opt/docker_volumn/mysql/data mkdir -p /opt/docker_volumn/mysql/mysql-files此步骤是为了将容…

云计算作业一:问题解决备忘

教程地址&#xff1a;https://blog.csdn.net/qq_53877854/article/details/142412784 修改网络配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33在root用户下编辑 静态ip地址配置后查看ip与配置不符 注意&#xff1a;确保在这之前已经在VMware的编辑>虚拟网络编…