Binder学习总结

目录

一、Binder 与AIDL的关系

二、大致流程:

三、Binder优点:

四、实现原理:

五、Binder相关类介绍:

附:


一、Binder 与AIDL的关系


Binder是跨进程通信的一种方式,AIDL(Android interface definition Language 即 Android 接口定义语言)是使用Binder的封装的一个模板、一种简单方法。


二、大致流程:

  1. 服务端启动时,IPCThreadState::joinThreadPool 会创建一个死循环线程,不断监听来自客户端的消息,然后调用executeCommand去执行,会调BBinder::transact--onTransact,而实现的本地服务会继承BBinder,实现onTransact方法。
  2. Server向ServerManager注册;
  3. Client通过ServerManager查询Server,并借助Binder驱动返回Server的引用; (并不是所有用来通信的binder都要注册到SM中,也可以通过创建的Binder连接直接把Binder实体给Client调用)

注意:startThreadPool会创建一个新线程,里面也会调用joinThreadPool。参考StartThread Pool和join Thread Pool分析Binder服务的调用对象和Binder服务处于同一进程。

调用流程:
AIDL文件编译后会生成一个对应的java文件,里面是个继承了AIDL接口的proxy.
Client调用函数如add时,调用proxy的add方法,会通过Remote.transact 函数名和参数。
Binder 调用transactNative,底层会调用底层Binder驱动,终会调用Binder的execTransact,里面会调用onTransact。而Stub类重写了onTransact()方法,里面会调用服务端的add方法。

在这里插入图片描述

参考:Binder通信机制与AIDL的基本使用

640?wx_fmt=jpeg

(1)client调用service
    client得到一个BpXXXService以后
    (a)会调用BpXXXService实现的helloWorld,它会将str参数打包到Parcel中。然后调用remote()->transact(xxx)
    (b)remote()是在BpXXXService的父类BpRefBase中实现的,返回的就是一个BpBinder.实际上调用的就是BpBinder的transact
    (c)BpBinder的transact实现,就是直接调用IPCThreadState::self()->transact()发送数据。
(2)service接收client请求:
    (a)通过IPCThreadState接收到client的请求后,首先会调用BBinder的transact方法。
    (b)BBinder的transact方法又会调用子类实现的虚拟方法onTransact。这个虚拟方法是在BnXXXService中实现的。
    (c)onTransact方法,会通过传递进来的参数来判断,需要调用IXXXService中的那个方法,示例中只有一个helloWorld方法。
    (d)直接调用helloWorld,就会找到它的真正实现,也就是BnXXXService的子类XXXService中的helloWorld方法。
总结一下,从上面的流程当中就可以看出前文说的,BpBinder并不在继承关系当中,它只是一个打包数据,并通过IPCThreadState::self()->transact()方法发送出去。
而BBinder和BnXXXService的作用,就是接收IPCThreadState传递过来的信息,解包数据,并调用XXXService真正的实现。

注意事项
Client持有自己Binder的实体,Server端持有其引用;Server端持有其自己Binder的实体,Client持有其引用。
ServerManager是一个进程、Server又是另一个进程。


三、Binder优点:


相比于内存共享:实现方便、方便管控;可知道对方的PID等;
相比于管道和消息队列等:数据只需一次拷贝,省时;

如何理解binder的一次拷贝

copy_from_user调用了多次,但真正建立内存映射的只有一次,其余的主要是地址引用的copy。

四、实现原理:


内存映射mmap:简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。

Client持有Binder引用;Server端持有Binder实体。

in,out,inout, oneway作用

参数类型默认是in,

int,String 等基本类型不能修饰为out或inout等类型。

当为in时,参数能传递至server端;但是server端修改值后不会影响client原来的值。

为out时,参数不能传递至server端,下面的例子中server打印出来为[0,0]; 

当为inout时,才能两边互传。

 int test(in int a,  in byte[] inArray,out byte[] outArray,  inout byte[] inoutArray);
