Android Binder 数据传输常见问题

1,037 阅读3分钟

在我们日常开发使用过程中,我们经常会通过Binder对象调用跨进程服务接口方法。但使用Binder调用服务的时候,有存在一些我们容易忽视的问题,下面我们就来看看有哪些问题吧。

1. 基本信息

宏定义作用默认值调整建议
BINDER_VM_SIZE定义每进程的 Binder 缓冲区大小,默认为 1MB - 2 页大小。约 1MB可调整到更大值,例如 2MB。
DEFAULT_MAX_BINDER_THREADS每进程的最大 Binder 线程数,限制线程创建,防止资源滥用。15根据需要调整,例如 20-30。
DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION启用单向调用垃圾检测,防止过量调用对系统资源的影响。1(启用)对高并发单向调用的服务可能需要关闭检测。

大小限制

// frameworks/native/libs/binder/ProcessState.cpp
#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)

作用

  • BINDER_VM_SIZE 定义了每个进程用于 Binder 缓冲区的虚拟内存大小。
  • 默认大小为 1MB 减去两页的大小(sysconf(_SC_PAGE_SIZE) 通常是 4KB 或 8KB,视架构而定)。
  • 这表示,Binder 为每个进程分配的内存区域稍小于 1MB。

原因

  • Binder 使用的内存需要页对齐。减去两页大小是为了给额外的内存管理结构留空间。

  • 每个 Binder 进程的缓冲区从这块虚拟内存中分配。

线程限制

#define DEFAULT_MAX_BINDER_THREADS 15  // 15子线程

作用

  • 限制每个进程可以创建的最大 Binder 工作线程数,默认最多 15 个线程。所以加上1
  • 这些线程在用户态处理来自 Binder 驱动的事务(transaction)。

原因

  • 限制线程数是为了防止某个进程过多占用系统资源,导致性能下降。

  • 默认值 15 是一个经验值,可以根据系统负载调整。

Oneway 异步

#define DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION 1

作用

  • 启用了 Binder 的单向调用(oneway)的垃圾检测机制。
  • 默认值为 1,表示启用。

背景

  • Binder 支持单向调用(oneway),即异步请求。这种调用不会等待接收端返回结果,因此处理速度更快。
  • 然而,如果存在过多的单向调用,可能会淹没接收端线程,导致性能问题。

启用的功能

  • 系统会检测某个进程是否发送了过多的单向调用。

  • 如果检测到过量调用,可能会限制该进程的调用频率。

2. 常见问题

Service端频繁调用oneway回调函数

E  Process seems to be sending too many oneway calls.
 2024-11-29 15:18:52.969  2853-4313  IPCThreadState xxxxxxxxx W  CallStack::getCurrentInternal not linked, returning null
 2024-11-29 15:18:52.969  2853-4313  oneway spamming  xxxxxxxxx  W  CallStack::logStackInternal not linked
 2024-11-29 15:18:52.969  2853-4313  JavaBinder    xxxxxxxxx E  !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2xx64)

Service 在回调client端的函数,通常会使用oneway声明函数,异步调用。但是如果短时间内调用的频率过高,会出现上述的错误。解决方案:

  • 如果是大数据分段传输,就需要重新选择数据传输方案。如传文件描述符,socket等
  • 控制回调频率

Binder 接口请求数据过大

BInder缓冲区最大值是不到1M,所以需要考虑并发情况下,每次调用最大传输的数据大小。

Binder调用执行所在的线程

会在binder线程中执行,默认会在上述提到的16个线程中分配,所以可能是子线程也可能是主线程。

为什么选择使用Binder传输大数据?如何传输大数据?

  • 为什么使用binder传输:通过binder机制传输数据,能够天然的使用到Android的权限校验机制

    • Service permission的配置
  • 如何传输:通过binder传递文件标识符,直接跨进程对文件进行读写

还有什么常见问题,可以评论区讨论讨论