安卓笔记—binder

binder的c实现代码我没有读,下面的笔记都是从文章中学习的
https://elinux.org/Android_Binder

binder有哪些功能?

  1. 跨进程传输数据,跨进程传递时机。
    进程是分配内存的最小单位,因此进程间不共享内存。但是内核与进程之间是一对多的关系,也就是一个内核对应多个进程,因此binder通过函数copy_from_user把进程A的数据复制到内核空间,通过函数copy_to_user把内核的数据复制到进程B,完成进程间数据传递。
  2. 将不同进程的同一个binder对象做映射。
    进程B只有拿到进程A的binder对象,才能使用这个对象来跨进程调用A的函数。
    进程A中的binder对象xa通过上面的方式被传递到进程B,实际上是在进程B的内存中新建了一个binder对象xb。对象xa和对象xb是不同的进程,不同的内存,怎么能叫同一个binder对象呢?因为每次进程A将对象xa传给进程B时,进程B收到的都是对象xb。这样进程B第二次接收到对象xb时,B就有能力说:“是你上次要启动的服务吧,服务已经启动好了,这是可以调用服务的binder,请收好”,这句话看似是进程B和对象xb说的,其实是进程B和对象xa说的。起到一个身份识别的作用。
    进程B将对象xb跨进程传给进程C时,进程C每次收到也都是同一个对象xc。那么当进程C将xc传给进程A的时候,进程A接收到的必然是对象xa。这映射是如何实现的呢?binder自有他的办法,反正也不难实现,我就不纠结了。
  3. 将跨进程操作伪装成函数调用,方便程序员使用

如果不跨进程,那么调用一个接口的方式是:

caller 
-> 接口函数 //interface
-> 接口函数的实现 //callee,接口函数的用户实现

直接使用binder进行跨进程通信,函数调用如下

//进程B的caller,利用xb对象
caller
-> IBinder.transact(int code, Parcel data, Parcel reply, int flags)  //IBinder接口函数
-> BinderProxy.transact(int code, Parcel data, Parcel reply, int flags) //IBinder接口函数的实现
-> BinderProxy.transactNative(int code, Parcel data, Parcel reply, int flags) // native方法,下接binder驱动
-> binder驱动,真正的IPC发生在这里 //切换到进程A,也切换到xa对象
-> Binder.onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) // 回调接口
-> callee // 接口函数的用户实现,也是caller真正想要调用的函数
// 其中函数中的参数code可以用来对应不同的函数,比如:
// onTransact接收到code是1时,从data中读一个int,并调用 M1(int i)函数
// onTransact接收到code是2时,......

这里比较机械繁琐的就是:
调用IBinder.transact时需要把函数名字转换成code,然后把参数序列化
实现Binder.onTransact时需要把code转化成函数名字,然后把参数反序列化

使用aidl的目的就是可以自动生成code和函数的转化代码,以及参数和返回值的序列化与反序列化代码,也就是proxy类和stub类,函数调用如下

//进程B的caller,利用xb对象
caller // new proxy对象时要传入xb对象,这样才能赋予proxy跨进程能力
-> Stub.Proxy.M1 //参数code由stub.proxy.M1函数负责传入一个能唯一代表M1的数字,利用xb对象
-> IBinder.transact(int code, Parcel data, Parcel reply, int flags)  //IBinder接口函数
-> BinderProxy.transact(int code, Parcel data, Parcel reply, int flags) //IBinder接口函数的实现
-> BinderProxy.transactNative(int code, Parcel data, Parcel reply, int flags) // native方法,下接binder驱动
-> binder驱动,真正的IPC发生在这里 //切换到进程A,也切换到xa对象
-> Binder.onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) // 回调接口
-> Stub.onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) // 自动生成的接口实现,会根据code调用不同的函数
-> Stub.M1 //callee,接口函数的用户实现,也是caller真正想要调用的函数

stub有静态函数asInterface,接受binder对象,然后帮你new一个proxy
proxy有asBinder方法,返回binder对象

  1. 维护引用关系,防止xa对象被gc

    进程B刚拿到对象xb时,xa会被弱引用,当进程B调用了xb/xa的函数后,xa会被强引用,防止被gc。

  2. 提供接口判断进程A是否还在,提供接口接受进程A结束的消息
public boolean pingBinder();
public boolean isBinderAlive();
public void linkToDeath(DeathRecipient recipient, int flags)
  1. binder线程池
    上面的Binder.onTransact的回调函数不是在进程A的主线程回调的,而是在进程A中有一个线程池专门用于接受onTransact回调
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值