//client端
    private void test() {
        byte[] inArray = new byte[]{1, 2};
        byte[] outArray = new byte[]{8, 9};
        byte[] inoutArray = new byte[]{8, 9};
        try {
            int a = 5;
            Log.d(TAG, "client ------------origin a: " + a);
            Log.d(TAG, "origin inArray: " + Arrays.toString(inArray));
            Log.d(TAG, "origin outArray: " + Arrays.toString(outArray));
            Log.d(TAG, "origin inoutArray: " + Arrays.toString(inoutArray));
            iRemote.test(5, inArray, outArray, inoutArray);
            Log.d(TAG, "client---------after a: " + a);
            Log.d(TAG, "after inArray: " + Arrays.toString(inArray));
            Log.d(TAG, "after outArray: " + Arrays.toString(outArray));
            Log.d(TAG, "after inoutArray: " + Arrays.toString(inoutArray));
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
//server端
        @Override
        public int test(int a, byte[] inArray, byte[] outArray, byte[] inoutArray) throws RemoteException {
            Log.d(TAG, "server-----origin a: " + a);
            Log.d(TAG, "origin inArray: " + Arrays.toString(inArray));
            Log.d(TAG, "origin outArray: " + Arrays.toString(outArray));
            Log.d(TAG, "origin inoutArray: " + Arrays.toString(inoutArray));
            a = 0;
            inArray[0] = 0;
            outArray[0] = 10;
            inoutArray[0] = 0;
            Log.d(TAG, "server----after a: " + a);
            Log.d(TAG, "after inArray: " + Arrays.toString(inArray));
            Log.d(TAG, "after outArray: " + Arrays.toString(outArray));
            Log.d(TAG, "after inoutArray: " + Arrays.toString(inoutArray));
            return 0;
        }

运行结果如下:

 

oneway 表示异步调用。修饰的接口不能有返回值,且参数不能包含out和inout修饰。默认为同步调用,会导致调用端阻塞。

不用oneway修饰时,多进程能同时调用server;

用oneway修饰时,多进程调用同一个接口,server端会按顺序先后执行。

下面server端sleep 4s。分别在Client1和Process2进程调用。

未用oneway修饰接口:client1和Process2都调用了server端时,service端接口同时执行,但客户端会卡住。

用oneway修饰接口:client1和Process2都调用了server端时,service端接口顺序执行。 

oneway 修饰接口

 

binder底层通信协议;

五、Binder相关类介绍:


IBinder : IBinder 是一个接口,代表了一种跨进程通信的能力。只要实现了这个借口,这个对象就能跨进程传输。
IInterface : IInterface 代表的就是 Server 进程对象具备什么样的能力(能提供哪些方法,其实对应的就是 AIDL 文件中定义的接口)
Binder : Java 层的 Binder 类,代表的其实就是 Binder 本地对象。BinderProxy 类是 Binder 类的一个内部类,它代表远程进程的 Binder 对象的本地代理;这两个类都继承自 IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。
Stub : AIDL 的时候,编译工具会给我们生成一个名为 Stub 的静态内部类;这个类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有 Server 承诺给 Client 的能力;Stub 是一个抽象类,具体的 IInterface 的相关实现需要开发者自己实现。

========================

RefBase:指针基类
IBinder 继承RefBase,IBinder.h: 申明binder的必要方法;
BBinder 继承IBinder;在Server进程中,BBinder为Binder本地对象提供了抽象的进程间接口.
BpBinder 继承IBinder;Binder proxy ,在Client进程中;
BBinder和BpBinder的功能并不是对称的,改成BnBinder可能更形象: Binder Native。
BnInterface 继承BBinder;    在Server进程中。
BpInterface 继承BpRefBase;BpRefBase继承RefBase,为Binder代理对象提供了进程间通信的接口

asInterface 完成的是Binder到Interface的转换,具体就是:BBinder->BnInterface;BpBinder->BpInterface。
而asBinder功能则相反,具体是:BnInterface->BBinder;BpInterface->BpBinder

Binder代理对象    类型为BpBinder,在用户空间创建,且执行在Client进程中.会被Client进程中的其他对象引用,另外会引用Binder驱动程序中的Binder引用对象.
Binder引用对象    类型为binder_ref,在Binder驱动程序中创建,被Binder代理对象引用.
Binder实体对象    类型为binder_node,在Binder驱动程序中创建,被Binder引用对象所引用
Binder本地对象    类型为BBinder,在用户空间中创建,且执行在Server进程中.会被Server进程中其他对象引用,还会被Binder实体对象引用.

ProcessState是负责打开Binder节点并做mmap映射,IPCThreadState是负责与Binder驱动进行具体的命令交互。
getService@ServiceManagerProxy-->transact@BinderProxy-->transact@BpBinder-->transact@IPCThreadState

Binder传输最大数据:普通的由Zygote孵化而来的用户进程,所映射的Binder内存大小是不到1M的,准确说是 110241024) - (4096 *2) :这个限制定义在ProcessState类中。


附:

Binder一些疑难点详解:参考深入理解Binder通信原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
binder_open是Binder机制中的一个函数,用于打开Binder驱动并返回一个Binder状态结构体。在该函数中,会调用copy_from_user函数从用户空间获取一个struct binder_write_read结构体,并将其作为参数传递给binder_thread_write和binder_thread_read函数。\[1\] 在Binder机制的Native层实现中,binder_open函数被用于开启Binder,并将自身注册为Binder进程的上下文,然后通过调用binder_loop函数来启动Binder循环。\[2\] 在binder_loop函数中,如果收到了Binder的读写消息信息,会调用binder_parse函数进行处理。binder_parse函数会将读取到的消息进行解析,并调用相应的处理函数进行处理。\[3\] #### 引用[.reference_title] - *1* [05.Binder系统:第6课第2节_Binder系统_驱动情景分析_打印数据交互过](https://blog.csdn.net/weixin_43013761/article/details/88171380)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【Binder 机制】Native 层 Binder 机制分析 ( binder_loop | svcmgr_handler | binder.c | binder_parse )](https://blog.csdn.net/han1202012/article/details/120345228)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值