Binder In Native

关于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(0)
{
    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(0);
}

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(0));

  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 != -1) {
                        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 = 1;
                binder_context_mgr_node->has_weak_ref = 1;
                break;

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

时间: 2024-10-22 06:59:05

Binder In Native的相关文章

《深入理解Android:卷III A》一一2.2Java层中的Binder分析

2.2Java层中的Binder分析 2.2.1Binder架构总览 如果读者读过卷I的第6章,相信就不会对Binder架构中代表Client的Bp端及代表Server的Bn端感到陌生.Java层中Binder实际上也是一个C/S架构,而且其在类的命名上尽量保持与Native层一致,因此可认为,Java层的Binder架构是Native层Binder架构的一个镜像.Java层的Binder架构中的成员如图2-1所示. 由图2-1可知: 图 2-1Java层中的Binder家族 系统定义了一个IB

Binder in Java

Android在Native层实现了进程间的Binder通信,但是上层应用程序的开发及Framework的实现都是Java,用Java层再实现一次肯定是不合理的,Java可以通过JNI调用Native Code,所以通过JNI复用Binder在Native层的实现就是一个顺理成章的事情. 注册Service 在Init进程的init2阶段,系统启动了ServerThread,在ServerThread中会启动很多用Java实现的系统服务,比如说PowerService: power = new

人人都会设计模式:05-代理模式--Proxy

版权声明:本文为博主原创文章,未经博主允许不得转载公众号:TigerChain 更多文章等着你 作者: TigerChain 教程简介 1.阅读对象 本篇教程适合新手阅读,老手直接略过 2.教程难度 初级,本人水平有限,文章内容难免会出现问题,如果有问题欢迎指出,谢谢 正文 一.什么是代理模式 1.生活中的代理 1.微商代理 代理在生活中就太多了,比如微商,在朋友圈中很多时候都可以看到微商说城招全国代理「不需要货源,不需要启动资金,只需要一个电话就能做生意,好吧我口才不好,没有人家吹的好」,这类

I.MX6 Android frameworks services 文件架构

/******************************************************************************* * I.MX6 Android frameworks services 文件架构 * 说明: * 这部分内容后续可能需要多给一点注意力了,因为这部分在做系统移植的时候经常 * 需要通过这部分来进行调试. * 2016-3-19 深圳 南山平山村 曾剑锋 ******************************************

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析_Android

        在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码.细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现的,但是我们在编写应用程序都是基于Java语言的,那么,我们如何使用Java语言来使用系统的Binder机制来进行进程间通信呢?这就是本文要介绍的Android系统应用程序框架层的用Java语言来实现的Binder接口了.        熟悉Android系统

Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析_Android

        在前面一篇文章Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路中,介绍了在Android系统中Binder进程间通信机制中的Server角色是如何获得Service Manager远程接口的,即defaultServiceManager函数的实现.Server获得了Service Manager远程接口之后,就要把自己的Service添加到Service Manager中去,然后把自己启动起来,等待Cl

Android深入浅出之Binder机制_Android

Android深入浅出之Binder机制 一 说明  Android系统最常见也是初学者最难搞明白的就是Binder了,很多很多的Service就是通过Binder机制来和客户端通讯交互的.所以搞明白Binder的话,在很大程度上就能理解程序运行的流程. 我们这里将以MediaService的例子来分析Binder的使用:          ServiceManager,这是Android OS的整个服务的管理程序         MediaService,这个程序里边注册了提供媒体播放的服务程

Android源码分析-Alarm机制与Binder的交互

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/18448997 前言 本次给大家分析的是Android中Alarm的机制以及它和Binder的交互,所用源码为最新的Android4.4.因为Alarm的功能都是通过Binder来完成的,所以,介绍Alarm之前必须要先介绍下它是如何调用Binder来完成定时功能的.由于内容较多,本文会比较长,在文章结构安排上是这样的:首先简单介绍如何使用Alarm并给出其工作原理,接着分析

Atlas:手淘Native容器化框架和思考

在刚刚过去的云栖大会上,手淘宣布其移动容器化框架Atlas将于2017年年初开源,对这个框架,在过去团队对外部做过一些分享,外界也一直对其十分关注,到现在它终于即将开源了. 本文将介绍Atlas的设计思路和手淘对容器化.组件化和动态化上的思考,主要内容来自阿里巴巴资深技术专家倪生华(玄黎)在2016杭州云栖大会上的分享. Atlas是什么 2013年,手淘航母战略的制定,带来了业务和开发人员的翻倍膨胀.从不到100人猛增四五倍,同时业务数量大增,整个客户端的架构和发版节奏受到极大挑战,Atlas