对应用开发者而言,bindService调用肯定是耳熟能详,本文将介绍framework如何表示和组织绑定关系,通过背后原理的分析来加深对Service的理解,除此之外,大家也能领略到框架代码是如何设计并带来一些启发。本文旨在理清主要的设计思路,并不会对所有细节展开描述,代码来自Android N。
bindService基本点
让我们回顾下bindService相关的知识点,这里以在Activity中调用bindService函数为例,函数原型如下:
public boolean bindService(Intent service, ServiceConnection conn,
int flags)
指定目标Service的Intent,当目标Service的onBind()方法执行后,传进来的ServiceConnection接口就会得到回调,之前Service.onBind()返回的IBinder对象会作为参数传进来。从这个过程可以看到,系统要管理Service以及Service的使用方,维护它们之间的关系并在合适的时机执行某些回调。
bindService的最终实现在ContextImpl.java中,经过一系列处理调用到AMS.bindService方法,函数原型如下:
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags, String callingPackage,
int userId)
ContextImpl封装了很多信息,很容易就可以拿到诸如调用方进程的标识(IApplicationThread),以及调用方Activity的标识(token),这些信息是维护Service绑定关系的一部分材料,后面会再提到。
这里主要提下IServiceConnection参数,看命名好像跟ServiceConnection有关,但ServiceConnection是普通的接口,而IServiceConnection是Binder接口,应该有着某种映射关系,做为Service绑定的一个重要标识,有必要认清这个映射关系。
LoadedApk.java中的如下成员维护了该映射关系:
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
LoadedApk.ServiceDispatcher封装了ServiceConnection并包含一个IServiceConnection,可以认为LoadedApk.ServiceDispatcher和IServiceConnection是一对一的关系,Binder代理端通过调用IServiceConnection的接口,找到对应的ServiceConnection。
即:指定一个Context和ServiceConnection,有且只有一个IServiceConnection与之对应。
也就意味着,在不同的Activity中用同一个ServiceConnection调用bindService,最后传给AMS的是不同的IServiceConnection。其它推论可自行推导。
绑定关系的表示:ConnectionRecord
先了解下AMS中几个类的含义,这在后面的内容中要用到:
- ServiceRecord:表示一个Service
- ActivityRecord:表示一个Activity
- ProcessRecord:表示一个应用进程
绑定关系至少包含如下信息:
- 发起绑定的Intent
- 绑定到哪个Service(ServiceRecord)
- 哪个应用进程发起的绑定(ProcessRecord)
- 哪个Activity发起的绑定(ActivityRecord)
- 对应的IServiceConnection
- flags或其它附加信息
ConnectionRecord用来表示绑定关系,即每次调用bindService都会生成该类对象,接下来讨论它是如何包含上述信息。
先看下它的成员变量:
/**
* Description of a single binding to a service.
*/
final class ConnectionRecord {
final AppBindRecord binding; // The application/service binding.
final ActivityRecord activity; // If non-null, the owning activity.
final IServiceConnection conn; // The client connection.
final int flags; // Binding options.
final int clientLabel;