lin20080410的专栏

从站在巨人的肩上,向成为巨人迈进... 互相学习!

多个基于AIDL的server,Binder驱动怎么区分它们

一个进程要想提供Binder服务,必须要调用

ProcessState::self()->startThreadPool();

IPCThreadState::self->joinThreadPool();这两个方法,然后整个进程就进入一个Binder loop循环了。

ProcessState负责打开Binder设备节点,做mmap内存映射,,IPCThreadState是负责跟Binder驱动做命令交互的,重点看下IPCThreadState::self->joinThreadPool();方法,

void IPCThreadState::joinThreadPool(boolisMain){

//告知Binder驱动,进入Binder主循环。

         mOut.writeInt32(isMain? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);

         do{

                   //now get the next command to be processed, waiting if necessary

                   result= getAndExecuteCommand();

} while (result!= -ECONNREFUSED && result != -EBADF);

//告知Binder驱动退出Binder循环。

mOut.writeInt32(BC_EXIT_LOOPER);

//参数false,表明不在从Binder驱动读数据。

         talkWithDriver(false);

}

status_t IPCThreadState::getAndExecuteCommand(){

// talkWithDriver的参数默认值是true,这个函数对数据的处理既包括读,也包括写。

         result= talkWithDriver();

//执行cmd

         result= executeCommand(cmd);

}

这样的Binderloop框架在所有需要Binder服务的进程中,基本是一致的。如果同一个进程中,有多个基于AIDLBinderServer时,IPCThreadState是单实例,该怎么来区分他们呢,Binder client发送的请求通过Binder驱动到达Binder server端,那么IPCThreadState是如何把Binder驱动的消息准确投递给对应的BinderServer的?

 

我们看executeCommand是怎么执行的。

status_t IPCThreadState::executeCommand(int32_t cmd){

         switch((uint32_t)cmd) {

// BR_TRANSACTIONBinder驱动向Server端发送请求数据,接收的是请求,

//BC_TRANSACTIONclientBinder驱动发送请求数据,发送的是请求,

//BR_REPLY Binder驱动向Client端发送回复数据,接收的是应答,

//BC_REPLY ServerBinder驱动发送回复数据,发送的是应答,

//这是Binder机制中clientserver端交互最关键的几个命令。

                   case BR_TRANSACTION:{

                            binder_transaction_data tr;

//读取业务请求

                            result= mIn.read(&tr, sizeof(tr));

//分情况,调用transact处理请求

                            if(tr.target.ptr) {

                                     error= reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,

                                     &reply,tr.flags);

}else{

         error =the_context_object->transact(tr.code, buffer, &reply, tr.flags);

}

}

}

}

如果tr.target.ptr不为null,把tr.cookie转换成BBinder,最后调用BBinder->transact来处理请求。所以BBinderserver 跟 IPCThreadState沟通的桥梁。

基于AIDLserver都会生成一个stub内部类,这个stub继承于android.os.Binder,我们看Binder.java的构造函数。

public Binder() {

//这是native函数,对应实现在android_util_Binder.cpp中,这个cpp类中包含了很多java

//类中的native函数实现。

         init();

}

static void android_os_Binder_init(JNIEnv*env, jobject obj){

//这里虽然没有直接看到BBinder,但是从JavaBBinderHolder进去,看到他有一个JavaBBinder

//类型的弱指针:wp<JavaBBinder>mBinder;JavaBBinder继承自BBinder

         JavaBBinderHolder* jbh = new  JavaBBinderHolder();

//JavaBBinderHolder的指针值保存到BindermObject变量中。

         env->SetLongField(obj,gBinderOffsets.mObject, (jlong)jbh);

}

在一个基于AIDLserver创建时,是想要生成BBinder的,但是在创建JavaBBinderHolder对象时并没有生成JavaBBinder对象,那什么时候创建的JavaBBinder对象呢?

当一个BinderServer创建后,会把他注册到ServiceManager中,这时会调用addService方法,实际是通过ServiceManagerProxy调用的addService,它是Servicemanager的代理类,这个类在ServiceManagerNative.java中,

public void addService(String name, IBinder service, boolean allowIsolated){

//这里的ParcelParcel.java

         Parcel data = Parcel.obtain();

//service是一个Ibinder,把这个service写入到parcel中,parcel是进程间传递数据的一个载体,利用parcelBinder对象写入,读取时就能得到原始的Binder对象。

         data.writeStrongBinder(service);

//这里是跨进程的开始。

         mRemote.transact(ADD_SERVICE_TRANSACTION,data, reply, 0);

}

接着看Parcel.javawriteStrongBinder的实现:

public final void writeStrongBinder(IBinder val) {

//只是调用了native层的实现。

         nativeWriteStrongBinder(mNativePtr,val);

}

进入到JNI中的实现android_os_Parcel.cpp

static  void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr,jobject object){

         Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);

//这里的参数object就是那个Java层的Ibinder对象,

         conststatus_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));

}

