关于Binder的设计思想与Driver层实现细节可以看这个:Android Binder设计与实现 - 设计篇,这里首先简要概括一下。

Service的每个Binder实体位于Service所属的进程种中,Binder实体在驱动中被表示为binder_node,并通过成员refs指向了驱动中所有对这个Binder实体的引用,Binder引用在驱动被表示为binder_ref,并通过成员node指向所引用的Binder实体。

每个使用Binder的进程都会在它的ProcessState的构造函数中打开Binder设备,当打开Binder设置时会调用驱动的binder_open,在binder_open中,会为使用Binder的进程创建一个binde_proc节点,binder_proc的成员nodes索引了这个进程创建的所有Binder实体,refs_by_desc与refs_by_node则是分别以这个进程引用的Binder实体的引用号与引用的实体在内核中的内在地址为索引构建的红黑树。这样每个进程都可以通过自己的binder_proc节点检索到所有自己创建的Binder实体与所有对其他Binder实体的引用。

匿名Binder要通过实名Binder传递,而实名Binder要向ServiceManager注册。所以首先一定要有进程通过调用ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0)成为ServiceManager,当有进程申请成为ServiceManager时,驱动就通过binder_new_node建立内核中的第一个binder_node节点。

数据在驱动中以binder_transaction_date结构传输,binder_transaction_data的成员ptr.buffer指向要发送的数据的内存地址,在进程间也可以传送Binder实体或引用,比如发送匿名Binder,当Binder实体或引用在数据中传输时,就需要一个方法将Binder实体或引用在数据中的位置指出来,ptr.offsets就指向Binder偏移数组,offsets_size指明了Binder偏移数组的大小,通过这两个成员驱动就可以找到传输的数据中的所有Binder实体或引用。Binder实体或引用在传递时被表示为flat_binder_object,flat_binder_object的type域表示传输的Binder的类型,TYPE_BINDER_(WEAK)_TYPE表示传输的是Binder实体,TYPE_BINDER_(WEAK)_HANDLE表示的是Binder引用,BINDER_TYPE_FD表示文件Binder。

Client要向Service发送请求,一定要获得对Service的Binder实体的引用,Client向Service发送请求时,以引用号指明要向哪个Service发送请求,引用号0表示向ServiceManager发送请求。

一般情况下,如果Client要向某一Service进行一个请求,首先会通过向引用号为0的Binder引用发送GET_SERVICE请求获得自己需要的Service在的引用,然后再向这个引用即这个引用对应的Service发送请求。

驱动会将所有发送到引用号为0的请求转发至ServiceManager,当一个进程向0号引用即ServiceManager请求某一个Service时,ServiceManager会检测一个表查找Client请求的Service是否已向自己注册,当Binder实体向ServiceManager注册时,ServiceManager会将Binder实体的名字与引用存入一个查找表中,如果已经注册,就将Service所注册的Binder引用返回给请求的进程。

当ServiceManager将某一进程请求的Service的Binder引用发送给这一进程时,由于传送的是引用,所以flat_binder_object的type的值是TYPE_BINDER_(WEAK)_HANDLE,驱动通过binder_transaction_date的ptr.offsets和offsets_size知道了返回数据中包含Binder实体或引用,然后通过这两个成员找出数据中的Binder实体或引用,通过flat_binder_object的type成员知道了返回数据中包含的是Binder引用,然后新建一个对Service的Binder实体的引用并同时保存到Binder实体在驱动中的节点binder_node的refs成员与Client进程的binder_proc中。

Client得到了Service的引用就可以以这个引用向Service发送请求了,数据包是binder_transaction_date结构体,其成员target是一个联合,target.handle表示Client对Service的引用号,target.ptr表示Binder实体在Service进程中的内存地址,当Client向Service发送请求时填充target.handle域,驱动根据Client所属的binder_proc节点与引用号handle获得Client对Service的Binder实体的引用binder_ref,然后通过binder_ref的node成员获得Service的Binder实体在内核中的节点binder_node,然后将Client的请求添加到Service进程的等待队列或Service进程某一线程的等待队列,Service就可以处理Client的请求了。

接下来看下Native层对Binder的使用。

Binder被实现为一个字符设备,应用程序通过ioctl调用与Binder驱动程序进行通信。首先看实现一个ServiceDemo涉及到的类结构关系。

RefBase是Android实现指针管理的类,牵扯到引用计数的都继承自这个类,然后通过sp,wp实现强引用计数与弱引用计数的管理。

