在前面文章我们分析了四大组件中的两个: Broadcast 和 Activity, 这章我们分析四大组件中的服务 (Service) 的启动过程. Service 的启动方式有两种: 一种是 startService, 一种是 bindService; 第一种通常是开启一个服务执行后台任务, 不进行通信, 第二章通过是启动服务进行通信. 下面我们就根据这两种启动方式来讲 Service 的启动流程以及 unbindService 和 stopService 流程.
Service 启动流程 - startService
首先来看启动流程时序图:
- Step0.ContextImpl.startService
- @Override
- public ComponentName startService(Intent service) {
- warnIfCallingFromSystemProcess();
- return startServiceCommon(service, mUser);
- }
调用当前类中的 startServiceCommon 方法.
- Step1.ContextImpl.startServiceCommon
- private ComponentName startServiceCommon(Intent service, UserHandle user) {
- try {
- // 检验 Intent, 组件和包名不能为空
- validateServiceIntent(service);
- service.prepareToLeaveProcess(this);
- // 通过 getDefault 方法获取 AMS 的一个代理对象 (ActivityManagerProxy), 然后调用这个代理对象
- // 的 startService 方法来请求 AMS 启动 Service
- ComponentName cn = ActivityManagerNative.getDefault().startService(
- mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
- getContentResolver()), getOpPackageName(), user.getIdentifier());
- ...
- return cn;
- } catch (RemoteException e) {
- ...
- }
- }
首先验证 Intent 中传递的组件名是否为空, 为什么判断下面我们介绍, 接着通过代理对象 ActivityManagerProxy, 通过 Binder 调用 AMS(ActivityManagerService) 中的对应方法 startService. 我们先看包名验证.
- Step2.ContextImpl.validateServiceIntent
- 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));
- }
- }
- }
这里给出了如果系统在 Android5.0 及以上版本, 启动服务必须为显式启动, 否则抛出异常, 这个情况我们在刚开始在高于 5.0 系统都会遇到过, 限制就在这里, 所以, 5.0 及以上系统必须用显式的方式启动服务.
- 3.AMP.startService
- public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, String callingPackage, int userId) throws RemoteException {
- ...
- // 通过 Binder 对象 mRemote 向 AMS 发送一个类型为 START_SERVICE_TRANSACTION 的进程间通信请求,
- // 然后会调用 AMS 中的对应的 startService 方法
- mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
- ...
- return res;
- }
看过前面文章的对这一段代码应该很熟悉了, 这个就是通过 Binder 调用 AMS 中对应方法的. 所以我们直接看 AMS.
- 4.AMS.startService
- public ComponentName startService(IApplicationThread caller, Intent service,
- String resolvedType, String callingPackage, int userId)
- throws TransactionTooLargeException {
- ...
- synchronized (this) {
- ...
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
- Binder.restoreCallingIdentity(origId);
- return res;
- }
- }
这里的 mServices 是 ActiveServices, 因此调用的是 ActiveServices 中的 startServiceLocked 方法.
5.ActiveServices.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
- int callingPid, int callingUid, String callingPackage, final int userId)
- throws TransactionTooLargeException {
- ...
- // 解析 service 这个 Intent, 就是解析在 AndroidManifest.xml 定义的 Service 标签的 intent-filter 相关内容
- // 并将其内容保存在 Service 的 record(ServiceRecord) 中
- ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, true, callerFg, false);
- ...
- // 每一个 Service 组件都使用一个 ServiceRecord 对象来描述, 就像每一个 Activity 都是用一个 ActivityRecord
- // 对象来描述一样
- ServiceRecord r = res.record;
- ...
- // 加入启动服务列表
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.mUserController.hasStartedUserState(r.userId)) {
- // 获取启动服务所在进程
- ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
- ...
- } else if (DEBUG_DELAYED_STARTS) {
- ...
- }
- return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
- }
这里做的主要是启动服务前的准备工作, 首先是解析 Intent 携带的参数, 并将这些内容保存在用来描述 Service 的 ServiceRecord 对象中保存起来, 并将该对象放到等待启动服务的列表中. 然后调用 startServiceInnerLocked 启动服务. 在上面调用 retrieveServiceLocked 函数解析的过程中先去判断 AMS 中是否存在参数为 service 对应的 ServiceRecord 对象, 如果存在说明已经启动过该服务, 如果不存在, 说明是第一次启动该服务.
8.ActiveServices.startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
- ServiceState stracker = r.getTracker();// 获取服务状态
- ...
- r.callStart = false;// 是否调用 onStart 方法
- ...
- // 启动 ServiceRecord 对象 r 所描述的一个 Service 组件, 即 Server 组件
- String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
- ...
- return r.name;
- }
这里比较简单主要是调用 bringUpServiceLocked 唤起服务.
- Step9.ActiveServices.bringUpServiceLocked
- private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,boolean whileRestarting, boolean permissionsReviewRequired)
- throws TransactionTooLargeException {
- // 这里的 r.app.thread 是一个 ApplicationThread 对象, ApplicationThread 是用来 AMS 和应用进程通信的工具,
- // 如果服务中的这个 thread 不为空说明已经和该 Service 存在通信了, 也就是说已经启动了该服务了.
- // 如果服务已经存在, 调用 startService 的时候会执行 Service.onStartCommand,
- // 只有首次启动服务才会调用 onCreate 方法
- if (r.app != null && r.app.thread != null) {
- // 执行 Service.onStartCommand 方法过程
- sendServiceArgsLocked(r, execInFg, false);
- return null;
- }
- ...
- // Make sure that the user who owns this service is started. If not,
- // we don't want to allow it to run.
- // 确保正在启动服务的用户已经启动, 否则不允许执行
- if (!mAm.mUserController.hasStartedUserState(r.userId)) {
- ...
- bringDownServiceLocked(r);
- return msg;
- }
- ...
- // 是不是独立进程
- final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
- // 首先获取 ServiceRecord 对象 r 所描述的 Service 组件的 android:process 属性, 并保存在 procName 中
- final String procName = r.processName;
- ProcessRecord app;
- if (!isolated) {// 要启动的服务不是独立进程
- // 如果不是独立进程, 通过进程名称和 uid 查找是否已经存在一个对应的 ProcessRecord 对象 app, 如果存在,
- // 说明用来运行这个 Service 组件的应用进程已经存在了, 因此下面的 realStartServiceLocked 函数在
- // ProcessRecord 对象 app 所描述的应用程序进程中启动这个 Service 组件.
- app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
- if (app != null && app.thread != null) {// 进程存在, 并且该进程已经与 AMS 通信过, 那么直接启动服务
- try {
- ...
- // 启动服务
- realStartServiceLocked(r, app, execInFg);
- return null;
- } catch (TransactionTooLargeException e) {
- ...
- }
- // If a dead object exception was thrown -- fall through to
- // restart the application.
- }
- } else {// 如果要启动的进程是独立进程
- ...
- }
- // 如果要启动的 Service 所在进程没有启动
- if (app == null && !permissionsReviewRequired) {
- // 启动 Service 所需要的进程
if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
- "service", r.name, false, isolated, false)) == null) {
- ...
- // 启动失败
- bringDownServiceLocked(r);
- return msg;
- }
- ...
- }
- ...
- if (r.delayedStop) {// 如果是延迟停止的服务
- // Oh and hey we've already been asked to stop!
- r.delayedStop = false;
- if (r.startRequested) {
- // 停止服务
- stopServiceLocked(r);
- }
- }
- return null;
- }
这里是启动服务最重要的部分, 根据不同的情况进行不同的处理. 首先是判断服务所在进程是否存在, 如果存在调用 sendServiceArgsLocked 方法, 最终根据条件, 如果服务存在调用服务的 onStartCommand 方法; 然后判断被启动服务的用户是否已经被启动, 如果没有则停止服务, 也就是调用 bringDownServiceLocked 方法, 最终调用服务的 onDestroy 方法; 然后判断非独立进程的服务, 如果进程存在并且服务未启动的开始正式启动服务, 调用 realStartServiceLocked 方法, 最终调用 onCreate 方法; 然后判断如果进程不存在, 要启动进程, 并且在 app 启动后启动服务, 这里会调用启动失败, 停止启动, 因为进程启动后会启动该服务, 这个过程在前面我们讲过, 这里不再分析这种情况. 最后是如果是延迟停止的服务这里直接停止该服务. 下面我们按顺序分析这几种情况.
- Step10.ActiveServices.sendServiceArgsLocked
- private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
- boolean oomAdjusted) throws TransactionTooLargeException {
- // 等待启动服务个数
- final int N = r.pendingStarts.size();
- if (N == 0) {
- return;
- }
- while (r.pendingStarts.size()> 0) {
- ...
- try {
- ..
- // 标记启动服务开始
- bumpServiceExecutingLocked(r, execInFg, "start");
- ...
- // 发送消息, 传动到 ApplicationThread 中的 scheduleServiceArgs 方法, 最终会调用 onStartCommand
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
- } catch (TransactionTooLargeException e) {
- ...
- }
- }
- }
上面 Step5 提到启动的服务都要先放到等待启动服务列表中, 因此这里先判断服务列表是否存在要启动的服务, 如果不存在则不再继续执行, 如果存在, 循环启动服务, 这里调用 scheduleServiceArgs 方法, 其实在前面分析了很多遍, 最终会发送消息 ActivityThread 中的 Handler 中的 handleMessage 中进行处理, 然后调用 ActivityThread 中的 handleServiceArgs 方法.
- Step13.ActivityThread.handleServiceArgs
- private void handleServiceArgs(ServiceArgsData data) {
- // 获取 Service 对象
- Service s = mServices.get(data.token);
- if (s != null) {
- try {
- ...
- if (!data.taskRemoved) {// 任务没有被移除的话, 调用 Service.onStartCommand 方法
- res = s.onStartCommand(data.args, data.flags, data.startId);
- } else {// 否则调用被移除方法
- s.onTaskRemoved(data.args);
- res = Service.START_TASK_REMOVED_COMPLETE;
- }
- ...
- } catch (Exception e) {
- ...
- }
- }
- }
根据 Service 对应的 token 去缓存中获取服务, 如果有该服务那么调用服务的 onStartCommand 方法, 如果不存在那么就要继续往下走创建服务.
Step15.ActiveServices.bringDownServiceLocked
这个方法主要是处理停止服务的方法, 里面主要是断开连接, 解除绑定, 然后销毁服务, 因为这个过程是在服务停止时会调用, 所以在后面介绍, 这里先不介绍了.
- Step16.ActiveServices.realStartServiceLocked
- private final void realStartServiceLocked(ServiceRecord r,
- ProcessRecord app, boolean execInFg) throws RemoteException {
- ...
- boolean created = false;
- ...
- // 发送信息到主线程, 准备调用 Service.onCreate 方法
- // 请求 ProcessRecord 对象 app 描述的应用程序进程将 ServiceRecord 独享 r 所描述的 Service 组件启动起来.
- // ServiceRecord 对象 r 所描述的 Service 组件启动完成之后, AMS 就需要将它连接到一个请求绑定它的一个
- // Activity 组件中, 这是通过调用 AMS 类的另一个成员函数 requestServiceBindingLocked 来实现的
- app.thread.scheduleCreateService(r, r.serviceInfo,
- mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
- app.repProcState);
- ...
- // 准备调用 Service.onBind 方法
- requestServiceBindingsLocked(r, execInFg);
- ...
- // 准备调用 Service.onStartCommand 方法
- sendServiceArgsLocked(r, execInFg, true);
- ...
- }
启动服务调用三个方法, 首先是通过 app.thread.scheduleCreateService 方法调用 onCreate 方法, 然后通过 requestServiceBindingsLocked 方法调用 Service.onBind 方法, 然后通过 sendServiceArgsLocked 方法调用 Service.onStartCommand 方法, 其中最后一个方法我们分析过了, 所以我们只分析前两个. 第一很简单了, 最终调用 ActivityThread 中的 handleCreateService 方法.
- Step18.ActivityThread.handleCreateService
- private void handleCreateService(CreateServiceData data) {
- ...
- // 获取一个用来描述即将要启动的 Service 组件所在的应用程序的 LoadedApk 对象, 并将它保存在 packageInfo
- // 变量中 (每一个应用程序都使用一个 LoadedApk 对象来描述, 通过它就能方位到它所描述的应用程序的资源)
- LoadedApk packageInfo = getPackageInfoNoCheck(
- data.info.applicationInfo, data.compatInfo);
- Service service = null;
- ...
- // 获取类加载器
- java.lang.ClassLoader cl = packageInfo.getClassLoader();
- // 通过类加载器将 CreateServiceData 对象 data 描述的一个 Service 组件加载的内存中, 并且创建它的一个
- // 实例, 保存在 Service 对象 service 中. 因为 CreateServiceData 对象 data 描述的 Service 组件即为应用
- // 程序的 Ashmem 中的 Server 组件, 因此, Service 对象 service 指向的 Service 组件实际上是一个 Server 组件
- service = (Service) cl.loadClass(data.info.name).newInstance();
- ...
- // 初始化一个 ContextImpl 对象 context, 用来为前面所创建的 Service 对象 service 的运行上下文环境,
- // 通过它可以访问特定的应用程序资源, 以及启动其他应用程序组件
- ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
- context.setOuterContext(service);
- // 创建一个 Application 对象 app, 用来描述 Service 对象 service 所属的应用程序.
- Application app = packageInfo.makeApplication(false, mInstrumentation);
- // 使用 Application 对象 app,ContextImpl 对象 context 和 CreateServiceData 对象 data 来初始化
- // Service 对象 service
service.attach(context, this, data.info.name, data.token, app,
- ActivityManagerNative.getDefault());
- // 调用 Service 的 onCreate 方法
- service.onCreate();
- // 以 token 为关键字保存 Service 对象 service 到 mServices 中, 服务启动完成
- mServices.put(data.token, service);
- ...
- } catch (Exception e) {
- ...
- }
- }
首先获取 LoadedApk 对象, 然后通过类加载器加载 Service 类, 初始化 Context, 获取对应的 Application, 如果存在直接返回, 如果该应用还没启动则直接创建该 Application, 然后通过 Service 的 attach 方法将对应的信息放置到 Service 中, 这里面就包含 ActivityThread, 因此我们在 Step9 中可以通过这个来判断 Service 是不是被启动了, 然后调用 onCreate 方法, 创建完成后, 将该服务以 token 为键, Service 为值放入到缓存中, 这样我们前面获取的时候就只从这里获取的, 因此如果服务启动了换粗就会存在, 否则不存在. 下面我们分析 onBind 方法.
- Step20.ActiveServices.requestServiceBindingsLocked
- // 参数 r 指向一个 ServiceRecord, 表示一个已经启动的 Service 组件
- private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
- throws TransactionTooLargeException {
- for (int i = r.bindings.size() - 1; i>= 0; i--) {
- // 每一个 IntentBindRecord 对象都用来描述若干个需要将 ServiceRecord 对象 r 所描述的 Service 组件
- // 绑定到它们里面的应用程序进程
- IntentBindRecord ibr = r.bindings.valueAt(i);
- if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
- break;
- }
- }
- }
for 循环调用 onBind.
- Step21.ActiveServices.requestServiceBindingLocked
- // 参数 rebind 表示是否需要将 ServiceRecord 对象 r 所描述的 Service 组件重新绑定到 IntentBindRecord 对象 i
- // 所描述的应用程序进程中如果为 false, 则说明为第一绑定
- private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,boolean execInFg, boolean rebind) throws TransactionTooLargeException {
- ...
- // 检查 AMS 是否已经为 IntentBindRecord 对象 i 所描述的应用程序进程请求过 ServiceRecord 对象 r 所描述的
- // Service 组件返回其内部的一个 Binder 本地对象. 如果还没有请求 requested 为 false 并且 apps 的数量大于 0
- if ((!i.requested || rebind) && i.apps.size()> 0) {
- try {
- ...
- // 会执行到 Service 的 onBind 方法
- r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,r.app.repProcState);
- if (!rebind) {
- // 设置为 true, 防止重复请求
- i.requested = true;
- }
- ...
- }
- }
- return true;
- }
这里通过调用 r.app.thread.scheduleBindService 方法, 最终调用到 ActivityThread 中的 handleBindService 方法.
- Step23.ActivityThread.handleBindService
- private void handleBindService(BindServiceData data) {
- // 通过 token 来获得一个描述 Service 组件的 Service 对象
- Service s = mServices.get(data.token);
- if (s != null) {
- try {
- ...
- if (!data.rebind) {// 首次绑定
- // 获取一个实现了 IBinder 接口的 Binder 对象
- IBinder binder = s.onBind(data.intent);
- ...
- } else {
- s.onRebind(data.intent);
- ...
- }
- ...
- } catch (Exception e) {
- ...
- }
- }
- }
现获取服务, 然后判断是再次绑定还是首次绑定, 如果是首次绑定调用 Service.onBind 方法, 如果是再次绑定调用 Service.onRebind 方法. 到这里服务的启动就完成了, 其他一些操作就不分析了. 下面我们先分析另外一个启动流程 bindService, 最后分析停止服务流程.
Service 启动流程 - bindService
首先来看绑定流程时序图:
- Step1.ContextImpl.bindService
- public boolean bindService(Intent service, ServiceConnection conn,
- int flags) {
- warnIfCallingFromSystemProcess();
- return bindServiceCommon(service, conn, flags, mMainThread.getHandler(),
- Process.myUserHandle());
- }
这里是绑定服务的入口位置, 调用 bindServiceCommon 方法.
- Step2.ContextImpl.bindServiceCommon
- private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler
- handler, UserHandle user) {
- IServiceConnection sd;
- ...
- // mPackageInfo 类型是 LoadedApk
- if (mPackageInfo != null) {
- // 将 ServiceConnection 对象 conn 封装成一个实现了 IServiceConnection 接口的 Binder 本地对象 sd
- sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
- } else {
- ...
- }
- ...
- try {
- IBinder token = getActivityToken();
- ...
- // 通过调用代理对象 ActivityManagerProxy 的 bindService 方法将前面获得的 sd 对象, 以及 Intent 对象
- // service 等信息发送给 AMS, 以便 AMS 可以将 ServiceConnection 组件启动起来
- int res = ActivityManagerNative.getDefault().bindService(
- mMainThread.getApplicationThread(), getActivityToken(), service,
- service.resolveTypeIfNeeded(getContentResolver()),
- sd, flags, getOpPackageName(), user.getIdentifier());
- ...
- return res != 0;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
首先调用 LoadedApk 中的 getServiceDispatcher 方法获取实现 IServiceConnection 接口的 Binder 对象 ServiceDispatcher.InnerConnection. 然后调用 AMP 中的 bindService 方法, 然后通过 Binder 通信调用 AMS 中的 bindService 方法.
- Step3.LoadedApk.getServiceDispatcher
- // 每一个绑定过 Service 组件的 Activity 组件在 LoadedApk 类中都有一个对应的 ServiceDispatcher 对象, 它负责将
- // 这个被绑定的 Service 组件与绑定它的 Activity 组件关联起来, 这些 ServiceDispatcher 保存在 map 中
- public final IServiceConnection getServiceDispatcher(ServiceConnection c,
- Context context, Handler handler, int flags) {
- synchronized (mServices) {
- LoadedApk.ServiceDispatcher sd = null;
- ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
- // 检查成员变量 mServices 中是否存在一个以 ServiceConnection 对象 c 为关键字的 ServiceDispatcher
- // 对象 sd, 如果不存在, 则创建一个并且以 context 为关键字保存到 mServices 中
- if (map != null) {
- sd = map.get(c);
- }
- if (sd == null) {
- sd = new ServiceDispatcher(c, context, handler, flags);
- if (map == null) {
- map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
- mServices.put(context, map);
- }
- map.put(c, sd);
- } else {
- sd.validate(context, handler);
- }
- // 调用前面获取到的 ServiceDispatcher 对象 sd 的成员函数 getIServiceConnection 来获取一个实现了
- // IServiceConnection 接口的本地 Binder 对象
- return sd.getIServiceConnection();
- }
- }
首先根据 ServiceConnection 取缓存中获取, 如果没有要初始化一个 ServiceDispatcher 对象, 然后获取 ServiceDispatcher.InnerConnection 对象并且返回.
- Step6.AMP.bindService
- public int bindService(IApplicationThread caller, IBinder token,Intent service, String resolvedType, IServiceConnection connection,int flags, String callingPackage, int userId) throws RemoteException {
- ...
- // 通过 Binder 对象 mRemote 向 AMS 发送一个类型为 BIND_SERVICE_TRANSACTION 的进程间通信请求
- mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
- ...
- return res;
- }
这里通过 Binder 调用 AMS 中对应的方法.
- Step7.AMS.bindService
- public int bindService(IApplicationThread caller, IBinder token, Intent service,
- String resolvedType, IServiceConnection connection, int flags, String callingPackage,
- int userId) throws TransactionTooLargeException {
- ...
- synchronized (this) {
- return mServices.bindServiceLocked(caller, token, service,
- resolvedType, connection, flags, callingPackage, userId);
- }
- }
这里调用 ActiveServices.bindServiceLocked 方法.
- Step8.ActiveServices.bindServiceLocked
- int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
- String resolvedType, final IServiceConnection connection, int flags,
- String callingPackage, final int userId) throws TransactionTooLargeException {
- if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService:" + service
- + "type=" + resolvedType + "conn=" + connection.asBinder()
- + "flags=0x" + Integer.toHexString(flags));
- // 根据 caller 来获取一个 ProcessRecord 对象 callerApp 用来描述 AMS 执行绑定 Service 组件操作的一个 Activity
- // 组件所运行在的应用程序进程
- final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
- ...
- ActivityRecord activity = null;
- if (token != null) {
- // 通过 token 来获得一个 ActivityRecord 对象 activity, 用来描述正在请求 AMS 执行绑定 Service 组件
- // 操作的一个 Activity 组件
- activity = ActivityRecord.isInStackLocked(token);
- if (activity == null) {
- Slog.w(TAG, "Binding with unknown activity:" + token);
- return 0;
- }
- }
- ...
- final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
- // 是否是绑定了外部服务, 这个服务不是应用中的服务, 而是外部独立的服务 (我们通常启动服务都是应用内部的服务)
- final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
- // 根据参数 service 来得到一个 ServiceRecord 对象 s, 用来描述即将被绑定的 Service 组件
ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(),Binder.getCallingUid(), userId, true, callerFg, isBindExternal);
- ...
- // 调用 ServiceRecord 对象 s 的成员函数 retrieveAppBindingLocked 来得到一个 AppBindRecord 对象 b,
- // 表示 ServiceRecord 对象 s 所描述的 Service 组件是绑定在 ProcessRecord 对象 callerApp 所描述的一个
- // 应用程序进程中的
- AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
- // 将前面获得的 APPBindRecord 对象, ActivityRecord 对象 Activity 以及参数 connection 封装成一个
- // ConnectionRecord 对象 s 所描述的一个 Service 组件, 并且这个 Activity 组件是运行在
- // ProcessRecord 对象 callerApp 所描述的一个应用进程中的
ConnectionRecord c = new ConnectionRecord(b, activity,connection, flags, clientLabel, clientIntent);
- // 由于一个 Service 组件可能会被同一个应用程序进程中的多个 Activity 组件使用同一个 InnerConnection
- // 对象来绑定, 因此, 在 AMS 中, 用来描述该 Service 组件的 ServiceRecord 对象就有可能会对应有多个
- // ConnectionRecord 对象. 在这种情况下, 这些 ConnectionRecord 对象就会被保存在一个列表中.
- // 这个列表最终会保存在对应的 ServiceRecord 对象的成员变量 Connection 所描述的 HashMap 中, 并且以
- // 它里面的 ConnectionRecord 对象共同使用的一个 InnerConnection 代理对象的 IBinder 接口为关键字
- // 参数 connection 是一个 InnerConnection 代理对象, 因此可以获取它的一个 IBinder 接口 binder
- IBinder binder = connection.asBinder();
- // 检测在 ServiceRecord 对象 s 中是否存在一个以 IBinder 接口 binder 为关键字的列表 clist, 如果不存在
- // 创建一个, 并且将 clist 以 binder 为关键字放到 ServiceRecord 对象成员变量 connections 中
- 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);// 添加到关联应用和服务的对象 AppBindRecord 中记录绑定列表中
- if (activity != null) {
- if (activity.connections == null) {// 这里判断 Activity 里面是否绑定过服务
- activity.connections = new HashSet<ConnectionRecord>();
- }
- // 添加到描述 Activity 的 ActivityRecord 对象中记录绑定服务的列表中
- activity.connections.add(c);
- }
- ...
- // 从记录该服务所有绑定列表中获取是否存在绑定列表
- clist = mServiceConnections.get(binder);
- if (clist == null) {
- clist = new ArrayList<ConnectionRecord>();
- mServiceConnections.put(binder, clist);
- }
- clist.add(c);// 添加都所有列表中
- // 从前面可知 flags 的 Context.BIND_AUTO_CREATE 位等于 1, 因此会调用 bringUpServiceLocked 来启动
- // ServiceRecord 对象 s 所描述的一个 Service 组件, 等到这个 Service 组件启动以后, AMS 再将它与
- // ActivityRecord 对象 Activity 所描述的一个 Activity 绑定自来
- if ((flags & Context.BIND_AUTO_CREATE) != 0) {
- s.lastActivity = SystemClock.uptimeMillis();
- if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,permissionsReviewRequired) != null) {
- return 0;
- }
- }
- ...
- if (s.app != null && b.intent.received) {
- // Service is already running, so we can immediately
- // publish the connection.
- try {
- // 这里的 c.conn 是 ServiceDispatcher.InnerConnection 对象, 这里最终调用
- // ServiceDispatcher 中的 doConnected 方法
- c.conn.connected(s.name, b.intent.binder);
- } catch (Exception e) {
- Slog.w(TAG, "Failure sending service" + s.shortName
- + "to connection" + c.conn.asBinder()
- + "(in" + c.binding.client.processName + ")", e);
- }
- // If this is the first app connected back to this binding,
- // and the service had previously asked to be told when
- // rebound, then do so.
- if (b.intent.apps.size() == 1 && b.intent.doRebind) {// 重新绑定
- requestServiceBindingLocked(s, b.intent, callerFg, true);
- }
- } else if (!b.intent.requested) {// 首次绑定
- requestServiceBindingLocked(s, b.intent, callerFg, false);
- }
- getServiceMap(s.userId).ensureNotStartingBackground(s);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- return 1;
- }
这里代码比较多, 所以写的注释也比较多, 前面主要是判断是否绑定过该服务, 并对 InnerConnection 进行缓存, 放置到各个列表中, 让 Activity,Service 进行联系. 最后调用 requestServiceBindingLocked 方法, 这个方法调用两次, 一次是首次绑定, 一个是重新绑定.
- Step9.AMS.requestServiceBindingLocked
- // 参数 rebind 表示是否需要将 ServiceRecord 对象 r 所描述的 Service 组件重新绑定到 IntentBindRecord 对象 i
- // 所描述的应用程序进程中如果为 false, 则说明为第一绑定
- private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
boolean execInFg, boolean rebind) throws TransactionTooLargeException {
- ...
- // 检查 AMS 是否已经为 IntentBindRecord 对象 i 所描述的应用程序进程请求过 ServiceRecord 对象 r 所描述的
- // Service 组件返回其内部的一个 Binder 本地对象. 如果还没有请求 requested 为 false 并且 apps 的数量大于 0
- if ((!i.requested || rebind) && i.apps.size()> 0) {
- try {
- bumpServiceExecutingLocked(r, execInFg, "bind");
- r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
- // 会执行到 Service 的 onBind 方法
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
- r.app.repProcState);
- if (!rebind) {
- // 设置为 true, 防止重复请求
- i.requested = true;
- }
- i.hasBound = true;
- i.doRebind = false;
- ...
- }
- return true;
- }
这里是判断首次绑定还是重新绑定, 这两种绑定都会执行绑定步骤, 这里有个参数 i.requested, 代表是否是首次绑定, 如果默认值是 false, 如果不是重新绑定, 那么执行完绑定就会设置为 true. 然后调用 thread.scheduleBindServic 方法, 这个方法讲了很多次了, 最终调用 ApplicationThread.scheduleBindService 方法, 然后通过 handler 调用 ActivityThread.handleBindService 方法.
- Step10.ActivityThread.handleBindService
- private void handleBindService(BindServiceData data) {
- // 通过 token 来获得一个描述 Service 组件的 Service 对象
- Service s = mServices.get(data.token);
- ...
- if (!data.rebind) {// 首次绑定
- // 获取一个实现了 IBinder 接口的 Binder 对象
- IBinder binder = s.onBind(data.intent);
- // 调用 AMS 代理对象的成员函数 publishService, 将前面得到的 Binder 本地对象传递给 AMS
- ActivityManagerNative.getDefault().publishService(
- data.token, data.intent, binder);
- } else {
- s.onRebind(data.intent);
- ActivityManagerNative.getDefault().serviceDoneExecuting(
- data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
- }
- }
这里如果是首次绑定调用 onBind 方法, 否则调用 onRebind 方法, 在首次调用绑定后还有 publishService 方法, 自己看一下, 不在详细分析了. 这样绑定流程就分析完了, 难度不大. 下面我们开分析解绑过程.
Service 解绑流程 - unbindService
首先来看解绑流程时序图:
- Step1.ContextImpl.unbindService
- public void unbindService(ServiceConnection conn) {
- ...
- if (mPackageInfo != null) {
- // 获取将 ServiceConnection 对象 conn 封装成一个实现了 IServiceConnection 接口的 Binder
- // 本地对象 sd(ServiceDispatcher.InnerConnection)
- IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
- getOuterContext(), conn);
- try {
- ActivityManagerNative.getDefault().unbindService(sd);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- } else {
- throw new RuntimeException("Not supported in system context");
- }
- }
IServiceConnection 对象的获取我们前面分析过了, 这里直接过, 然后调用 AMP.unbindService 方法, 最终调用 AMS.unbindService 方法.
- Step3.AMS.unbindService
- public boolean unbindService(IServiceConnection connection) {
- synchronized (this) {
- return mServices.unbindServiceLocked(connection);
- }
- }
这里调用 ActiveServices.unbindServiceLocked 方法.
- Step4.ActiveServices.unbindServiceLocked
- boolean unbindServiceLocked(IServiceConnection connection) {
- IBinder binder = connection.asBinder();
- // 获取缓存中绑定列表
- ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
- ...
- try {
- while (clist.size()> 0) {
- ConnectionRecord r = clist.get(0);
- removeConnectionLocked(r, null, null);
- if (clist.size()> 0 && clist.get(0) == r) {
- // In case it didn't get removed above, do it now.
- Slog.wtf(TAG, "Connection" + r + "not removed for binder" + binder);
- clist.remove(0);
- }
- ....
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- return true;
- }
首先从 AMS 中获取绑定过的列表, 如果存在说明绑定过, 然后调用 removeConnectionLocked 移除连接.
- Step5.ActiveServices.removeConnectionLocked
- void removeConnectionLocked(
ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
- // 获取连接中的 Binder 对象
- IBinder binder = c.conn.asBinder();
- // 获取连接应用, 服务和连接列表的客户端
- AppBindRecord b = c.binding;
- // 获取描述服务的对象
- ServiceRecord s = b.service;
- // 根据 Binder 对象获取服务绑定的连接列表
- ArrayList<ConnectionRecord> clist = s.connections.get(binder);
- if (clist != null) {
- clist.remove(c);// 移除该连接对象
- if (clist.size() == 0) {// 如果列表为空, 移除该列表
- s.connections.remove(binder);
- }
- }
- // 从连接应用, 服务和连接列表的客户端中的连接列表中移除
- b.connections.remove(c);
- ...
- // 从总的缓存列表中移除
- clist = mServiceConnections.get(binder);
- if (clist != null) {
- clist.remove(c);
- if (clist.size() == 0) {
- mServiceConnections.remove(binder);
- }
- }
mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);
- // 如果连接应用, 服务和连接列表的客户端中的连接列表为空了, 说明没有绑定了, 那么移除该客户端
- if (b.connections.size() == 0) {
- b.intent.apps.remove(b.client);
- }
- if (!c.serviceDead) {// 服务还存在
- if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
- && b.intent.hasBound) {
- try {
- ...
- b.intent.doRebind = false;
- s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
- } catch (Exception e) {
- Slog.w(TAG, "Exception when unbinding service" + s.shortName, e);
- serviceProcessGoneLocked(s);
- }
- }
- ...
- }
- }
在绑定服务的时候进行各种缓存, 加入各种列表, 那么在接触绑定的时候就有从之前加入的列表中删除, 然后执行接触绑定.
- Step7.ActivityThread.handleUnbindService
- private void handleUnbindService(BindServiceData data) {
- Service s = mServices.get(data.token);
- if (s != null) {
- try {
- ...
- boolean doRebind = s.onUnbind(data.intent);// 调用解绑回调
- ...
- } catch (Exception e) {
- ...
- }
- }
- }
调用 Service 的 onUnbind 接触绑定. 到这里接触绑定就分析完了, 过程比较简单, 只是上面的各种列表搞清楚要多看看. 最后就剩下了 stopService, 我们一口气就将它分析完.
Service 停止流程 - stopService
首先来看停止服务流程时序图:
- Step1.ContextImpl.stopSevice
- // 停止服务
- @Override
- public boolean stopService(Intent service) {
- warnIfCallingFromSystemProcess();
- return stopServiceCommon(service, mUser);
- }
调用 stopServiceCommon 停止服务.
- Step2.ContextImpl.stopServiceCommon
- private boolean stopServiceCommon(Intent service, UserHandle user) {
- try {
- // 检验 Intent, 组件和包名不能为空
- validateServiceIntent(service);
- service.prepareToLeaveProcess(this);
- int res = ActivityManagerNative.getDefault().stopService(
- mMainThread.getApplicationThread(), service,
- service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
- ...
- return res != 0;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
这里最终调用 AMS 的 stopService 方法.
- Step3.AMS.stopService
- public int stopService(IApplicationThread caller, Intent service,
- String resolvedType, int userId) {
- ...
- synchronized (this) {
- return mServices.stopServiceLocked(caller, service, resolvedType, userId);
- }
- }
这里就是简单的调用 ActiveServices.stopServiceLocked 方法.
- Step4.ActiveServices.stopServiceLocked
- int stopServiceLocked(IApplicationThread caller, Intent service,
- String resolvedType, int userId) {
- // 根据 caller 获取调用者进程
- final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
- ...
- if (r != null) {
- ...
- stopServiceLocked(r.record);
- ...
- return -1;
- }
- return 0;
- }
简单的调用了 stopServiceLocked 方法.
- Step6.ActiveServices.stopServiceLocked
- private void stopServiceLocked(ServiceRecord service) {
- ...
- bringDownServiceIfNeededLocked(service, false, false);
- }
我们前面分析过 bringUp 的是启动服务, 因此对应的 bringDown 的是结束服务.
- Step7.ActiveServices.bringDownServiceIfNeededLocked
- // 停止服务
- private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
- boolean hasConn) {
- ...
- bringDownServiceLocked(r);
- }
这里只是简单的调用了 bringDownServiceLocked 方法, 这个方法我们在服务启动时也遇到过, 只是没有分析, 我们放到了停止服务的流程中来分析, 下面我们看看详细代码.
- Step8.ActiveServices.bringDownServiceLocked
- private 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++) {
- ...
- // 断开服务连接
- cr.conn.connected(r.name, null);
- ...
- }
- }
- // Tell the service that it has been unbound.
- 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 {
- ...
- // 调用 Service 的 onUnbind 方法
- r.app.thread.scheduleUnbindService(r,
- ibr.intent.getIntent());
- } catch (Exception e) {
- ...
- }
- }
- }
- }
- ...
- if (r.app != null) {// 服务进程存在
- ...
- if (r.app.thread != null) {
- updateServiceForegroundLocked(r.app, false);
- try {
- ...
- // 停止服务, 调用 onDestroy 方法
- r.app.thread.scheduleStopService(r);
- } catch (Exception e) {
- ...
- ...
- }
这里主要有三步, 第一步, 断开服务连接, 这个方法我们前面提到过, 可以根据前面提到的去看看如何断开连接的; 第二步, 如果已经绑定了服务要解除绑定, 这个在上面解除绑定的时候分析了该过程, 因此这里就不再重复了; 第三步, 如果服务存在, 则停止服务. 我们开始分析第三步, 第三步这里最终调用 ActivityThread 的 handleStopService 方法.
- Step13.ActivityThread.handleStopService
- private void handleStopService(IBinder token) {
- Service s = mServices.remove(token);
- ...
- s.onDestroy();
- ...
- }
这里如果服务存在则调用服务的 onDestroy 方法, 到这里服务的停止也就结束了. 从上面看服务的整个流程相对于 Activity 简单的多. 很容易就看懂了. 其实还有一个 IntentService, 整个服务继承 Service, 只不过里面多了一个 Handler, 我们看看这段代码:
- private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
- }
- @Override
- public void handleMessage(Message msg) {
- onHandleIntent((Intent)msg.obj);
- stopSelf(msg.arg1);
- }
- }
如果有 Handler 就有发送消息的地方, 那么发送消息在哪里呢, 我们知道当你调用服务的时候会走 onStartCommand 方法:
- public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
- onStart(intent, startId);
- return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
- }
这里会调用 onStart 方法:
- public void onStart(@Nullable Intent intent, int startId) {
- Message msg = mServiceHandler.obtainMessage();
- msg.arg1 = startId;
- msg.obj = intent;
- mServiceHandler.sendMessage(msg);
- }
这里就是发送消息的时候, 消息发出后会由上面的 ServiceHandler 来处理, 我们看到构造函数里传入了一个 Looper, 这个是在 onCreate 方法中初始化的:
- public void onCreate() {
- // TODO: It would be nice to have an option to hold a partial wakelock
- // during processing, and to have a static startService(Context, Intent)
- // method that would launch the service & hand off a wakelock.
- super.onCreate();
- HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
- thread.start();
- mServiceLooper = thread.getLooper();
- mServiceHandler = new ServiceHandler(mServiceLooper);
- }
这里创建了一个 Handler 线程, 并且获取了它的 Looper, 用来循环处理消息, 因此我们知道同时只能处理一个消息, 等前一个消息处理完了才会处理第二个, 以此类推, 因此需要同时处理的不能用这个 Service, 另外在 ServiceHandler 中有个 stopSelf 用来在消息处理完成后停止自己, 因此该服务可以说是用完自动停止, 不会一直粗在, 占用资源.
来源: https://juejin.im/post/5ae33eac6fb9a07aa349febd