该系列文章总纲链接:专题分纲目录 android 系统核心机制 binder
本章关键点总结 & 说明:
这里关注 Binder Java 实现中TestClient分析,主要是 获取服务和使用服务流程,而事实上这些流程在TestServer端添加服务时均有相关的分析,因此该部分 相对来说较为简单。
TestClient源码如下:
import android.util.Slog;
import android.os.ServiceManager;
import android.os.IBinder;
/* test_client <hello> [name] */
public class TestClient {
private static final String TAG = "TestClient";
public static void main(String args[])
{
if (args.length == 0)
{
System.out.println("Usage: need parameter: <hello> [name]");
return;
}
if (args[0].equals("hello"))
{
//关键点1:获取hello服务的句柄 IBinder
IBinder binder = ServiceManager.getService("hello");//getService
if (binder == null)
{
Slog.i(TAG, "can not get hello service");
return;
}
//关键点2:通过binder句柄 获取hello服务客户端
IHelloService svr = IHelloService.Stub.asInterface(binder);
if (args.length == 1)
{
try {
svr.sayhello();//关键点3:客户端发送请求流程
System.out.println("call sayhello");
Slog.i(TAG, "call sayhello");
} catch (Exception e) {}
}
else
{
try {
int cnt = svr.sayhello_to(args[1]);
System.out.println("call sayhello_to "+args[1]+" : cnt = "+cnt);
Slog.i(TAG, "call sayhello_to "+args[1]+" : cnt = "+cnt);
} catch (Exception e) {
System.out.println("call sayhello_to , err :"+e);
Slog.i(TAG, "call sayhello_to , err : "+e);
}
}
}
}
}
1 获取服务的binder引用
首先关注如何获取服务,代码实现如下:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
接下里 这个过程有没有很熟悉,实际上和添加服务类似,实际上与服务添加流程类似,getIServiceManager()分析完毕,即得到了一个ServiceManagerProxy(BinderProxy(0));接下来 分析ServiceManagerProxy的getService函数,其代码如下:
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
//mRemote实际上就是BinderProxy对象,调用它的transact,将封装好的请求数据发送出去
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
这里也与 服务添加流程分析一致,获取服务和添加服务相比,仅仅是发送的数据不同罢了,原理是一致的。
2 IHelloService.Stub.asInterface(binder);
asinterface的实现是在上一篇文章 TestServer的分析中,如下所示:
public static IHelloService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof IHelloService))) {
return ((IHelloService)iin);
}
return new IHelloService.Stub.Proxy(obj);
}
上面代码和Native层interface_cast非常类似,也和之前分析的ServiceManagerProxy类似,都是以一个BpProxy对象为参数构造和业务相关的IHelloService.Stub.Proxy。 它的各个业务函数会将相应请求打包后交给BpProxy对象,最终由BpProxy对象发送给Binder驱动以完成一次通信。
3 svr.sayhello();客户端发送请求流程,使用服务
这里客户端开始走代理流程,根据之前 在binder java层 实现的框架中有:
private static class Proxy implements IHelloService
{
private android.os.IBinder mRemote;
//...
@Override public void sayhello() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_sayhello, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public int sayhello_to(java.lang.String name) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
mRemote.transact(Stub.TRANSACTION_sayhello_to, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
这里最关键的语句便是 mRemote.transact(Stub.TRANSACTION_sayhello, _data, _reply, 0);这也是如服务端分析,走native层,最后再调用binder C++层的 IPCThreadState的transact函数,与binder驱动层交互。
4 总结
对于binder java层 客户端的分析,多数分析关键点已经在服务端的分析中解决了,因此binder java层客户端分析相对较为简单。