返回

Binder 解析之 getService() 理解(五)

Android

引言

在上一篇文章中,我们从服务端角度剖析了 addService() 方法,深入了解了服务端如何注册并发布服务。本篇文章,我们将从客户端角度继续探索 Binder 机制的奥秘,重点分析 getService() 方法,揭示客户端如何获取服务端代理对象,从而实现跨进程通信。

客户端视角下的 getService()

getService() 方法是客户端获取服务端代理对象的关键入口,它位于 android.os.IServiceManager 接口中。当客户端需要访问某个服务时,它会调用 getService() 方法,向 ServiceManager 服务传递服务名称。ServiceManager 服务收到请求后,会根据服务名称查找对应的服务代理对象,并将其返回给客户端。

服务代理对象的本质

服务代理对象是客户端与服务端通信的桥梁,它是一个位于客户端进程中的 Stub 类。Stub 类继承自 IBinder 接口,并实现了服务端接口中的所有方法。当客户端调用服务代理对象的方法时,实际上是通过 Binder 机制将方法调用和参数传递到服务端。

getService() 方法的实现

getService() 方法的实现相对简单,如下所示:

public IBinder getService(String name) {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.DESCRIPTOR);
    data.writeString(name);
    mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
    return reply.readStrongBinder();
}
  1. 获取 Parcel 对象: 首先,getService() 方法获取两个 Parcel 对象,data 用于存储请求数据,reply 用于存储响应数据。
  2. 写入接口符: data 中写入接口符 IServiceManager.DESCRIPTOR,表明请求来自 IServiceManager 接口。
  3. 写入服务名称: data 中写入服务名称,标识客户端要获取的具体服务。
  4. 发送请求: mRemote 是一个跨进程代理对象,代表 ServiceManager 服务。getService() 方法通过 mRemote 将 data 发送到服务端。
  5. 接收响应: 服务端处理请求后,将响应数据写入 reply。
  6. 读取 Binder 对象: 最后,getService() 方法从 reply 中读取 Binder 对象,该对象即为服务代理对象。

使用服务代理对象

获取到服务代理对象后,客户端就可以像调用本地对象一样调用服务代理对象的方法。实际上,这些方法调用会被 Binder 机制转换成跨进程调用,传递到服务端执行。服务端执行完成后,结果会通过 Binder 机制返回给客户端。

示例代码

下面是一个使用 getService() 方法获取服务代理对象的示例代码:

// 获取 ActivityManager 服务
IActivityManager activityManager = IActivityManager.Stub.asInterface(
    ServiceManager.getService("activity"));

// 调用服务方法
List<RunningTaskInfo> runningTasks = activityManager.getRunningTasks(5);

总结

通过getService() 方法,客户端可以获取服务端代理对象,从而与服务端进行跨进程通信。Binder 机制将方法调用和参数透明地传递到服务端,客户端无须感知跨进程通信的复杂性,大大简化了进程间通信的开发。