2.4 C++层传输数据封装
使用ProcessState和IPCThreadState建立好binder运行环境后,后续要做的,就是对发送和接收数据的封装,先从基础接口和类开始:
1:IBinder binder发送和接收基础功能接口,最终要的接口函数是transact,对应数据传输
2:BpBinder 实现IBinder,对应于binder proxy,主要用于binder数据的发送,初始化必须关联对应的binder handle
3:BBinder 实现IBinder,对应native binder,它不同于BpBinder的点是,它定义了onTransact这个虚函数
所以很明显,如果是binder客户端,就要通过拿到要通信service对应binder的handle来初始化BpBinder,反之,如果是binder服务端,那就必须实现BBinder
BpBinder和BBinder都实现了IBinder,它们最大的不同是对transact接口的实现
先看BpBinder::transact
status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { // Once a binder has died, it will never come back to life. if (mAlive) { status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; }
return DEAD_OBJECT; } |
很简单,直接调用IPCThreadState的transact函数,然后传递目标handle和transaction code以及对应的参数。
再看BBinder:: transact
status_t BBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { data.setDataPosition(0);
status_t err = NO_ERROR; switch (code) { case PING_TRANSACTION: reply->writeInt32(pingBinder()); break; default: err = onTransact(code, data, reply, flags); break; }
if (reply != NULL) { reply->setDataPosition(0); }
return err; } |
transact基本没做啥,直接把请求转发到onTransact,看到这里,基本明白了,如果要定义自己的native binder,那肯定要派生自BBinder并实现onTransact
BBinder的transact是在IPCThreadState收到BR_TRANSACTION时被调用的:
if (tr.target.ptr) { sp<BBinder> b((BBinder*)tr.cookie); error = b->transact(tr.code, buffer, &reply, tr.flags); } |
代码在IPCThreadState::executeCommand中,这个函数比较长,就不全部贴出了
Transact code对应各种传输功能,如果要继续简化开发,最好把transact code也隐藏掉,直接定义业务接口给外部使用,由于binder service和binder serviceproxy相关类的封装还是有点区别,这里分开讲解。
Binder Service:
binder service通过多继承同时派生于业务接口和IBinder,接着在实现时将transactcode和各服务接口做关联,但这里会有一个问题,就是无法将两个子接口在对象内地址偏移直接进行转换问题,这个是接口多继承导致的,解决也很简单,就是在各个接口都定义虚函数用以地址转换,然后让binder service去实现:
1) IInterface,服务基础接口,主要定义接口asBinder用于获取IBinder在对象内地址偏移
2) IBinder接口定义queryLocalInterface用于得到IInterface在对象内地址偏移
接着实现模板类BnInterface:
template<typename INTERFACE> class BnInterface : public INTERFACE, public BBinder { public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const;
protected: virtual IBinder* onAsBinder(); }; |
INTERFACE就是我们最终要实现的服务接口,它要派生自IInterface
接着看queryLocalInterface的实现:
template<typename INTERFACE> inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface( const String16& _descriptor) { if (_descriptor == INTERFACE::descriptor) return this; return NULL; } |
descriptor是binder service定义的一个静态变量,主要用于binderservice 接口描述,它的初始化在后续再介绍,接着看onAsBinder:
template<typename INTERFACE> IBinder* BnInterface<INTERFACE>::onAsBinder() { return this; } |
Binder Service Proxy:
Binder service proxy对服务接口和binder proxy则不是通过多继承来实现的,而是通过包含,在构造的时候,直接传入BpBinder对象来初始化内部的remoteIBinder变量,然后通过
onAsBinder拿到其内部的remote IBinder对象。
同样的,它也有一个模板类:
template<typename INTERFACE> class BpInterface : public INTERFACE, public BpRefBase { public: BpInterface(const sp<IBinder>& remote);
protected: virtual IBinder* onAsBinder(); }; |
INTERFACE跟BnInterface一样,对应最终要实现的服务接口,构造必须传入remote BpBinder,否则数据发哪去都不知道,这个proxy就没任何意义
接着看onAsBinder的实现:
template<typename INTERFACE> inline IBinder* BpInterface<INTERFACE>::onAsBinder() { return remote(); } |
通过上面解析,我们可惜清晰的看出,如果拿到BnInterface或者BpInterface的实例,拿到其关联的IBinder数据,很简单,直接调用asBinder()就可以了
将IBinder转换成BnInterface调用queryLocalInterface,如果要转换成BpInterface,直接
new BpInterface,但是对开发人员来说,他拿到一个IBinder对象,还得先判断是nativebinder还是binder proxy,还是不大方便,再封装下吧
Android对应的实现是定义了两个宏,分别是DECLARE_META_INTERFACE(INTERFACE)和
IMPLEMENT_META_INTERFACE(INTERFACE, NAME),对应声明和实现
任何binder service接口类,也就是上面模板的INTERFACE,都必须要添加这两个宏,这个宏主要实现:
1) binder service接口描述名,对应静态变量descriptor
2) 接口描述名获取接口,对应函数getInterfaceDescriptor
3) 接口转换函数,对应函数asInterface
下面是宏张开后的完整代码:
#define DECLARE_META_INTERFACE(INTERFACE) \ static const android::String16 descriptor; \ static android::sp<I##INTERFACE> asInterface( \ const android::sp<android::IBinder>& obj); \ virtual const android::String16& getInterfaceDescriptor() const; \ I##INTERFACE(); \ virtual ~I##INTERFACE(); \
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ const android::String16 I##INTERFACE::descriptor(NAME); \ const android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } \ android::sp<I##INTERFACE> I##INTERFACE::asInterface( \ const android::sp<android::IBinder>& obj) \ { \ android::sp<I##INTERFACE> intr; \ if (obj != NULL) { \ intr = static_cast<I##INTERFACE*>( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == NULL) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \ } \ I##INTERFACE::I##INTERFACE() { } \ I##INTERFACE::~I##INTERFACE() { } \ |
asInterface先用调用IBinder的queryLocalInterface来尝试获取binder service,如果不为空,直接返回,如果为空,说明这个是binder service proxy,直接newBp##INTERFACE,将该IBinder对象传入作为remote binder
接下去,介绍跟我们开发最相关的部分,就是transactioncode的绑定,这部分我就直接拿ICamera这个binder service接口来介绍,为了简洁起见,我只贴出ICamera两个transactioncode的代码
首先,根据业务功能定义transactioncode:
//ICamrea.cpp enum { DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, SET_PREVIEW_TARGET, }; |
Transaction code的值不能随便定义,要基于IBinder::FIRST_CALL_TRANSACTION递增
接着,实现ICamera接口类:
class ICamera: public IInterface {
public: DECLARE_META_INTERFACE(Camera);
virtual void disconnect() = 0; // pass the buffered IGraphicBufferProducer to the camera service virtual status_t setPreviewTarget( const sp<IGraphicBufferProducer>& bufferProducer) = 0; } |
一般transaction code跟虚函数都是一一对应的,还有就是添加
DECLARE_META_INTERFACE(Camera);
接着还要添加宏的实现:
//ICamera.cpp IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera"); |
从这里可以看出,这个接口的描述名为android.hardware.ICamera
接口定义好了,接着就是实现BnCamera类,对应binder service,并实现onTransact函数:
类声明:
class BnCamera: public BnInterface<ICamera> { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; |
对应实现:
status_t BnCamera::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case DISCONNECT: { ALOGV("DISCONNECT"); CHECK_INTERFACE(ICamera, data, reply); disconnect(); reply->writeNoException(); return NO_ERROR; } break; case SET_PREVIEW_TARGET: { ALOGV("SET_PREVIEW_TARGET"); CHECK_INTERFACE(ICamera, data, reply); sp<IGraphicBufferProducer> st = interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); reply->writeInt32(setPreviewTarget(st)); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } |
将DISCONNECT与SET_PREVIEW_TARGET分别与函数disconnect()和setPreviewTarget做绑定
接着看binder service proxy类的实现,对应BpCamera:
class BpCamera: public BpInterface<ICamera> { public: BpCamera(const sp<IBinder>& impl) : BpInterface<ICamera>(impl) { }
// disconnect from camera service void disconnect() { ALOGV("disconnect"); Parcel data, reply; data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); remote()->transact(DISCONNECT, data, &reply); reply.readExceptionCode(); }
// pass the buffered IGraphicBufferProducer to the camera service status_t setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer) { ALOGV("setPreviewTarget"); Parcel data, reply; data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); sp<IBinder> b(bufferProducer->asBinder()); data.writeStrongBinder(b); remote()->transact(SET_PREVIEW_TARGET, data, &reply); return reply.readInt32(); } } |
很简单,将相关参数封装到Parcel中后,调用remote()->transact将数据发送出去。
接下去,把这个binder service注册到service manager中
首先,先初始化service manager对应的binder proxy service:
代码如下:
//通过调用ProcessState:: getStrongProxyForHandle获取service manager对应的BpBinder //service manager的handle固定为0 Sp<IBinder> bpSM = ProcessState::self()->getStrongProxyForHandle(0); //接着将其转换成IServiceManager对应的binder proxy service sp<IServiceManager> servicemanager = IServiceManager::asInterface(bpSM); |
注册代码:
sp<BnCamera> bnCamera = new BnCamera(); sevicemanager->addService(“demoCamera”, bnCamera); |
就这样,我们在service manager添加了一个名叫demoCamera的binder service
客户进程如果要连接这个binderservice,只需要使用如下代码,创建binderservice proxy对象即可:
Sp<IBinder> pp = servicemanager->getService(“demoCamera”); Sp<ICamera> proxyCamera = ICamera::asInterface(pp); |
接着就可以直接通过proxyCamera与binder service进行通信了
So easy!!!
2.5 JAVA(Android)层封装
JAVA层的封装主要分三部分:
1) 定义Binder和BinderProxy两个类,然后通过JNI,跟C++层的BBinder和BpBinder做绑定
2) 使用AIDL接口描述语言和相关解析工具,来封装bindertransaction code的定义和与对应接口函数的绑定
3) 通过Service的onBind接口,将Binder返回给ActivityManagerService统一管理,在有应用申请连接这个Binder服务时,AMS再将Binder服务对应的Binder proxy通过回调传给应用,从而实现通过Intent来找到指定Binder服务
先说第一部分
Binder相关的JNI代码文件android_util_binder.cpp
Java对象跟C++对象数据进行绑定的基本都是通过在Java类定义一个long类型的变量,然后在jni调用c++代码时,将创建的C++对象地址保存到Java对象的这个long类型变量中。
接着在Java类定义native函数,然后通过JNI跟C++的函数做一一绑定
除了上面说的这些以外,Java端的Binder和BinderProxy和C++层的BBinder和BpBinder还有两个问题需要解决:
1) BBinder的收到onTransact事件后,如何回调到java Binder?
2) 如何将基于Parcel.java的binder数据反序列化成Java Binder或BinderProxy对象
第一个问题,Android在C++层定义了一个派生自BBinder的类JavaBBinder来解决:
class JavaBBinder : public BBinder |
如何在JavaBBinder::onTransact时回调Java对象的onTransact函数:
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags); |
第二个问题直接看Parcel.java的jni映射函数看其怎么反序列binder对象就可以了,
JavaParcel类对应的jni代码文件为 android_os_parcel.cpp
Parcel反序列化binder函数为readStringBinder,对应jni代码:
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr) { Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); if (parcel != NULL) { return javaObjectForIBinder(env, parcel->readStrongBinder()); } return NULL; } |
通过parcel->readStrongBinder()反序列后,得到对应的BBinder或BpBinder对象,接着传给
javaObjectForIBinder
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) { if (val == NULL) return NULL;
if (val->checkSubclass(&gBinderOffsets)) { // One of our own! jobject object = static_cast<JavaBBinder*>(val.get())->object(); LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object); return object; }
// For the rest of the function we will hold this lock, to serialize // looking/creation of Java proxies for native Binder proxies. AutoMutex _l(mProxyLock);
// Someone else's... do we know about it? jobject object = (jobject)val->findObject(&gBinderProxyOffsets); if (object != NULL) { jobject res = jniGetReferent(env, object); if (res != NULL) { ALOGV("objectForBinder %p: found existing %p!\n", val.get(), res); return res; } LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get()); android_atomic_dec(&gNumProxyRefs); val->detachObject(&gBinderProxyOffsets); env->DeleteGlobalRef(object); }
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); if (object != NULL) { LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object); // The proxy holds a reference to the native object. env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get()); val->incStrong((void*)javaObjectForIBinder);
// The native object needs to hold a weak reference back to the // proxy, so we can retrieve the same proxy if it is still active. jobject refObject = env->NewGlobalRef( env->GetObjectField(object, gBinderProxyOffsets.mSelf)); val->attachObject(&gBinderProxyOffsets, refObject, jnienv_to_javavm(env), proxy_cleanup);
// Also remember the death recipients registered on this proxy sp<DeathRecipientList> drl = new DeathRecipientList; drl->incStrong((void*)javaObjectForIBinder); env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
// Note that a new object reference has been created. android_atomic_inc(&gNumProxyRefs); incRefsCreated(env); }
return object; } |
先通过checkSubClass来判断这个Binder是否是JavaBBinder对象,如果是,说明是nativebinder,直接静态强转成JavaBBinder类型,然后调用object拿到对应的java Binder对象,否则,通过env->newObject来创建JavaBinderProxy对象
接着将其返回给Java层
接着说第二部分
其实C++层将binder transactioncode和自定义功能接口函数的绑定这块封装的已经比较方便了,不过如果我们回过头来看看绑定相关代码,其实会发现,这些代码都非常标准化,都有两个Parcel对象用来保存输入和返回数据,还有就是将每一个定义的transaction code和某函数调用一一对应起来,既然这么标准化,那能不能让这块代码自动生成,我们只需要写一个接口,把所有的函数名,以及函数对应的输入和返回数据类型描述清楚就好了
android就是这么做的:
1)使用AIDL语言描述binder传输接口信息,并保存到.aidl文
2)使用AIDL语言解析工具,将.aidl文件内容解析后,生成对应的.java文件,这个java文件会自动生成transaction code列表,然后实现派生自Binder的Stub类做binder service,还有实现派生自BinderProxy的Proxy类作为binder service proxy,这两个类内部实现的代码跟C++类似,这里就不再介绍
最后说第三部分
通过第二部分AIDL相关描述,我们知道通过定义AIDL文件,就可以自动生成Stub类做binder service,那如何将这个binder service添加到binder kernel呢?
之前说过可以通过servicemanager,但是servicemanager.addService对普通的android app来说是没有权限的
Android采用的方法是,可以在Service的onBind函数返回Stub类对应的binder service,然后用startService启动这个service后,ActivityThread在调用pushService将其push到ActivityManagerService之前,会调用service.onBinder获取这个binderservice,接着作为pushService的参数传到ActivityManagerService,由于ActivityThread和ActivityManagerService之间就是基于Binder进行通信的,还记得上面说的吗?Native binder化身数据流在binder传过,最终反序列化后拿到的就是对应的handle(binder proxy),然后ActivityManagerService将这个binderproxy相关数据保存到ServiceRecord的bindings列表中。
接下去,app就可以通过context.bindService,传入ServiceConnection,如果绑定成功,则会将对应的binderproxy回调回来,大体的流程是这样的:
1)ContextImpl.bindService回调用LoadedApk的成员函数getServiceDispatcher并传入
Serviceconnection对象
2)getServiceDispatcher会创建ServiceDispatcher来跟ServiceConnection绑定, 在
ServiceDispatche内部会创建类型为IServiceConnection.Stub的binder service
3)接着调用AMS的bindService,将IServiceConnection对应的binderservice和intent等数
据传到AMS
4)AMS收到bindService后,首先会根据Intent从对应ServiceRecord的bindings列表中拿到 对应的binder proxy(对应Service.onBind),然后保存到创建connectionRecord中,接着添加到 ServiceRecord的connections这个Map中,map的key为binder,value为connectionRecord列表
5)接着再回调IServiceConnection.Connected将binder proxy(对应Service.onBind)传到第2条中的ServiceDispatcher中,然后ServiceDispatcher再将其回调给ServiceConnection,ServiceConnection.onServiceConnected再通过对应接口的.asInterface将IBinder 转换后,就可以使用了。
上面只是一个简单的介绍,详细代码就不贴了,大家可自行看源码。