Android-Binder

概述

  • Binder框架包括四部分:Binder驱动,ServiceManager,Client,Server;Binder驱动是整个Binder框架的核心,IPC就是通过Binder驱动来通信的;ServiceManager用来管理所有的Server,Client需要通过ServiceManger获取对应的服务器IBinder;Client相当于服务的调用方;Server相当于服务的接收方;
  • Binder系统框架


    ANDROID_Binder_Arch.jpg
  • 优点
    • 内存消耗小
    • 安全

原理

Binder驱动
  • Binder驱动是作为一个特殊的杂项设备存在,设备节点为/dev/binder,遵循Linux设备驱动模型,对应的设备为内存,运行于内核态;Binder驱动的主设备号为10(“杂项”驱动的主设备号统一为10),次设备号是每种设备独有的;
  • Binder驱动是一个标准的Linux驱动,Binder驱动运行于内核态,可以提供open,ioctl,mmap等常用的文件操作;
  • Binder驱动主要负责Binder的服务节点,调用Binder相关的处理线程,完成实际的Binder传输;
  • 每个进程只允许打开一次Binder设备,且制作一次内存映射,所有需要使用Binder驱动的线程共享这一资源;
Binder驱动的数据结构
  • Binder对象
    enum {
      BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
      BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
      BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
      BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
      BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', B_TYPE_LARGE), 
    };
    
    enum transaction_flags {
      TF_ONE_WAY = 0x01,
      TF_ROOT_OBJECT = 0x04,
      TF_STATUS_CODE = 0x08,
      TF_ACCEPT_FDS = 0x10,
    };
    
    struct flat_binder_object {
      unsigned long type;
      unsigned long flags;
      union {
        void *binder;
        signed long handle;
      };
      void *cookie;
    };
    
    • Binder对象是进程之间能够传递的对象,对应的是flat_binder_object结构体;type为Binder类型,如果Binder是本地对象,可以传递额外数据,存放在cookie中;flags表示事务flag;
    • Binder被分为5类:本地对象-BINDER_TYPE_BINDER 和 BINDER_TYPE_WEAK_BINDER,远程对象引用-BINDER_TYPE_HANDLE 和 BINDER_TYPE_WEAK_HANDLE 以及 文件-BINDER_TYPE_FD;
    • transaction_flag表示事务flag:TF_ONE_WAY表示单向传递;TF_ROOT_OBJECT表示内容为根对象,对应类型为本地对象;TF_STATUS_CODE表示内容为32位的状态码,对应类型为远程对应引用;TF_ACCEPT_FDS表示可以接收一个文件描述符,对应类型为文件;
  • binder_transaction_data
    struct binder_transaction_data {
      union {
        size_t handle;
        void *ptr;
      } target;
      void *cookie;
      unsigned int code;
      unsigned int flags;
      pid_t sender_pid;
      uid_t sender_euid;
      size_t data_size;
      size_t offsets_size;
      union {
        struct {
          const void *buffer;
          const void *offsets;
        } ptr;
        uint8_t buf[8];
      } data;
    };
    
    • 该结构体用来存储事务数据;
    • target是符合联合体对象,表示要处理此次事务的对象;handle是远程对象引用,根据handle,Binder驱动可以找到应该由哪个进程处理此事务,并分发给一个线程,而那个线程也正在执行ioctl的BINDER_WRITE_READ操作,即正在等待一个请求;ptr是本地对象,cookie为额外数据;handle和ptr之间的映射关系是Binder驱动中需要维护的;
    • code是一个命令,表示请求Binder对象执行的操作;flags表示事务flag,与上面flat_binder_object中的flags一样;
    • sender_pid和sender_euid表示事务请求的pid和uid;
    • data_size表示数据的大小字节数,offsets_size表示数据的偏移量字节数;
    • data表示真正的数据,ptr表示target->ptr对应的对象的数据,buf表示与handle对象对应的数据,data中的ptr中的buffer表示真实的数据,offsets表示其偏移量;
  • binder_transaction
    struct binder_transaction {
      int debug_id;
      struct binder_work work;
      struct binder_thread *from;
      struct binder_transaction *from_parent;
      struct binder_proc *to_proc;
      struct binder_thread *to_thread;
      struct binder_transaction *to_parent;
      unsigned need_reply : 1;
      struct binder_buffer *buffer;
      unsigned int code;
      unsigned int flags;
      long priority;
      long saved_priority;
      uid_t sender_euid;
    }
    
    struct binder_buffer {
      struct list_head entry;
      struct rb_node rb_node;
      unsigned free : 1;
      unsigned allow_user_free : 1;
      unsigned async_transaction ; 1;
      unsigned debug_id : 29;
      struct binder_transaction * transaction;
      struct binder_node *target_node;
      size_t data_size;
      size_t offsets_size;
      uint8_t data[0];
    }
    
    • 该结构体主要用来中转请求和返回结果,保存接收和要发送的进程信息;
    • work为一个binder_work;
    • from和to_thread都是binder_thread,表示要发送和接收的线程信息,to_proc表示接收的进程信息;
    • buffer是一个binder_buffer,表示缓冲区信息;
  • binder_work
    struct binder_work {
      struct list_head entry;
      enum {
        BINDER_WORK_TRANSACTION = 1,
        BINDER_WORK_TRANSACTION_COMPLETE,
        BINDER_WORK_NODE,
        BINDER_WORK_DEAD_BINDER,
        BINDER_WORK_DEAD_BINDER_AND_CLEAR,
        BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
      } type;
    };
    
    • entry为list_head,用来实现一个双向链表,存储所有binder_work的队列;enum类型的type,表示binder_work的类型;
  • binder_write_read
    struct binder_write_read {
      signed long write_size;
      signed long write_consumed;
      unsigned long write_buffer;
      signed long read_size;
      signed long read_consumed;
      unsigned long read_buffer;
    }
    
    #defin BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
    
    • Binder驱动找到处理此次事务的进程之后,把需要处理的事务放在读缓冲区中,返回给服务线程,服务线程执行指定命令的操作;处理请求的线程把数据交给合适的对象来执行预定操作,然后把结果同样用binder_transaction_data结构封装,以写命令的方式回传给Binder驱动,这样就完成了一次通信;
    • BINDER_WRITE_READ操作的参数就是binder_write_read结构体,该结构体就是读写缓冲区,用来存储发送的任务信息和接收返回的结果信息;
    • 分别指定了读写缓冲区;对于写操作,write_buffer包含了一系列请求线程执行的Binder命令,write_size表示写入的数据的大小,write_consumed表示被消耗的写数据;对于读操作,read_buffer包含了一系列线程执行后填充的返回值,read_size表示读取的数据的大小,read_consumed表示被消耗的读数据的大小;
    //BINDER_WRITE_READ的写操作命令协议
    enum BinderDriverCommandProtocol {
      BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
      BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
    
      BC_ACQUIRE_RESULT = _IOW('c', 2, int),
      BC_FREE_BUFFER = _IOW('c', 3, int),
      BC_INCREFS = _IOW('c', 4, int), 
      BC_ACQUIRE = _IOW('c', 5, int),
      BC_RELEASE = _IOW('c', 6, int),
      BC_DECREFS = _IOW('c', 7, int),
      BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
      BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
      BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
      BC_REGISTER_LOOPER = _IO('c', 11),
      BC_ENTER_LOOPER = _IO('c', 12),
      BC_EXIT_LOOPER = _IO('c', 13),
      BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie),
      BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie),
      BC_DEAD_BINDER_DONE = _IOW('c', 16, void *),
    }
    
    //BINDER_WRITE_READ 的读操作命令协议
    enum BinderDriverReturnProtocol {
      BR_ERROR = _IOR('r', 0, int),
      BR_OK = _IO('r', 1),
      BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
      BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
      BR_ACQUIRE_RESULT = _IOR('r', 4, int),
      BR_DEAD_REPLY = _IOR('r', 5),
      BR_TRANSACTION_COMPLETE = _IO('r', 6),
      BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
      BR_ACQUIRE = _IOR('r', 8, strcut binder_ptr_cookie),
      BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
      BR_DECREFS = _IOR('r', 10, strcut binder_ptr_cookie),
      BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct, binder_pri_ptr_cookie),
      BR_NOOP = _IO('r', 12),
      BR_SPAWN_LOOPER = _IO('r', 13),
      BR_FINISHED = _IO('r', 14),
      BR_DEAD_BINDER = _IOR('r', 15, void *),
      BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *),
      BR_FAILED_REPLY = _IO('r', 17),
    }
    
    • 读写操作是相对于Binder驱动的;
    • 最重要的就是BC_TRANSACTION和BC_REPLY命令;
  • binder_node
    struct binder_node {
      int debug_id;
      struct binder_work work;
      union {
        struct rb_node rb_node;
        struct hlist_node dead_node;
      };
      struct binder_proc *proc;
      struct hlist_head refs;
      int internal_strong_refs;
      int local_weak_refs;
      int local_strong_refs;
      void __user *ptr;
      void __user **cookie;
      unsigned has_strong_ref : 1;
      unsigned pending_strong_ref : 1;
      unsigned has_weak_ref : 1;
      unsigned pending_weak_ref : 1;
      unsigned has_async_transaction : 1;
      unsigned accept_fds : 1;
      int min_priority : 8;
      struct list_head async_todo;
    };
    
    • 该结构体表示一个Binder节点;
  • binder_thread
    struct binder_thread {
      struct binder_proc *proc;
      struct rb_node rb_node;
      int pid;
      int looper;
      struct binder_transaction *transaction_stack;
      struct list_head todo;
      uint32_t return_error;
      uint32_t return_error2;
      wait_queue_head_t wait;
      struct binder_stats stats;
    }
    
    enum {
      BINDER_LOOPER_STATE_REGISTERED = 0x01,
      BINDER_LOOPER_STATE_ENTERED = 0x02,
      BINDER_LOOPER_STATE_EXITED = 0x04,
      BINDER_LOOPER_STATE_INVALID = 0x08,
      BINDER_LOOPER_STATE_WAITING = 0x10,
      BINDER_LOOPER_STATE_NEED_RETURN = 0x20
    };
    
    struct binder_stats {
      int br[_IOC_NR(BR_FAILED_REPLY) + 1];
      int bc[_IOC_NR(BC_DEAD_BINDER_DONE) + 1];
      int obj_created[BINDER_STAT_COUNT];
      int obj_deleted[BINDER_STAT_COUNT];
    }
    
    • 该结构体用于存储一个单独的线程的信息;
    • proc表示所属进程;
    • rb_node是一个红黑树节点;
    • pid表示线程的pid;looper表示线程的状态信息,包括注册,进入,退出,销毁,需要返回等;
    • transaction_stack表示接收和发送的进程和线程信息;
    • todo是一个双向链表;
    • return_error和return_error2表示返回的错误信息码;
    • wait表示等待队列头;
    • stats表示Binder状态信息;
  • binder_proc
    struc binder_proc {
      //双向链表
      struct hlist_node proc_node; 
      //线程队列,双向链表,所有的线程信息;
      struct rb_root threads;
      struct rb_root nodes;
      struct rb_root refs_by_desc;
      struct rb_root refs_by_node;
      //进程ID
      int pid;
      struct vm_area_struct *vma;
      struct task_struct *tsk;
      struct files_struct *files;
      struct hlist_node deferred_work_node;
      int deferred_work;
      void *buffer;
      ptrdiff_t user_buffer_offset;
    
      struct list_head buffers;
      struct rb_root free_buffers;
      struct rb_root allocated_buffers;
      size_t free_async_space;
    
      struct page ** pages;
      size_t buffer_size;
      uint32_t buffer_free;
      struct list_head todo;
      //等待队列
      wait_queue_head_t wait;
      //Binder状态
      struct binder_stats stats;
      struct list_head delivered_death;
      //最大线程
      int max_threads;
      int requested_threads;
      int requested_threads_started;
      int ready_threads;
      //默认优先级
      long default_priority;
    };
    
    • 该结构体用于保存调用Binder的各个进程和线程的信息;
    • buffer 表示 mmap 内存映射的地址;
Binder驱动的函数
  • binder_init
    static int _init binder_init(void) {
      int ret;
      //创建文件系统根节点
      binder_proc_dir_entry_root = proc_mkdir("binder", NULL);
      //创建proc节点
      if(binder_proc_dir_entry_root)
        binder_proc_dir_entry_proc = proc_mkdir("proc", binder_proc_dir_entry_root);
      //注册Misc设备
      ret = misc_register(&binder_miscdev);
      if (binder_proc_dir_entry_root) {
        create_proc_read_entry("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL);
        create_proc_read_entry("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL);
        create_proc_read_entry("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL);
        create_proc_read_entry("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log);
        create_proc_read_entry("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_failed);
      }
      return ret;
    }
    device_initcall(binder_init);
    
    • 初始化函数一般需要设备驱动接口来调用;module_init和module_exit是为了同时兼容支持静态编译的驱动模块(buildin)和动态编译的驱动模块(module);Binder选择用device_initcall的目的就是不让Binder驱动支持动态编译;
    • /proc目录用于存储全局的,只存在于内存中的文件系统;
    • 1.使用proc_mkdir创建了一个Binder的proc文件系统的根节点(/proc/binder);
    • 2.根节点(/proc/binder)创建成功后,再创建binder proc节点(/proc/binder/proc);
    • 3.使用misc_register把自己注册为一个Misc设备,其设备节点位于/dev/binder;
    • 4.最后调用create_proc_read_entry创建以下只读proc文件,同时也指定了操作这些文件的函数及其参数
      • /proc/binder/state
      • /proc/binder/stats
      • proc/binder/transactions
      • /proc/binder/transaction_log
      • /proc/binder/failed_transaction_log
    • Binder驱动还需要填写 file_operations 结构体
      static const struct file_operations binder_fops = {
        .owner = THIS_MODULE,
        .poll = binder_poll,
        .unlocked_ioctl = binder_ioctl,
        .mmap = binder_mmap,
        .open = binder_open,
        .flush = binder_flush,
        .release = binder_release,
      };
      
      • 由此可见,Binder驱动总共为上层提供了6个接口;
  • binder_open
    static int binder_open(struct inode *nodp, struct file *filp) {
      //为binder_proc分配空间
      struct binder_proc *proc;
      proc = kzalloc(size(*proc), GFP_KERNEL);
    
      //初始化binder_proc队列
      INIT_LIST_HEAD(&proc->tod);
      init_waitqueue_head(&proc->wait);
      
      //添加到binder_proc哈希表
      hlist_add_head(&proc->proc_node, &binder_procs);
      //
      proc->pid = current -> group_leader -> pid;
      INIT_LIST_HEAD(&proc -> delivered_death);
      //创建只读文件 /proc/binder/proc/$pid
      if (binder_proc_dir_entry_proc) {
        char strbuf[11];
        snprintf(strbuf, sizeof(strbuf), "%u", proc -> pid)
        create_proc_read_entry(strbuf, S_IRUGO, binder_proc_dir_entry_proc, binder_read_proc_proc, proc);
      }
      return 0;
    }
    
    • 上层进程在访问Binder驱动时,首先需要打开 /dev/binder 节点;
    • 1.分配一个binder_proc来保存数据;
    • 2.初始化binder_proc队列,包括todo,wait队列;
    • 3.将binder_proc添加到哈希表中,任何一个进程都可以访问到其他进程的binder_proc对象;
    • 4.在binder proc目录中创建只读文件 /proc/binder/proc/$pid;
    • 用户对 Binder 设备的操作,都是基于 binder_proc 实体;
  • binder_release
    static int binder_release(struct inode *nodp, struct file *filp) {
      struct binder_proc *proc = filp -> private_data;
      remove_proc_entry(strbuf, binder_proc_dir_entry_proc);
      binder_defer_work(proc, BINDER_DEFERRED_RELEASE);
    }
    
    • 1.找到当前进程的pid;
    • 2.删除pid对应的binder proc只读文件;
    • 3.释放binder_proc对象的数据和分配的空间;
  • binder_poll
    static unsigned int binder_poll(struct file *filp, struct poll_table_struct *wait) {
      struct binder_proc *proc = filp -> private_data;
      struct binder_thread *thread = NULL;
      int wait_for_proc_work;
      //得到当前进程的信息
      thread = binder_get_thread(proc);
      wait_for_proc_work = thread -> transaction_stack == NULL && list_empty(&thread -> todo) && thread -> return_error == BR_OK;
      if(wait_for_proc_work) { //proc_work方式
        if (binder_has_proc_work(proc, thread))
          return POLLIN;
        poll_wait(filp, &proc -> wait, wait);
        if (binder_has_proc_work(proc, thread))
          return POLLIN;
      } else { //thread_work方式
        if (binder_has_thread_work(thread))
          return POLLIN:
        poll_wait(filp, &thread -> wait, wait);
        if (binder_has_thread_work(thread))
          return POLLIN;
      }
      return 0;
    }
    
    • poll函数是非阻塞性IO的内核驱动实现,所有支持非阻塞IO操作的设备驱动都需要实现poll函数;Binder的poll函数仅支持设备是否可以非阻塞的读(POLLIN),这里又两种等待任务:一种是proc_work,另一种是thread_work;
    • 1.获取当前进程/线程的信息;
    • 2.通过检测线程队列是否为空,线程的循环状态以及返回信息来判断所要采用的等待方式;
    • 3.通过调用 poll_wait 函数来实现 poll 操作;
  • binder_mmap
    • mmap(memory map)用于把设备内存映射到用户程序的内存空间中,这样就可以像操作用户内存那样操作设备内存;
    • Binder设备对内存映射是有限制的,Binder设备最大能映射4MB的内存区域,Binder不能映射具有写权限的内存区域等;
    • Binder的设备内存是在mmap操作时分配的;分配的方法是:现在内核虚拟映射表上获取一个可以使用的区域,然后分配物理页,并把物理页映射到获取的虚拟空间上,分配到的地址赋值个 binder_proc -> buffer;由于设备内存是在mmap操作中实现的,因此每个进程/线程只能执行一次映射操作;
  • binder_ioctl
    #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
    #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, int64_t)
    #define BINDER_SET_MAX_THREADS _IOW('b', 5, size_t)
    #define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int)
    #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int)
    #define BINDER_THREAD_EXIT _IOW('b', 8, int)
    #define BINDER_VERSION _IOWR('b', 9, struct binder_version)
    
    • ioctl是设备驱动程序中对设备I/O通道进行管理的函数;
    • binder_ioctl 是 Binder最核心的部分,Binder的功能就是通过ioctl命令来实现的;binder_ioctl命令有7个;
    • BINDER_SET_MAX_THREADS 用于设置进程的Binder对象的最大线程数目;
    • BINDER_THREAD_EXIT 用于终止并释放 binder_thread 对象及其 binder_transaction 事务;
    • BINDER_SET_CONTEXT_MGR 被ServiceManager用于设置自己为 Context Manager 节点;该命令在初始化Binder驱动的过程中被调用;
    • BINDER_WRITE_READ
        struct binder_write_read bwr;
        //检查数据完整性
        if (size != sizeof(struct binder_write_read))  {
          ret = -EINVAL;
          goto err;
        }
        //从用户空间复制数据  
        if (copy_form_user(&bwr, ubuf, sizeof(bwr))) {
          ret = -EFFAULT;
          goto err;
        }
        //执行写操作
        if (bwr.write_size > 0) {
          ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
          if (ret < 0) {
            bwr.read_consumed = 0;
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
              ret = -EFAULT;
            goto err;
          }
        }
        //执行读操作
        if (bwr.read_size > 0) {
          ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, flag -> f_flag & O_NONBLOCK);
          if (!list_empty(&proc -> todo)) 
            wake_up_interruptible(&proc -> wait);
          if (ret < 0) {
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
              ret = -EFAULT;
            goto err;
          }
        }
        //将数据复制到用户空间
        if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
          ret = -EFAULT;
          goto err;
        }
      
      • 1.检查其数据是否完整;
      • 2.从用户空间复制数据到binder_write_read结构体中;
      • 3.通过write_size和read_size判断需要执行的读写操作;
      • 4.处理完之后再将数据复制到用户空间;
BinderAdapter
  • BinderAdapter是对Binder驱动的封装,用于完成Binder库与Binder驱动的交互;包括ProcessState和IPCThreadState;
  • ProcessState
    • 每个进程只有一个ProcessState对象,在创建ProcessState对象时,利用open_binder打开Linux设备/dev/binder,并且映射了内存空间,通过ioctrl建立基本的通信框架;
    • ProcessState维护当前进程的所有服务代理(BpBinder);
    • ProcessState维护了一个线程池;
  • IPCThreadState
    • 每个线程都会有一个IPCThreadState对象,主要负责Binder数据读取,写入和请求处理框架;
    • IPCThreadState保存在TLS中;
    • 所有关于Binder的操作都放置在IPCThreadState中;几个重要函数有:
      • talkWithDriver:读取/写入
      • executeCommand:请求处理
      • joinThreadPool:循环结构
    • talkWithDriver
      • talkWithDriver用来与Binder驱动交互的,在调用之前数据都已封装好;
      • 对于BC_TRANSACTION的处理流程:
        • 1.根据 target_handel 取得目标对象所对应的 target_node ;
        • 2.找出目标对象的 target_proc 和 target_thread;
          1. 找出 target_list 和 target_wait ,分别用于表示 todo 和 wait;
        • 4.生成 binder_transaction 对象用于表示本次要进行的transaction,将其加入 target_list -> todo 中;
          1. 生成一个 binder_work对象用于说明当前调用者线程有一个未完成的transaction,天机到本线程的todo队列;
        • 6.填写 binder_transaction 数据;
        • 7.申请到 buffer 内存后,从用户空间把数据赋值过来,因为buffer所指向的内存空间和目标对象是共享的,所以只需要一次复制就把数据从Binder Client 复制到 Binder Server中;
      • 8.如果需要的话,唤醒目标对象;
      • 9.调用者线程最终将进入等待;
      • 10.目标线程检查自己的todo队列是否有要处理的事项,读取数据,处理数据,然后把结果写入Binder驱动;
IBinder/BpBinder/BBinder
  • IBinder
    • IBinder是对跨进程对象的抽象,在C/C++和Java层都有定义;
    • IBinder可以指向本地对象,也可以指向远程对象,关键在于IBinder接口中的transact函数的实现;
  • BpBinder
    status_t BpBinder::transact (uint32_t code, const Parcel& data, Parcel& reply, uint32_t flags) {
      if (mAlive) {
        status_t status = IPCThreadState::self() -> transact(mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
      }
      return DEAD_OBJECT;
    }
    
    • BpBinder是服务端代理对象,即远程对象在当前进程的代理;实现了IBinder接口;
    • transact方法是同步方法,会挂起客户进程的当前线程,直到Server把请求处理完成并返回结果;
  • BBinder
    status_t BBinder::transact(uint32_t code, const Parcel& data, Parcel& reply, uint32_t flags) {
      data.setDataPosition(0);
      status_t err = NO_ERROR;
      switch (code) {
        case PING_TRANSACTION:
          reply -> writeInt32(pingBinder());
          break;
        default:
          err = onTransact(code, data, reply, flags);
          break;
      }
      if (reply != NULL) {
        reply -> setDataPosition(0);
      }
      return err;
    }
    
    • BBinder同样实现了IBinder;transact直接调用onTransact;
    • 服务端Binder对象要确保线程安全;
Parcel
  • Parcel的主要实现是C/C++层,Java层也有该类,但是对象实际是指向了C/C++层的对象,API大部分是native方法;
  • Parcel只是对数据进行打包整理,真正传送数据是在调用 transact 方法时;
  • Parcel支持传送的数据类型有:基本类型,String,Parcelable,Binder,FD及对应的数组类型;
ServiceManager
  • svcinfo表示一个服务,ServiceManager维护了一个全局链表-svclist;
  • 启动
    service servicemanager /system/bin/servicemanager
      class core
      user system
      group system
      critical
      onrestart restart zygote
      onrestart restart media
      onrestart restart surfaceflinger
      onrestart restart drm
    
    • 以上是 init.rc 文件中的,如果servicemanager发生问题重启,其他系统服务zygote,media,surfaceflinger和drm也会被重新加载;
    • 在Android系统启动时,会有一个runtime进程用来执行ServiceManager的相关逻辑,ServiceManager会打开Binder驱动,映射128K内存空间,并把自己设置为ContextManager,进入循环状态等待客户端的请求,然后通知Zygote启动SystemServer进程,进行有名Service注册;
    int main(int argc, char **argv) {
      struct binder_state *bs;
      void *svcmgr = BINDER_SERVICE_MANAGER;
      bs = binder_open(128 * 1024);
      if (binder_become_context_manager(bs)) {
        return -1;
      }
      svcmgr_handle = svcmgr;
      binder_loop(bs, svcmgr_handler);
    }
    
    struct binder_state *binder_open(unsigned mapsize) {
      struct binder_state *bs; //记录了SM中有关于Binder的所有信息;
      bs = malloc(sizeof(*bs));
      bs -> fd = open("/dev/binder", O_RDWR); //打开Binder设备节点;
      bs -> mapsize = mapsize;
      bs -> mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fs -> fd, 0);
      return bs;
    }
    
    • 打开Binder设备,并映射了128K的内从空间;
    int binder_become_context_manager(struct binder_state *bs) {
      return ioctl(bs -> fd, BINDER_SET_CONTEXT_MGR, 0);
    }
    
    • ServiceManager把自己设置为ContextManager;
    void binder_loop(struct binder_state *bs, binder_handler func) {
      int res;
      struct binder_write_read bwr; //执行BINDER_WRITE_READ命令所需的数据格式
      unsigned readbuf[32]; //一次读取容量
      bwr.write_size = 0;
      bwr.write_consumed = 0;
      bwr.write_buffer = 0;
      readbuf[0] = BC_ENTER_LOOPER; //命令
      binder_write(bs, readbuf, sizeof(unsigned));
      for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;
        res = ioctl(bs -> fd, BINDER_WRITE_READ, &bwr);
        ...
        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
        
      }
    }
    
    • 1.进入循环前,先告知Binder驱动这一状态变化;
    • 2.通过BINDER_WRITE_READ命令从Binder驱动读取消息;
    • 3.通过binder_parse处理消息;
  • 注册
    • 根据svclist查询是否已经注册该服务,没有的话,则新建svcinfo,并添加到svclist中;
  • 查询
    • 在svclist中查询;

扩展

AIDL
  • AIDL解决了数据读写顺序一致的问题;
bindService
  • bindService解决了IBinder获取的问题;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,200评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,526评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,321评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,601评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,446评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,345评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,753评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,405评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,712评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,743评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,529评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,369评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,770评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,026评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,301评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,732评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,927评论 2 336

推荐阅读更多精彩内容