关闭

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

标签: AIDLIPCThreadStateBpBn
136人阅读 评论(3) 收藏 举报
分类:

一个进程要想使用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_tIPCThreadState::getAndExecuteCommand(){

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

         result= talkWithDriver();

//执行cmd

         result= executeCommand(cmd);

}

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

 

我们看executeCommand是怎么执行的。

status_tIPCThreadState::executeCommand(int32_t cmd){

         switch((uint32_t)cmd) {

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

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

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

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

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

                   caseBR_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来处理请求。所以BBinderserverhe 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, IBinderservice, boolean allowIsolated){

//这里的ParcelParcel.java

         Parceldata = 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(IBinderval) {

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

         nativeWriteStrongBinder(mNativePtr,val);

}

进入到JNI中的实现android_os_Parcel.cpp

static voidandroid_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);

                   returnjbh != 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){

         returnflatten_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*/,

         constwp<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,

         structbinder_thread *thread,

         structbinder_transaction_data *tr, int reply){

         switch(fp->type) {

                   caseBINDER_TYPE_BINDER:

                   caseBINDER_TYPE_WEAK_BINDER:

                            structbinder_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××××这个类


0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

Android基础——Binder连接池连接多个AIDL文件的处理

初学者必知的Binder连接池 事先说明: 本人也是个初学者,所以本文是从初学者的角度入手,如果有不妥的地方请留言教导我,谢谢。 如果对AIDL的使用和Binder机制不懂的,可以参照我...
  • qq_30379689
  • qq_30379689
  • 2016-08-25 10:20
  • 1914

AIDL与Binder的区别

Binder是一个远程对象的基础类,核心部分是远程调用机制,这部分是由IBinder定义的。 它是对IBinder类的实现,其中IBinder类提供了这样一个类的标准的本地化实现方式。 大...
  • sunny_girl_11
  • sunny_girl_11
  • 2015-11-17 11:18
  • 3991

基于顺序搜索的动态分区分配算法

有以下四种算法: 最佳适应法 最坏适应法 首次适应法 下次适应法(循环首次适应法) 1) 首次适应算法(First Fit): 从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空...
  • qq_23930393
  • qq_23930393
  • 2016-09-05 21:20
  • 1413

binder驱动-------之内存映射篇

1:binder内存管理概述 binder一次跨进程通讯,只需要一次拷贝(原因后面会解析),而一般的像socket通讯则需要两次拷贝;参与binder通讯的进程,无论是client还是服务器端,...
  • u011006622
  • u011006622
  • 2018-01-03 15:03
  • 24

Binder驱动服务获取过程

00000000000000000000000
  • haoyun1990
  • haoyun1990
  • 2017-12-18 13:45
  • 10

Android之binder驱动个人学习小结

本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。 欢迎和大家交流。qq:1037701636 email: gzzaigcn2009@163.com,gzzaigcn2012@gmail.com...
  • gzzaigcn
  • gzzaigcn
  • 2012-08-15 16:16
  • 3464

binder驱动-------之内存映射篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 http://blog.csdn.net/xiaojsj111/article/details/31422175 目录...
  • jingxia2008
  • jingxia2008
  • 2016-02-29 10:35
  • 724

对binder驱动的理解

引用上篇文章作者的一幅经典图片描述,记录下读后的一点心得,没有对照源码深入分析,可能有的地方存在误解:     下面结合图1 binder通讯示例的图,总结以下三个过程:server向SMgr注...
  • lizhiguo0532
  • lizhiguo0532
  • 2011-08-14 22:36
  • 2667

binder驱动和内核交互笔记

进程只运行在进程固有的虚拟地址空间, 剩下的1G是内核空间 用户代码和相关库都运行在用户空间的代码区域. 两个进程共享的内核空间  binder driver是通信媒介 ipc由调用服务号,调用函数...
  • JIYILANZHOU
  • JIYILANZHOU
  • 2016-07-15 01:05
  • 2216

binder驱动源码全注释上

本文主要是自己阅读binder驱动时的注释。 大概会先描述下数据结构,然后贴上主要的代码部分。 //描述一个binder对象 struct flat_binder_object { /...
  • u014089131
  • u014089131
  • 2017-06-29 08:42
  • 226
    个人资料
    • 访问:35508次
    • 积分:1686
    • 等级:
    • 排名:千里之外
    • 原创:130篇
    • 转载:38篇
    • 译文:0篇
    • 评论:9条
    最新评论