文章

Binder相关问题

Binder相关问题

Binder 面试题

Binder 相关问题

Binder 线程数?

默认为 16 个 Binder 线程

Zygote 孵化进程的 IPC 机制用 Socket 而不用 Binder?为什么?

为什么不用 Binder?

  1. zygote 在 fork 时,它会保持自己为单线程状态,这是因为多线程下的 fork 很容易在子进程中产生死锁、状态紊乱等一系列问题,根本原因是因为即便父进程为多线程,fork 之后的子进程也只会有一个线程,这种多对一的转换会遗漏掉很多同步的信息
  2. 19 年邮件咨询过 Google 负责 Binder 的两位工程师,因为 Binder 压根就不支持 fork,除非 fork 后调用 exec 开启全新的进程环境,这主要是因为 Binder 中对象生命周期的管理比较复杂,而如果为了支持 fork,那么它的设计将会更加复杂
  3. zygote 和 systemserver 本就是父子关系,对于简单的消息通信,用管道或者 socket 非常方便。

为什么不 fork system_server?
如果 zygote 用了 binder 机制,再 fork systemServer,那 systemServer 就继承了 zygote 的描述符和映射的内存,这两个进程在 binder 驱动层就会共用一套数据结构,这肯定是不行的。那还得把旧的描述符关掉,再重新启动一遍 binder 机制,自找麻烦。

ServiceManager

Client、Server 和 ServiceManager 之间怎么通信的?

Client、Server 和 ServiceManager 它们都是在不同的进程中,它们之间通信通过 Binder IPC 机制。Server 提供服务给 Client 使用,这个服务是以 Binder 引用的形式提供的。那么 Client 如何拿到 Server 的 Binder 的引用呢?
从 ServiceManager 中拿,ServiceManager 也是一个单独的进程,那么 Client 和 Server 如何与 ServiceManager 进行通信呢?这就陷入了先有鸡还是先有蛋的死循环了。
其实 Client、Server 和 ServiceManager 之间都是通过 Binder 通信的,只是 ServiceManager 作为特殊的 Binder(handle=0) 提前放入了 Binder 驱动里,Client 和 Server 想要获取 ServiceManager 的 Binder 引用,只需要获取 handle=0 的 Binder 即可。

servicemanager 进程和 Binder 驱动

servicemanager 是用户空间的守护进程,它会在启动时和 Binder 驱动进行通信;
它会在 Binder 驱动新建 ServiceManager 对应的 Binder 实体,并将该 Binder 实体设置为全局变量。

为什么要设置为全局的?

因为 Client 和 Server 都需要和 ServiceManager 进行通信,不设置为全局的,怎么找到 servicemanager。

ServiceManager 如何注册为 binder 上下文管理者的?

ServiceManager 提供的 Binder 比较特殊,它没有名字也不需要注册,当一个进程使用 BINDER_SET_CONTEXT_MGR 命令将自己注册成 ServiceManager 时 Binder 驱动会自动为它创建 Binder 实体(这就是那只预先造好的鸡)。其次这个 Binder 的引用在所有 Client 中都固定为 0而无须通过其它手段获得。也就是说,一个 Server 若要向 ServiceManager 注册自己 Binder 就必需通过 0 这个引用号和 ServiceManager 的 Binder 通信。

Android 中使用 binder 一定要用 service 吗?

什么是匿名 Binder、实名 Binder?匿名 Binder 的应用

  • 实名 Binder 在 ServiceManager 中注册了名字的 Binder 叫实名 Binder;
  • 匿名 Binder 未在 ServiceManager 注册了名字就是匿名 Binder,但必须通过实名 Binder 已经建立的 Binder 实体传递给 Client,Client 会收到这个匿名 Binder 的引用,通过这个引用向位于 Server 中的实体发送请求,匿名 Binder 为通信双方建立一条私密通道,只要 Server 没有把匿名 Binder 发送给其他进程,其他进程就无法通过穷举或猜测的方式获得该 Binder 的引用,向该 Binder 发送请求

什么是 oneway?AIDL 的 oneWay 和非 oneway 有什么区别?

oneway server 端是串行处理,异步调用,Client 端不用休眠等待驱动返回数据。

  • 非 oneway

w5607

  • oneway

8749v

  • 在 AIDL 中写代码时,如果接口标记了 oneway,表示 Server 端串行化处理 (从异步队列中拿出消息指令一个个分发)、异步调用。这个关键字主要是用于修改远程调用的行为,就如上面的两个图一样。非 oneway 关键字的 AIDL 类,客户端需要挂起线程等待休眠,相当于调用了 Sleep 函数。例如 WMS 、AMS 等相关系统 Binder 调用都是 oneway 的。

Intent 跨进程传大图为什么会崩溃?Binder 传输数据大小限制?1M?怎么突破?

常规的 intent 传递数据,在 startActivity 时将 Bundle 的 allowFds 设置成了 false(禁用了文件描述符), 然后就会将 Bitmap 直接写到 Parcel 缓冲区,不能利用共享内存,导致缓冲区超限,触发异常。如果通过 bundle.putBinder 形式传递 Bitmap,避免了 Intent 禁用描述符的影响,会开辟一个块共享匿名内存用来存 Bitmap 的数据,而 Parcel 缓冲区只是存储 FD 。

Binder 传输 1M 限制

原因:官方TransactionTooLargeException的文档中描述到:Binder 事务缓冲区有一个有限的固定大小,目前为 1MB,由进程所有正在进行的事务共享。继续往下看。

普通的应用是由 Zygote 孵化而来的用户进程,所映射的 Binder 内存大小是不到 1M 的,准确说是 1M-8K:110241024) - (4096 *2) :这个限制定义在 frameworks/native/libs/binder/processState.cpp 类中,如果传输数据超过这个大小,系统就会报错,因为 Binder 本身就是为了进程间频繁而灵活的通信所设计的,并不是为了拷贝大数据而使用的,所以当传递大的数据时会出现上述的错误:

解决 :用 Intent.putBinder
如果通过 bundle.putBinder 形式传递 Bitmap,会开辟一个块共享匿名内存用来存 Bitmap 的数据,而 Parcel 缓冲区只是存储 FD 。

Binder 只需要一次内存拷贝的原因?

底层用到了 mmap

本文由作者按照 CC BY 4.0 进行授权