美文网首页
Android-Binder

Android-Binder

作者: 写代码的阿毛 | 来源:发表于2020-02-19 22:24 被阅读0次

    概述

    • 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获取的问题;

    相关文章

      网友评论

          本文标题:Android-Binder

          本文链接:https://www.haomeiwen.com/subject/azbifhtx.html