返回介绍

3.3 Binder 设备文件的打开和读写

发布于 2024-12-23 21:29:01 字数 3189 浏览 0 评论 0 收藏 0

1. 设备的打开

在上一小节中我们看到 JNI 过程中调用了 ProcessState::getContextObject() 函数, 在 ProcessState 初始化时会打开 binder 设备

// ProcessState.cpp
ProcessState::ProcessState()
  : mDriverFD(open_driver())
  ...
{
  ...
}

open_driver() 函数内容如下

// ProcessState.cpp
static int open_driver()
{
  // 打开设备文件
  int fd = open("/dev/binder", O_RDWR);
  if (fd >= 0) {
    fcntl(fd, F_SETFD, FD_CLOEXEC);
    int vers = 0;
    // 获取驱动版本
    status_t result = ioctl(fd, BINDER_VERSION, &vers);
    if (result == -1) {
      ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
      close(fd);
      fd = -1;
    }
    // 检查驱动版本是否一致
    if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
      ALOGE("Binder driver protocol does not match user space protocol!");
      close(fd);
      fd = -1;
    }
    // 设置最多 15 个 binder 线程
    size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
    result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
    if (result == -1) {
      ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
    }
  } else {
    ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
  }
  return fd;
}

2. 设备的读写

打开设备文件后,文件描述符被保存在 mDriverFD , 通过系统调用 ioctl 函数操作 mDriverFD 就可以实现和 binder 驱动的交互。

对 Binder 设备文件的所有读写及关闭操作则都在 IPCThreadState 中,如上一小节提及到的 IPCThreadState::talkWithDriver 函数

talkWithDriver() 函数封装了 BINDER_WRITE_READ 命令,会从 binder 驱动读取或写入封装在 binder_write_read 结构体中的本地或远程对象。

// IPCThreadState.cpp
status_t IPCThreadState::talkWithDriver(bool doReceive)
{   
  binder_write_read bwr;
  const bool needRead = mIn.dataPosition() >= mIn.dataSize();
  const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
  
  // 写入数据
  bwr.write_size = outAvail;
  bwr.write_buffer = (uintptr_t)mOut.data();

  // 读取数据
  if (doReceive && needRead) {
    bwr.read_size = mIn.dataCapacity();
    bwr.read_buffer = (uintptr_t)mIn.data();
  } else {
    bwr.read_size = 0;
    bwr.read_buffer = 0;
  }
  ...
  // 使用 ioctl 系统调用发送 BINDER_WRITE_READ 命令到 biner 驱动
  if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
    err = NO_ERROR;
  ...
}

可以看出,本地层是对应用与 binder 驱动交互的直接封装与实现,最终的数据传输仍是由驱动来完成的。本地层对底层驱动进行了完整的封装,上层应用只关心 transact() 和 onTransact() 回调,察觉不到 binder 驱动的存在,减轻了上层应用进程间通信开发的复杂度。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文