Binder In Native

关于Binder的设计思想与Driver层实现细节能够看这个:Android Binder设计与实现 - 设计篇,这里首先简要归纳一下。html

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

每一个使用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实体的引用。android

匿名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发送请求。ui

通常状况下,若是Client要向某一Service进行一个请求,首先会经过向引用号为0的Binder引用发送GET_SERVICE请求得到本身须要的Service在的引用,而后再向这个引用即这个引用对应的Service发送请求。this

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

当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。

相关文章
相关标签/搜索