问题描述
Android开发中,客户端通过Binder向服务端注册 / 去注册 callback,是我们常用的开发方式。了解Binder通信机制的同学应该会知道,我们通过Binder,把callback从客户端发送回调接口到服务端时,服务端获得的,其实是一份反序列化后new出来的IInterface实例。例如以下服务端接收代码:
status_t BnPreviewService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case START_PREVIEW: {
CHECK_INTERFACE(IPreviewService, data, reply);
sp<IGraphicBufferProducer> st =
interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
int channel = data.readInt32();
reply->writeInt32(startPreview(st,channel));
return NO_ERROR;
} break;
通过Binder,服务端接收到客户端发来的序列化打包的Parcel,用于构建一个新的IGraphicBufferProducer实例。
即使重复将同一个callback实例通过Binder发向服务端,服务端都会构建出一个新的IGraphicBufferProducer实例。这时候对比这两个实例,它们指向的地址必然是不同的。
我们为什么能够实现callback的去注册?
google为我们封装了一个管理callback的类:RemoteCallbackList,我们看看它是如何实现callback的注册和去注册的。
//RemoteCallbackList.java
public boolean register(E callback, Object cookie) {
synchronized (mCallbacks) {
if (mKilled) {
return false;
}
// Flag unusual case that could be caused by a leak. b/36778087
logExcessiveCallbacks();
IBinder binder = callback.asBinder();
try {
Callback cb = new Callback(callback, cookie);
binder.linkToDeath(cb, 0);
mCallbacks.put(binder, cb);
return true;
} catch (RemoteException e) {
return false;
}
}
}
最核心的两行:
1,通过IInterface接口的public IBinder asBinder()方法,获取IBinder接口的实例:
IBinder binder = callback.asBinder();
2,存储IBinder实例:
mCallbacks.put(binder, cb);
再看去注册回调的实现:
public boolean unregister(E callback) {
synchronized (mCallbacks) {
Callback cb = mCallbacks.remove(callback.asBinder());
if (cb != null) {
cb.mCallback.asBinder().unlinkToDeath(cb, 0);
return true;
}
return false;
}
}
关键在于下面这句:
Callback cb = mCallbacks.remove(callback.asBinder());
这里就有两个疑问:
1,是如何比较两个IBiner实例是否相同的?
2,IBinder实例为什么能作为Map的key进行正确的比较?
1,asBinder()返回的实例为什么能指向同一个BBinder?
先看注册callback时,从aidl文件自动生成的代码:
@Override public int registerServerCallBack(IMyCallback client) 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.writeStrongBinder((((client!=null))?(client.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_registerServerCallBack, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
可以看到,传递的aidl接口序列化时调用了
Parcel.writeStrongBinder
而Parcel的这个接口,实际上通过JNI调用了Native接口:
public final void writeStrongBinder(IBinder val) {
nativeWriteStrongBinder(mNativePtr, val);
}
跟踪代码:
/frameworks/base/core/jni/android_os_Parcel.cpp
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
{
// 使用Native的Parcel方法进行实际的序列化
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
/frameworks/base/core/jni/android_util_Binder.cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { //mClass指向Java层中的Binder class
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL; //get() 返回一個JavaBBinder,继承自BBinder
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { //mClass 指向Java层的BinderProxy class
return (IBinder*)
env->GetIntField(obj, gBinderProxyOffsets.mObject); //返回一个BpBinder,mObject是它的地址值
}
ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
return NULL;
}
序列化时,IBinder实际是BBinder类。Native的Parcel真正地序列化:
// framework/native/libs/binder/Parcel.cpp
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj;
if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
/* minimum priority for all nodes is nice 0 */
obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
} else {
/* minimum priority for all nodes is MAX_NICE(19) */
obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
}
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
ALOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.hdr.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
// 因为打包时callback属于BBinder,所以local不是null,走这个分支
obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);
}
} else {
obj.hdr.type = BINDER_TYPE_BINDER;
obj.binder = 0;
obj.cookie = 0;
}
return finish_flatten_binder(binder, obj, out);
}
结论:
callback传递时,序列化的过程就是将BBinder的地址放进了Pacel中。
服务端反序列化代码:
case TRANSACTION_registerServerCallBack:
{
data.enforceInterface(descriptor);
IMyCallback _arg0;
_arg0 = IMyCallback.Stub.asInterface(data.readStrongBinder());
int _result = this.registerServerCallBack(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
data.readStrongBinder()其实就是返回了一个指向BBinder地址的IBinder对象。
调用Stub.asInterface后,得到的就是Proxy了。参考以下代码:
public static android.os.IMessenger asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.os.IMessenger))) {
return ((android.os.IMessenger)iin);
}
return new android.os.IMessenger.Stub.Proxy(obj);
}
Proxy会保存BBinder的地址:
private static class Proxy implements android.os.IMessenger
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
所以,属于同一个BBinder的Proxy,通过asBinder方法得到的IBinder对象的地址都是一样的。
2,为什么IBinder实例能作为Map的key进行正确的比较?
我们已经知道,Proxy.asBinder能够获取到IBinder接口对象。这个C++对象,在java端对应的是BinderProxy类。具体可以看反序列化的那段代码。
vfinal class BinderProxy implements IBinder {
// See android_util_Binder.cpp for the native half of this.
private static final class ProxyMap {
/**
* Hash function tailored to native pointers.
* Returns a value < MAIN_INDEX_SIZE.
*/
private static int hash(long arg) {
return ((int) ((arg >> 2) ^ (arg >> (2 + LOG_MAIN_INDEX_SIZE)))) & MAIN_INDEX_MASK;
}
在java层,我们使用IBinder作为Map的Key时,它的Hash值就是来源于此。
网友评论