概述
- 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;
- 找出 target_list 和 target_wait ,分别用于表示 todo 和 wait;
- 4.生成 binder_transaction 对象用于表示本次要进行的transaction,将其加入 target_list -> todo 中;
- 生成一个 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获取的问题;
网友评论