Binder使用Client-Server的通信方式,要实现一个Server,需要先定义一套接口,Client与Server同时实现这套接口,Server端完成实际的功能,Client端只是对Server端功能调用的封装,由于这套接口需要跨进程调用,需要对所有接口一一编号,Server端根据接口编号决定调用什么函数。在上图中对接口的定义就是IServiceDemo。

要实现进程间通信,首先需要定义通信的协议,然后向应用程序提供通信的接口,Binder Driver定义了通信协议,IBinder,BpBinder,BBinder承担了通信接口的工作,IBinder定义了通信的接口,BpBinder是Client访问服务端的代理对象,负责打开Binder设备并与Binder设备通信,BBinder作为服务端与Binder设备通信的接口。Client通过BpBinder连接Binder Driver,然后Binder Driver通过BBinder与Server通信,从而完成进程间通信。

IServiceDemo定义了Client与Server通信的接口,需要Client与Server同时实现,我们已经知道,Client通过BpBinder与Server的BBinder进行通信,那么Client端怎么得到BpBinder,Server端怎么得到BBinder呢?从上图可以看到,IServiceDemo继承自IInterface,其实IInterface就定义了一个方法asBinder,返回一个IBinder对象的指针,应该是通过这个方法获得BpBinder与BBinder对象了。看asBinder实现可以知道,asBinder直接调用了onAsBinder,onAsBinder是一个虚方法,所以是调用子类的具体实现。我们发现,IInterface有两个子类BpInterface与BnInterface,在这两个类中都实现了onAsBinder,在BpInterface中,onAsBinder返回了remote(),remote()其实是返回一个BpBinder对象,后面会看到。在BnInterface中,onAsBinder直接返回this指针,而BnInterface继承自BBinder,所以BnInterface的onAsBinder返回了一个BBinder对象,BpBinder与BBinder都有了,Client就可以与Server通信了。

前面说到remote()返回一个BpBinder对象,那么这个对象是如何返回的呢?从上图看到,BnInterface是继承自BBinder的,但是BpInterface并没有继承自BpBinder,但是我们发现,BpInterface的构造函数接收一个IBinder类型的参数,我们看一下BpInterface的构造函数:

template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
: BpRefBase(remote)
{

BpInterface继承自BpRefBase,在BpInterface的初始化列表中调用了父类BpRefBase的构造函数,将IBinder remote传了过去。再看BpRefBase的构造函数:

BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(NULL), mState()
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK); if (mRemote) {
mRemote->incStrong(this); // Removed on first IncStrong().
mRefs = mRemote->createWeak(this); // Held for our entire lifetime.
}
}

直接将BpInterface传过来的IBinder remote保存到了成员mRemote中,而remote()函数就直接返回了这个mRemote对象。

通过BpInterface的构造函数保存了BpBinder对象,那么BpInterface的构造函数是什么时候调用的,而作为构造函数参数传递进去的BpBinder又是什么时候构造的?以ServiceManager为例,实名Binder需要通过addService向ServiceManager注册,这也是进程间通信,那么我们就需要获得ServiceManager的BpBinder,即BpInterface的子类BpServiceManager对象,来看一下BpServiceManager的获取方法:

sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager; {
AutoMutex _l(gDefaultServiceManagerLock);
if (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
}
} return gDefaultServiceManager;
}

单例模式,看以上代码的红色部分,ProcessState代表进程对象,每个进程只有一个,在ProcessState::self()中通过单例模式返回每个进程的ProcessState的唯一实例,在ProcessState的函数函数中通过open调用打开了Binder设备,并通过mmap建立了内存映射。open引起binder driver中的binder_open被调用,binder_open中新建binder_proc节点,初始化todo队列与wait队列,并将binder_proc节点保存在binder_open第二个参数struct file *flip的flip->private_data中及binder_procs中。

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller)
{
return getStrongProxyForHandle();
} sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result; AutoMutex _l(mLock); handle_entry* e = lookupHandleLocked(handle); if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
} return result;
}

handle是0,lookupHandleLocked的返回结果会是NULL,所以会执行红色部分新建一个BpBinder,defaultServiceManager中红色部分可以简化为:

gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder());

BpBinder有了,我们在前面也知道了BpBinder会做为参数传递给BpInterface的构造函数,那么BpInterface的构造函数是什么时候调用的?从以上代码看,应该是interface_cast了,将参数BpBinder转化为了BpInterface的子类BpServiceManager,再来看interface_cast的实现。

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}

