android进程间binder机制服务端及客户端c 实现分析-凯发app官方网站

凯发app官方网站-凯发k8官网下载客户端中心 | | 凯发app官方网站-凯发k8官网下载客户端中心
  • 博客访问: 283052
  • 博文数量: 1
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 15
  • 用 户 组: 普通用户
  • 注册时间: 2019-06-26 14:38
文章分类

(1)

  • (1)
文章存档

(1)

我的朋友
最近访客
相关博文
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·
  • ·

分类: 嵌入式

2019-07-10 20:03:57

原文地址: 作者:

接触过android的人都知道binder服务调用是android系统的基础。它担负是跨进程或进程内调用和数据传递的任务。理解它是理解android众多services的基础。binder服务的层次图如下:

从图中看出,一个binder服务基本分为3层:第一层业务层,它是服务的主体;第二层是粘合层,它把服务的主体和下层的binder层粘合在一起,在这一层上,可以进行transact()调用;第三层是binder层,它负责与binder驱动交互,完成跨进程数据传递。下面从服务端实现说起:

binder服务的c 实现分析
bnxxxservice是由模板类bninterface生成的,bninterface扮演粘合剂的角色,它把服务主体接口(ixxxservice)和服务载体(bbinder)粘和在一起。它定义在frameworks/base/include/binder/iinterface.h:
  1. template<typename interface>
  2. class bninterface : public interface, public bbinder
  3. {
  4. public:
  5.     virtual sp<iinterface> querylocalinterface(const string16& _descriptor);
  6.     virtual const string16& getinterfacedescriptor() const;

  7. protected:
  8.     virtual ibinder* onasbinder();
  9. };

一个新的服务实体类bnxxxservice一般用下面的方式定义:

  1. class bnxxxservice : public bninterface<ixxxservice>
  2. {
  3. public:
  4.     virtual status_t ontransact( uint32_t code,
  5.                                     const parcel& data,
  6.                                     parcel* reply,
  7.                                     uint32_t flags = 0);
  8. };

模板展开后,相当于:
  1. class bnxxxservice : public ixxxservice, public bbinder{
  2. public:
  3.     virtual status_t ontransact( uint32_t code,
  4.                                     const parcel& data,
  5.                                     parcel* reply,
  6.                                     uint32_t flags = 0);
  7. }
