@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_increaseCounter:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _result = this.increaseCounter(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
是不是非常清晰易懂,就是根据传过来的数据包来做相应的操作,然后把结果写回数据包,Binder 驱动会来帮我们做好这些数据包的分发工作。而这段代码是运行在 Service 本地进程中的,它可以直接调用实现好的 Stub 类中的相关方法(本例子中是 increaseCounter
方法)。
下面我们趁热打铁再来看一眼 Proxy
类中的 increaseCounter
是怎么实现的:
@Override
public int increaseCounter(int increment) throws RemoteException{
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(increment);
mRemote.transact(Stub.TRANSACTION_increaseCounter, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
正好与 Stub
中的处理能够对应起来,其实这两段代码就是整个 IPC 的核心了,Binder 驱动和 Binder 类在底层帮我们做好了其他一切事情。
休息一下。
下面我们来思考另一件事情,如何判断 Service 运行在同一进程还是不同进程?
我们知道,Service
有一个 onBind
方法,这里面就返回了我们实现好的 Stub
类,而客户端 bind service 时拿到的又是一个 IBinder
对象,我们每次只需要调用 Stub
的 asInterface
静态方法,把这个 IBinder
对象传进去就能拿到 Stub
类或者 Proxy
类了,看起来十分智能!那么这个 asInterface
又蕴藏什么玄机呢?我们来看一眼实现代码:
public static IBackgroundService asInterface(IBinder obj){
if ((obj==null)) {
return null;
}
IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IBackgroundService))) {
return ((IBackgroundService) iin);
}
return new IBackgroundService.Stub.Proxy(obj);
}
是不是有点莫名其妙,queryLocalInterface
是什么鬼?
我们再来看看 queryLocalInterface
的实现:
public IInterface queryLocalInterface(String descriptor) {
if (mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
它判断了一下 descriptor
参数是否与自身 owner
的 descriptor
一致,如果一致就直接返回 owner
,那么 owner
和 descriptor
是在哪被设置的呢,就是在 Stub
的构造函数中被设置的。
于是乎,如果 Service 运行在同一进程,那么客户端拿到的 IBinder
就是 Stub
类,而 Stub
的 queryLocalInterface
又会返回自己;而 Service 运行在单独进程中时,客户端拿到的 IBinder
就是系统提供好的 BinderProxy
,BinderProxy
中的 queryLocalInterface
默认直接返回 null
,根据代码,asInterface
就会构造一个 Proxy
返回给客户端,那么接下来的故事就是上面我们讲过的了。
自己利用 Binder 来进行 IPC
有了上面的基础,其实我们完全不需要 AIDL 了有木有,自己用 Binder
类和 BinderProxy
类就完全可以实现 Service 与客户端的通讯,下面我就速速写一个简单的例子。
Service 中的 onBinder 方法我这样实现:
inder类和
BinderProxy` 类就完全可以实现 Service 与客户端的通讯,下面我就速速写一个简单的例子。
Service 中的 onBinder 方法我这样实现: