Binder浅析

211 阅读3分钟

为什么要用多进程: 扩大内存,风险隔离

单个虚拟机即单个进程能申请的最大内存
 adb shell getprop|grep dalvik.vm.heapsize
|[dalvik.vm.heapsize]: [384m]

image.png

UID相当于唯一标识,身份证,系统服务有UID,所以我们可以通过 getSystemService(String name)方式获取系统服务,这个是实名服务。 而我们自己创建的服务就是匿名的,外部不能随意获取。

内核空间所有进程共享是因为不同进程对应的内核空间的虚拟地址共同指向同一块物理空间,使用时候再分配。

image.png

内核空间和数据接收方的虚拟内存共同指向同一块物理地址,这是内存映射的实质

Binder驱动的四个步骤

image.png

binder_init 创建binder设备节点

  1. 分配内存
  2. 初始化设备
  3. 放入链表 binder_devices

binder_open 获取binder文件描述富豪

  1. 创建binder_proc对象 是保存参与IPC的进程信息
  2. 把binder_proc添加到binder_procs链表中

binder_mmap 分配内存并映射

struct vm_struct *area; --- 内核的虚拟内存

vma --- 进程的虚拟内存 --- 4M 驱动定的binder一次传输数据上限,应用层指定的上限是1M-8k --- 这也是intent传输的时候数据不能超过1M的原因 如果是异步方法的话传输上限为同步的1/2 默认是同步

  1. 通过用户空间的虚拟内存大小 --- 分配一块内核的虚拟内存
  2. 分配了一块物理内存 --- 4KB(默认先分配这么多,真正通信时候再添加,免得内存浪费)
  3. 把这块物理内存分别映射到用户空间的虚拟内存和内核的虚拟内存

binder_ioctl 操作数据传输

读写操作 --- BINDER_WRITE_READ --- ioctl(BINDER_WRITE_READ)

Binder 涉及到的类

image.png

IPC交互的主要过程

image.png

Binder的整体架构

image.png

ServiceManager

image.png

维护服务的ibinder,能够让寻找服务的进程拿到ibinder对象

sm注册流程

  1. 打开驱动,内存映射(设置大小 128K)把sm和内核区域共同映射一块内存

  2. 设置 SM 为大管家 --- sm  作用  为了管理系统服务  并通过binder_looper循环监听是否有其他进程访问它

   1. 创建 binder_node 结构体对象

   2. proc --》 binder_node

   3. 创建  work  和 todo --》类似 messageQueue

  1. BC_ENTER_LOOPER 命令

   1. 写入状态Loop

   2. 去读数据:binder_thread_read:ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); 进入等待

native层注册服务到sm流程

  1. ProcessState::self()->getContextObject(NULL)、

   1. ProcessState::self()

      1. 打开驱动:binder

      2. 设置线程最大数目:15个

      3. mmap  -- 设置共享内存大小 --- (1M-8K) 普通服务的大小

   2. getContextObject

      1. 创建一个BpBinder --- 客户端的对象

  1. interface_cast

   1. new BpServiceManager(new BpBinder) ==》 new Proxy(binder==BinderProxy)

   2. remote.transact -->远程调用  

   3. remote == BpBinder

  1. java 层 --- ServiceManager.addService

   1. new ServiceManagerProxy(new BinderProxy)

   2. mRemote == BinderProxy

   3. BinderProxy.mObject == BpBinder

   4. mRemote.transact == BpBinder.transact

服务的注册和获取,线程池管理

从java --- AMS

如何注册到SM中

getIServiceManager().addService(name, service, false);

  • getIServiceManager --- new ServiceManagerProxy(new BinderProxy())
    • ServiceManagerNative.asInterface(BinderInternal.getContextObject())
      • BinderInternal.getContextObject --- 返回 BinderProxy 对象
        • ProcessState::self()->getContextObject:创建一个BpBinder
        • javaObjectForIBinder -- BinderProxy 和 BpBinder 互相绑定
      • ServiceManagerNative.asInterface
        • 返回 ServiceManagerProxy
  • addService
    • data.writeStrongBinder(service); -- service == AMS --- 将AMS 放入 data中
    • mRemote.transact --- mRemote == BinderProxy
      • 获取BpBinder --- IPCThreadState::transact
        • 1.writeTransactionData --- out 写入命令 --write --- cmd == BC_TRANSACTION
        • 2.waitForResponse
          • talkWithDriver -- 非常重要 --- 代码非常长
            • binder_transaction
              • handle == 0 --》 sm
                1. target_node
                2. proc
                3. todo,wait
                4. 创建t,tcomplete,
                5. 数据拷贝
                6. binder_transaction_binder --> handle
                7. thread->transaction_stack = t; ---> 方便sm找到client
                8. t->work.type = BINDER_WORK_TRANSACTION; -- 给sm -- 做事
                9. tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; -- 给client--挂起
                10. wake_up_interruptible 唤醒sm
        • client挂起
          • BR_NOOP ,BR_TRANSACTION_COMPLETE
          • wait_event_freezable --- 挂起
        • sm处理添加服务
          • BINDER_WORK_TRANSACTION --- 要处理 cmd == BR_TRANSACTION
            1. reply初始化
            2. res = func(bs, txn, &msg, &reply); --- 函数指针 --- svcmgr_handler作用:获取或者添加 service
              1. sm是用 svclist 保存所有服务的
            3. binder_send_reply --- bc_reply
            4. t->work.type = BINDER_WORK_TRANSACTION; --- 给Client list_add_tail(&t->work.entry, target_list); tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; -- 给SM --- 被挂起 list_add_tail(&tcomplete->entry, &thread->todo);
            5. wake_up_interruptible(target_wait); -- 唤醒 Client
        • client 被唤醒
          • BINDER_WORK_TRANSACTION --- cmd = BR_REPLY;

SM 处理 onTransact

  • IPCThreadState::executeCommand

    • error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);

    • JavaBBinder.onTransact --- C++

    • jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, reinterpret_cast(&data), reinterpret_cast(reply), flags); -- Binder.java.execTransact 方法