Binder In Native_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > Binder In Native

Binder In Native

 2013/9/17 15:59:14  AngelDevil  博客园  我要评论(0)
  • 摘要:关于Binder的设计思想与Driver层实现细节可以看这个:AndroidBinder设计与实现-设计篇。这里只记录下Native层对Binder的使用。Binder被实现为一个字符设备,应用程序通过ioctl调用与Binder驱动程序进行通信。首先看实现一个ServiceDemo涉及到的类结构关系。RefBase是Android实现指针管理的类,牵扯到引用计数的都继承自这个类,然后通过sp,wp实现强引用计数与弱引用计数的管理。Binder使用Client-Server的通信方式
  • 标签:

  关于Binder的设计思想与Driver层实现细节可以看这个:Android Binder设计与实现 - 设计篇。这里只记录下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会调用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。

 

  • 相关文章
发表评论
用户名: 匿名