通过ibinderForJavaObject对这个IBinder进行转化,

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj){

         if(env->IsInstanceOf(obj, gBinderOffsets.mClass)) {

                   JavaBBinderHolder*jbh = (JavaBBinderHolder*)

                            env->GetLongField(obj,gBinderOffsets.mObject);

                   return jbh != NULL ? jbh->get(env, obj) : NULL;

         }

}

前面在Binder的构造函数中,我们把JavaBBinderHolder的指针值保存到gBinderOffsetsmObject变量中,这里通过gBinderOffsets.mObject把它取出来,并转成JavaBBinderHolder,接着调用它的get方法。

class JavaBBinderHolder : public RefBase{

         sp<JavaBBinder>get(JNIEnv* env, jobject obj){

                   sp<JavaBBinder>b = mBinder.promote();

//第一次调用,会New一个JavaBBinder,实际就是一个BBinder

                   if(b == NULL) {

                            b= new JavaBBinder(env, obj);

                            mBinder= b;

}

}

}

接下来就是Parcel.cpp中的方法writeStrongBinder,把JavaBBinder这样一个强指针写入到parcel中。

status_t Parcel::writeStrongBinder(constsp<IBinder>& val){

         return flatten_binder(ProcessState::self(), val, this);

}

这里又把val转成了弱指针,wp<IBinder>& binderwp是一个模板类,在构造一个wp对象时,给其成员m_ptr赋值,

wp<T>::wp(T* other) : m_ptr(other){

         if(other) m_refs = other->createWeak(this);

}

所以这里的m_ptr实际就是BBinder对象。

status_t flatten_binder(constsp<ProcessState>& /*proc*/,

         const wp<IBinder>& binder, Parcel* out){

//这里的cookie记录的就是BBinder对象。

         obj.cookie= reinterpret_cast<uintptr_t>(binder.unsafe_get());

//把这个obj写入到parcel空间的相应位置,这样就把一个Binder对象填充到了Parcel中。

finish_flatten_binder(real,obj, out);

}

 

以上addService的操作都还在client端,后面就会通过mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);进而通过ioctlBinder驱动通信,把请求(数据)发送到servicemanager的服务端。

Binder驱动中,只有有用户带一个Binder对象经过他,就会被记录下来,进而把这一Binder对象相关的binder_node节点加入到当前procnodes树中,也就是说当前proc的所有Binder对象在驱动中都有记录。

相关代码就是Binder.cbinder_transaction函数,

Kernel/drivers/staging/android/Binder.c

static void binder_transaction(structbinder_proc *proc,

         struct binder_thread *thread,

         struct binder_transaction_data *tr, int reply){

         switch(fp->type) {

                   case BINDER_TYPE_BINDER:

                   case BINDER_TYPE_WEAK_BINDER:

                            struct binder_node *node = binder_get_node(proc, fp->binder);

                            node= binder_new_node(proc, fp->binder, fp->cookie);

                            ref= binder_get_ref_for_node(target_proc, node);

}

}

这样就知道BBinder是怎么来的了。

使用AIDL来描述的server,经过工具转化后生成的java文件中,有两个重要的嵌套类,一个是stub,还有一个是Proxy,其中I***.Stub是服务端要继承的类,I***.Stub.Proxy是相应的client,这是java层的Binder服务格式

native层的Binder服务都是手写的,以IGraphicBufferProducer.cpp为例,其中的Bp***,相当于AIDL中的I***.stub.Proxy,而Bn××××相当于AIDL中的I***.Stub,

相应的服务端要继承Bn××××这个类


做个小结:

1)在请求的数据包中binder_transaction_data类性的数据tr,其中的tr.target.ptr通常不会为null,也就是target中指定了目标对象,具体是其中tr.cookie,这是个BBinder类型的。

2)这个BBinder的来源,在一个AIDL的server被创建时,确切的说是在其被添加到serviceManager时,会去生成一个BBinder,具体是由stub的父类android.os.binder的构造过程中实现的,在addService的过程中,肯定是经过Binder驱动的,在Binder驱动的设计中,只要有人带着Binder对象路过他,就会被记录下,存到当前proc的nodes树中,这也是后面client发送的数据可以携带BBinder的来源。

3)BBinder的transact函数,会调用onTransact函数,onTransact函数的重点是调用java层的Binder对象的某个接口,把client的请求传过去,所以服务端都会重写这个onTransact函数,这样就把client的请求传到了Binder(java)了。基于aidl的server,其中的onTransact通常什么都没做,只是调用了super.onTransact函数,这是因为aidl的stub类也重写了onTransact方法,做好了无缝调转,基于aidl的server只要实现业务处理接口就可以,这也是aidl的server编写方便的一个原因。


阅读更多
版权声明:笔记记录,互相学习,不足之处,欢迎指正! https://blog.csdn.net/lin20044140410/article/details/77012361
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