这样bnxxxservice同时继承于ixxxservice和bbinder。ixxxservice是服务的接口,具体的服务函数在bnxxxservice中实现。必须重载bnxxxservice::ontransact(),在其中对不同的请求code,调用不同的函数。bbinder是服务的载体。当客户端发起服务请求,binder驱动找出相应服务的binder对象,这个binder对象就是bbinder,返回给ipcthreadstate,ipcthreadstate调用bbinder::transact(),如下面1028行代码所示:
  1. 891 status_t ipcthreadstate::executecommand(int32_t cmd){
  2. ...
  3. 897 switch (cmd) {
  4. ....
  5. 970 case br_transaction:
  6. 971 {
  7. 972     binder_transaction_data tr;
  8. 973     result = min.read(&tr, sizeof(tr));
  9.         ....
  10. 1026    if (tr.target.ptr) {
  11. 1027        sp<bbinder> b((bbinder*)tr.cookie);
  12. 1028        const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
  13. 1029        if (error < no_error) reply.seterror(error);
  14. 1030
  15. 1031     } else {
  16.             ....
  17. 1034 }
  18. }

1028行调用bbinder::tranact()。bbinder::tranact()是:

  1. 96 status_t bbinder::transact(
  2. 97 uint32_t code, const parcel& data, parcel* reply, uint32_t flags)
  3. 98 {
  4. 99     data.setdataposition(0);
  5. 100
  6. 101     status_t err = no_error;
  7. 102     switch (code) {
  8.         ....
  9. 106     default:
  10. 107         err = ontransact(code, data, reply, flags);
  11. 108         break;
  12. 109     }
  13.         ....
  14. 115     return err;
  15. 116 }

107行调用的ontransact(),其实就是bnxxxservice::ontransact()。这样就可以在bnxxxservice::ontransact()中通过switch语句完成各种各样的服务。有关类的关系如图:


由此看出:bnxxxservice包含两部分:一是ixxxservice,服务的主体的接口;另一部分是bbinder,它是服务的载体,它和binder驱动共同工作,保证客户的请求最终是对一个binder对象(bbinder类)的调用。从binder驱动的角度,每一个服务就是一个bbinder类,binder驱动负责找出服务对应的bbinder类。然后把这个bbinder类返回给ipcthreadstate,ipcthreadstate调用bbinder的transact()。bbinder的transact()又会调用ontransact()。bbinder::ontransact()是虚函数,所以实际实际是调用bnxxxservice::ontransact(),这样就可在bnxxxservice::ontransact()中完成具体的服务函数的调用。

bnxxxservice可以用下面的方法以名字“xxx.xxx.servicename”向servicemanager注册:
  1. defaultservicemanager()->addservice(string16("xxx.xxx.servicename"), new bnxxxservice());

注册后,系统中的其他用户就可以调用这个服务啦。

binder客户端c 实现分析

如果说bninterface是服务端服务主体和载体的粘和剂,那么bpinterface就是客户端代理和binder载体的粘合剂。它的定义:
  1. template<typename interface>
  2. class bpinterface : public interface, public bprefbase
  3. {
  4. public:
  5.     bpinterface(const sp<ibinder>& remote);
  6. protected:
  7.     virtual ibinder* onasbinder();
  8. };

与服务端类似,客服端一般也用下面的方式得到客户端的服务代理:
  1. class bpxxxservice: public bpinterface<ixxxservice>{
  2. }

这样bpxxxservice实际上是
  1. class bpxxxservice : public ixxxservice, public bprefbase{
  2. public:
  3.     bpxxxservice(const sp<ibinder& remote);
  4. ....
  5. };

构造bpxxxservice时需要一个ibinder引用。这个引用从哪里来呢?下面这段代码说明这个问题,它的功能是从servicemanager得到注册服务代理对象:
  1.     sp<iservicemanager> sm = defaultservicemanager();
  2.     sp<ibinder> binder = sm->getservice(string16("ixxxservice.name"));
  3.     sp<ixxxservice> cs = interface_cast<ixxxservice>(binder);

如代码所示:先通过defaultservicemanager()得到iservicemanager的客户代理,然后这个iservicemanager对象查询"ixxxservice.name"服务,servicemanager::getservice()返回对应服务的ibinder。最后,interface_cast把这个ibinder转换成服务的客户端代理类bpxxxservice。interface_cast的定义如下,

  1. template<typename interface>
  2. inline sp<interface> interface_cast(const sp<ibinder>& obj)
  3. {
  4.     return interface::asinterface(obj);
  5. }

  #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::asinterface(                \
            const android::sp& obj)                   \
    {                                                                   \
        android::sp intr;                                 \
        if (obj != null) {                                              \
            intr = static_cast(                          \
                obj->querylocalinterface(                               \
                        i##interface::descriptor).get());               \
            if (intr == null) {                                         \
                intr = new bp##interface(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    i##interface::i##interface() { }                                    \
    i##interface::~i##interface() { }                                   \
关键在:如果obj是bbinder,obj->querylocalinterface()返回接口本身;如果是bpbinder,则返回null。利用这个特性,当querylocalinterface()返回null时,程序构造一个bpxxxservice。这就是interface_cast(const sp& obj)返回的客户端代理类bpxxxservice。

这里有个细节,binder驱动实际上返回的是服务的句柄(handle),而getservice返回的是ibinder。这中间发生了什么?看看getservice(),getserivice()调用checkservice():
  1. virtual sp<ibinder> checkservice( const string16& name) const
  2. {
  3.     parcel data, reply;
  4.     data.writeinterfacetoken(iservicemanager::getinterfacedescriptor());
  5.     data.writestring16(name);
  6.     remote()->transact(check_service_transaction, data, &reply);
  7.     return reply.readstrongbinder();
  8. }
check_service_transaction的结果放在reply,binder驱动返回的服务句柄放在reply中,它应该在parcel::readstrongbinder()中被转换成sp。看看parcel::readstrongbinder()
  1. sp<ibinder> parcel::readstrongbinder() const
  2. {
  3.     sp<ibinder> val;
  4.     unflatten_binder(processstate::self(), *this, &val);
  5.     return val;
  6. }
  7. ...
  8. status_t unflatten_binder(const sp<processstate>& proc,
  9.     const parcel& in, sp<ibinder>* out)
  10. {
  11.     const flat_binder_object* flat = in.readobject(false);
  12.     
  13.     if (flat) {
  14.         switch (flat->type) {
  15.             case binder_type_binder:
  16.                 *out = static_cast<ibinder*>(flat->cookie);
  17.                 return finish_unflatten_binder(null, *flat, in);
  18.             case binder_type_handle:
  19.                 *out = proc->getstrongproxyforhandle(flat->handle);
  20.                 return finish_unflatten_binder(
  21.                     static_cast<bpbinder*>(out->get()), *flat, in);
  22.         }
  23.     }
  24.     return bad_type;
  25. }
parcel::readstrongbinder()调unflatten_binder()。在unflatten_binder()里,由于binder驱动返回的是handle,所以processstate::getstrongproxyforhandle()被调用。
  1. sp<ibinder> processstate::getstrongproxyforhandle(int32_t handle)
  2. {
  3.     sp<ibinder> result;

  4.     automutex _l(mlock);

  5.     handle_entry* e = lookuphandlelocked(handle);

  6.     if (e != null) {
  7.         ibinder* b = e->binder;
  8.         if (b == null || !e->refs->attemptincweak(this)) {
  9.             b = new bpbinder(handle); /*以handle为参数构造bpbinder*/ e->binder = b;
  10.             if (b) e->refs = b->getweakrefs();
  11.             result = b;
  12.         } else {
  13.             ....
  14.         }
  15.     }
  16.     return result;
  17. }
如果应用是第一次请求服务,那lookuphandlelocked(handle)应该返回null 。这样processstate::getstrongproxyforhandle()构造一个以handle为参数构造bpbinder。这个bpbinder就是getservice()得到ibinder。这样这个至关重要的handle被保存在bpbinder里。这个bpbinder也是interface_cast(const sp& obj)中输入参数的ibinder。
客户端涉及的类关系图:

到此为止,我们大致勾画出binder调用的过程,服务端用bninterface模板,把具体服务的接口和bbinder结合起来生成一个服务类。然后把这个服务类向servicemanager注册,注册简单地说就是把一个服务的名字和它对应的bbinder的句柄(handle)在servicemanager中关联起来。以后有人需要这个服务,可以用名字得到它的句柄,用这个句柄,binder驱动就可以找到具体的bbinder服务类了。
客户端用bpinterface模板,把具体服务的接口和bpbinder结合起来生成一个客户端代理类。客户端代理类的实质就是一个服务句柄,这个句柄从binder驱动中返回给应用层,应用层再用parcel::readstrongbinder()把它转换成sp,并把它保存在bpbinder。


阅读(283771) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:没有了

给主人留下些什么吧!~~
")); function link(t){ var href= $(t).attr('href'); href ="?url=" encodeuricomponent(location.href); $(t).attr('href',href); //setcookie("returnouturl", location.href, 60, "/"); }
网站地图