INTERFACE即为IServiceManager,继承自IInterface的类都会声明DELCARE_META_INTERFACE与IMPLEMENT_META_INTERFACE,看一下IMPLEMENT_META_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() { }

在IMPLEMENT_META_INTERFACE宏中实现了asInterface,上述红色代码中,obj即传进来的BpBinder(0),最上面的图的注释中说了BpBinder的queryLocalInterface返回NULL,所以会执行蓝色代码,INTERFACE是Servicemanager,所以会新建一个BpServiceManager对象。BpServiceManager对象有了,对过其asBinder方法返回的BpBinder对象就可以与Server进行通信了。

Client有了代理对像BpInterface,那么怎么通过这个代理对象与Server进行通信呢?标准方法是下面这样:

remote()->transact(SET_MASTER_VOLUME, data/*parcel*/, &reply/*parcel*/);

前面已经说了,Client通过BpBinder经由Binder驱动、BBinder与Server端通信,从这里看确实是这样,remote()返回BpBinder对象,调用BpBinder的transact来与Server通信,transact是定义在IBinder中的,BpBinder与BBinder都实现了这个方法。

在BpBinder::transact的实现中,直接调用了IPCThreadState::transact,前面说过ProcessState代表进程对象,每个进程有一个,在ProcessState的构造函数会打与Binder设备并进行mmap,而这里的IPCThreadState就表示线程对象,使用LTS(Local Thread Storage)每个线程有一个IPCThreadState对象,Binder通信是线程与线程的通信,这里我们能通过IPCThreadState::transact与Server端进行通信。

IPCThreasState::transact方法首先调用writeTransactionDate将请求数据封装进binder_transaction_data结构并写入Parcel mOut中。然后调用waitForResponse。

waitForResponse会调用talkWithDriver,talkWithDriver通过ioctl(driverFD,BINDER_WIRTE_READ,&binder_write_read)与Binder驱动进行通信,当Server处理完请求后talkWithDriver成功返回,然后waitForResponse中读取Binder Driver返回的指令并执行相应的动作。

在Server中,binder thread的joinThreadPool中会调用taklWithDriver等待Client请求,当有请求到来时talkWithDriver返回,读取command,调用executeCommand处理请求。在executeCommand中调用BBinder的transact处理请求,BBinder::transact会调用虚方法onTransact来完成具体功能,具体实现就是BnServiceManager::onTransact或BnServiceDemo::onTransact等等。一般会有一个类继承自BnXXXXX完成具体功能,在BnXXXXX的onTransact中会调用完成相应功能的接口,由于是虚方法,就会调用到具体实现类。

注册上下文管理者--ServiceManager

通过 ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); 一个进程可以注册成为上下文件管理者,在ServiceManager就是执行这条ioctl请求。

ioctl调用会执行Binder Driver的binder_ioctl函数,binder_ioctl根据第二个参数cmd执行相应的同作,看下BINDER_SET_CONTEXT_MGR对应的处理:

case BINDER_SET_CONTEXT_MGR:
if (binder_context_mgr_node != NULL) {
printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
goto err;
}
if (binder_context_mgr_uid != -) {
if (binder_context_mgr_uid != current->cred->euid) {
printk(KERN_ERR "binder: BINDER_SET_"
"CONTEXT_MGR bad uid %d != %d\n",
current->cred->euid,
binder_context_mgr_uid);
ret = -EPERM;
goto err;
}
} else
binder_context_mgr_uid = current->cred->euid;
binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
if (binder_context_mgr_node == NULL) {
ret = -ENOMEM;
goto err;
}
binder_context_mgr_node->local_weak_refs++;
binder_context_mgr_node->local_strong_refs++;
binder_context_mgr_node->has_strong_ref = ;
binder_context_mgr_node->has_weak_ref = ;
break;

很简单,就是通过binder_new_node获取到一个binder_node保存到全局变量binder_context_mgr_node中,同时保存了UID,只能有一个context_manager。

