Binder关键问题

如何利用关键问题,感性理解Binder

1.service_manager的启动

用来管理服务,所有的系统服务都会注册到这里。

本质上是服务的引用BpBinder的管理者,可以将服务引用BpBinder分发给其他Client。

当然了,这种分发在内核中是传递binder_node到其他进程,并在该进程中建立新的binder_ref和 BpBinder

思考:

       service_manager是如何成为管理者的 
        {
              必须是公共入口
              
              提供了存储服务
              
       }
       
       如何与管理者通信 {
       
              /dev/binder休眠唤醒
              
              数据协议
              
      }
复制代码

2.BpBinder、BBinder、IPCThreadState、ProcessState之间的关系

进程复用的底层与/dev/Binder的交互逻辑,全部放到了IPCThreadState中,数据的分发是靠Parcel + binder_transaction_data -> binder_write_read协议来实现的,所以只要将数据打包好,自然能够发送到目的地。

ProcessState主要缓存了BpBinder,实现放到IPCThreadState中也没有什么问题。

3.BpInterface、BnInterface、BpBinder、BBinder之间的关系

C++层的aidl而已,这个理解应用比较到位吧

Java层的

    IXXXService.Stub继承自Binder映射了JNI中的JavaBBinder

    IXXXService.Proxy继承自BinderProxy,从IPCProcessState传过来的Parcel,最终解析成为BpBinder,转化为了Java层的BinderProxy。
复制代码

4.如何划分Binder架构层次

Java层:

             Binder.exeTransact
复制代码

C++层:

           (BnInterface)
            JavaBBinder.onTransact    (data)
            
            BBinder.transact  (data、BBinder -> Parcel)
            
            IPCThreadState::getAndExecuteCommand  (Parcel -> binder_transaction_data ->
            
            binder_write_read )
            
            IPCThreadState::talkWifiDriver + waitForResponse
复制代码

内核层:

            ioctl
            /dev/binder          (binder_write_read -> binder_transaction_data -> binder_write_read)
            binder_ioctl
            binder_write_read
            binder_write_thread
            binder_transaction
复制代码

5.一次有效的通信是如何实现的

无论是Java层还是C++层的上层调用,都是利用BpBinder -> IPCThreadState来发送数据,利用BBinder-> IPCThreadState来接收数据。一次有效的数据通信涉及到几个方面:

1.BBinder实体的注册

2.BpBinder引用的获取

3.利用上层数据(data + flat_binder_object + 协议) + 传输handle 进行传输

4.内核驱动数据转发实现

6.如和注册到实名binder的

要注册实名binder(service_manager进行一次add,其他binder先得获得引用,然后执行add操作) A.service_manager中执行add,先获取其引用BpBinder(0),Java层构建了ServiceManager_Proxy->Binder_Proxy->BpBinder(0),可以直接通信了。

1.一个服务在Java层注册

利用aidl生成Stub和Proxy,实现Stub的接口,利用ServiceManager.addService(name, Stub)注册到ServiceManager中.代码如下:

142    public void addService(String name, IBinder service, boolean allowIsolated)
143            throws RemoteException {
144        Parcel data = Parcel.obtain();
145        Parcel reply = Parcel.obtain();
146        data.writeInterfaceToken(IServiceManager.descriptor);
147        data.writeString(name);
148        data.writeStrongBinder(service);
149        data.writeInt(allowIsolated ? 1 : 0);
150        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
151        reply.recycle();
152        data.recycle();
153    }
复制代码

Java层的Binder写到Parcel中变成了ibinderForJavaObject(env, object),即转换成了JavaBBinder,并与Stub构建了关系关系,即JavaBBinder (BBinder) <-> Stub (Binder)

2.一个服务在C++层注册

利用BpInterface和BnInterface约定关系,实现BnXXXService,并实现其中的code与函数调用关系。BnXXXService是BBinder的子类,最后调用C++层的IServiceManager.defaultServiceManager.addService(name, BBinder)来注册。

virtual status_t addService(const String16& name, const sp<IBinder>& service,
          bool allowIsolated)  {
       Parcel data, reply;
       data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
       data.writeString16(name);
       data.writeStrongBinder(service);
       data.writeInt32(allowIsolated ? 1 : 0);
       status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
       return err == NO_ERROR ? reply.readExceptionCode() : err;
}       
复制代码

这里还需要记录一点:Binder节点基本上是第一次注册到实名Binder时,在通信的两个进程中,分别在内核中创建的binder_node。当然了,在发送端是创建binder_node节点,而在接收端是拷贝binder_node节点。

7.如何拿到引用以及引用如何找到目标

要拿到引用,只要跟实名binder通信一次(servcie_manager是一次、其他实名binder是两次) 如果要从service_manager中拿到引用,首先在IPCThreadState中找到BpBinder(0),利用其构造getService的通信handle + data + target binder -> Parcel -> binder_transaction_data -> binder_write_read,利用通信协议将binder_transaction_data.handle传递到内核,内核根据handle去查找binder_ref (两处查找,一个是binder_proc->refs_by_desc,一个是binder_context_mgr_node),进而查找到目标binder_node。利用binder_node通信的过程:唤醒目标binder线程、取数据、解析,于是到了service_manager的上层了,后续不详述了。

1.Java层如何找到服务

ServiceManager.getService在Java层是带有缓存的,如果有缓存那么直接取,如果没有那么利用ServiceManagerProxy -> BinderProxy -> BpBinder(0)来获取服务,看下代码吧。最后得到的是一个经JNI转换的BinderProxy。native得到的是BpBinder,而Java很显然不能使用,了解Binder层次的话,很自然能够确定一定是Binder_Proxy。

118    public IBinder getService(String name) throws RemoteException {
119        Parcel data = Parcel.obtain();
120        Parcel reply = Parcel.obtain();
121        data.writeInterfaceToken(IServiceManager.descriptor);
122        data.writeString(name);
123        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
124        IBinder binder = reply.readStrongBinder();
125        reply.recycle();
126        data.recycle();
127        return binder;
128    }
复制代码

2.在C++层找到服务

同样利用BpInterface来找到服务,先构建了一个BpServiceManager (继承自BpInterface和IServiceManager),然后通信就好了。最后得到的是一个BpBinder

gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL));

146    virtual sp<IBinder> getService( const String16& name) const
147    {
148        Parcel data, reply;
149        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
150        data.writeString16(name);
151        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
152        return reply.readStrongBinder();
153    }
复制代码

8.Java层和C++层的映射关系

Binder构造时:

JavaBBinder 放到了JavaBBinderHolder 的mBinder域, JavaBBinderHolder放到了 Binder.mObject 域,而Binder引用放到了 JavaBBinder.mObject,因此Binder和JavaBBinder建立了Java到C++的双向关联引用关系。

BinderProxy构造时:

基本在C++里面出发,将BpBinder放到BinderProxy.mObject,而例如ServiceManagerProxy将BinderProxy放到了ServiceManagerProxy.mRemote域中。

9.Android层服务的注册和引用

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

首先注册Service到SystemServer进程,然后在Context中静态初始化Client,应用利用Context.getSystemServer即可找到IVibratorService.Proxy了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值