Binder In Native的更多相关文章

  1. Binder的Native实现libbinder

    libbinder – Binder的Native实现 出于性能和代码统一性的角度考虑,Binder IPC并不Java和Native环境里各实现一次,而只是分别在不同的执行环境里提供使用的接口.使用 ...

  2. Binder机制,从Java到C (6. Binder in Native : libbinder)

    1.Java和C++中的Binder 从前一篇 Binder机制,从Java到C (5. IBinder对象传递形式) 中可以看到,使用Binder的Java代码,到最后都会进入到Native环境,将 ...

  3. Binder in Java

    Android在Native层实现了进程间的Binder通信,但是上层应用程序的开发及Framework的实现都是Java,用Java层再实现一次肯定是不合理的,Java可以通过JNI调用Native ...

  4. Binder机制,从Java到C (大纲)

    转载请标注:张小燕:http://www.cnblogs.com/zhangxinyan/p/3487381.html 前段时间一直在看有关Binder机制的内容,觉得受益匪浅,整理记录于此,大家请随 ...

  5. IPC 之 Binder 初识

    概述 最近在看Android 的 IPC 机制,想要系统的研究一下,然后就走到了 Binder 这里,发现这个东西真是复杂,查看了一下些文章想要记录下.想要自己写但是发现一篇文章已经写的非常好了,就转 ...

  6. Android Native IPC 方案支持情况

    Binder - 不支持Native层的binder 内存共享 - 不支持 信号量(信号灯) - 不支持 消息队列 - 不支持 信号 - 支持,但是不能用sigqueue传消息,只能用来安装信号,可以 ...

  7. 《深入理解Android 卷III》第二章 深入理解Java Binder和MessageQueue

    <深入理解Android 卷III>即将公布.作者是张大伟.此书填补了深入理解Android Framework卷中的一个主要空白,即Android Framework中和UI相关的部分. ...

  8. 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制【转】

    本文转载自:https://blog.csdn.net/freekiteyu/article/details/70082302 Android-Binder进程间通讯机制 概述 最近在学习Binder ...

  9. Binder进程与线程ProcessState以及IPCThreadState

    ProcessState以及IPCThreadState ProcessState是负责打开Binder节点并做mmap映射,IPCThreadState是负责与Binder驱动进行具体的命令交互. ...

随机推荐

  1. junit4进行单元测试

    一.前言 提供服务的时候,为了保证服务的正确性,有时候需要编写测试类验证其正确性和可用性.以前的做法都是自己简单写一个控制层,然后在控制层里调用服务并测试,这样做虽然能够达到测试的目的,但是太不专业了 ...

  2. Visual Studio 2012远程调试中遇到的问题

    有的时候开发环境没问题的代码在生产环境中会某些开发环境无法重现的问题,或者需要对生产环境代码进行远程调试该怎么办? Vs已经提供给开发者远程调试的工具 下面简单讲讲该怎么用,前期准备:1.本地登录账户 ...

  3. Spring之初体验

                                     Spring之初体验 Spring是一个轻量级的Java Web开发框架,以IoC(Inverse of Control 控制反转)和 ...

  4. ASP.NET SignaiR 实现消息的即时推送,并使用Push.js实现通知

    一.使用背景 1. SignalR是什么? ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指 ...

  5. python 数据类型 ---文件一

    1.文件的操作流程: 打开(open), 操作(read,write), 关闭(close) 下面分别用三种方式打开文件,r,w,a 模式 . "a"模式将不会覆盖原来的文件内容, ...

  6. 信息安全-1:python之playfair密码算法详解[原创]

    转发注明出处: http://www.cnblogs.com/0zcl/p/6105825.html 一.基本概念 古典密码是基于字符替换的密码.加密技术有:Caesar(恺撒)密码.Vigenere ...

  7. Jquery 获得当前标签的名称和标签属性

    得到标签的名称 $("#name").prop("tagName"); 或者 $("#name")[0].tagName; 注意:1.得到的 ...

  8. 在Linux虚拟机下配置jdk的环境变量

    1.到Oracle公司的官网里下载好jdk,网址 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133 ...

  9. [Unity3D]利用Raycast实现物体的选择与操作

    本文系作者原创 转载请注明出处 如果是一个2D的平面项目或者说需要在三维空间选择一个物体时(经常表现为抓取物件),我们需要用到Raycast事件 那么首先先说说什么是Raycast 按照字面上来理解的 ...

  10. 通过几个Hello World感受.NET Core全新的开发体验

    2016年6月27日,这是一个特殊的日子,微软全新的.NET开发平台.NET Core的RTM版本正式发布.我个人将.NET Core的核心特性归结为三点,它们的首字母组成一个非常好记的简称——COM ...