当前位置:操作系统 > 安卓/Android >>

Android之binder驱动个人学习小结

前言:
Read the fucking Source Code.
这段时间,大概花了两个星期(期间还偷懒了好几天),深入学习了一下Android的Binder驱动。话说上半年在看Mediaplay的源码时,就遇到过很多的IPC,当时也没有深入的去了解这块内容。这次为了对Android有一个系统级别的了解,所以较为深入的学习了一番。主要参考的内容包括:csdn的android 红人老罗,以及手里的一本杨丰盛的Android技术内幕(系统卷),作为主要的学习资料。当然我所小结的内容,也没有他们那么的详细,只是理清了整个思路而已。
注释:
SM:ServiceManager
MS:MediaPlayerService
xxx:指的是某种服务,入HelloService。
一.Binder驱动的整体架构
单从C++层宏观上看来,binder驱动的主要组成部分是:client(客户端),server(服务端),一个Service Manager和binder底层驱动。
整体的框图如下(摘自老罗的图):

其实从图中可以清晰的发现,在Android的应用层中Client和Server所谓的IPC,其实真正的工作均由底层的Binder驱动来完成。也就是说binder驱动可以完成进程间通信,这也是Android特点之一。Service Manager做为一个守护进程,主要来处理客户端的服务请求,管理所有的服务项。
 
二.binder底层驱动核心内容。
说到底,binder底层的驱动架构和通用的linux驱动没有区别,核心的内容包括binder_init,binder_open,binder_mmap,binder_ioctl.
binder驱动在Android系统中以miscdevice完成设备的注册,作为抽象设备,他没有直接操作硬件,只是完成了内存的拷贝处理。如果要深入理解这块机制,请参考老罗的android之旅。在这里对binder_ioctl做一定的分析:
2.1 驱动核心的操作数据结构:
binder_proc和binder_thread:
每open一个binder驱动(系统允许多个进程打开binder驱动),都会有一个专门的binder_proc管理当前进程的信息,包括进程的ID,当前进程由mmap所映射出的buffer信息,以及当前进程所允许的最大线程量。同时这个binder_proc会加入到系统的全局链表binder_procs中去,方便在不同进程之间可以查找信息。
binder_thread:在当前进程下存在多线程,因此binder驱动使用binder_thread来管理对应的线程信息,主要包括线程所属的binder_proc、当前状态looper以及一个transaction_stack(我的理解是负责着实际进程间通信交互的源头和目的地)。
binder_write_read :
[plain]
struct binder_write_read { 
    signed long write_size; /* bytes to write */ 
    signed long write_consumed; /* bytes consumed by driver */ 
    unsigned long   write_buffer; 
    signed long read_size;  /* bytes to read */ 
    signed long read_consumed;  /* bytes consumed by driver */ 
    unsigned long   read_buffer; 
}; 
在binder驱动中,以该结构体作为信息封装的中转(可以理解为内核和用户的连接)。在驱动中为根据write_size和read_size的大小来进行处理(见ioctl的解析部分),在write_buffer和read_buffer都代表着用户空间的buffer地址。在write_buffer中,由一个cmd和binder_transaction_data组成,cmd主要告知驱动当前所要处理的内容。
binder_transaction_data:
[plain]  
struct binder_transaction_data { 
    /* The first two are only used for bcTRANSACTION and brTRANSACTION, 
     * identifying the target and contents of the transaction. 
     */ 
    union { 
        size_t  handle; /* target descriptor of command transaction */ 
        void    *ptr;   /* target descriptor of return transaction */ 
    } target; 
    void        *cookie;    /* target object cookie */ 
    unsigned int    code;       /* transaction command */ 
 
    /* General information about the transaction. */ 
    unsigned int    flags; 
    pid_t       sender_pid; 
    uid_t       sender_euid; 
    size_t      data_size;  /* number of bytes of data */ 
    size_t      offsets_size;   /* number of bytes of offsets */ 
 
    /* If this transaction is inline, the data immediately 
     * follows here; otherwise, it ends with a pointer to 
     * the data buffer. 
     */ 
    union { 
        struct { 
            /* transaction data */ 
            const void  *buffer; 
            /* offsets from buffer to flat_binder_object structs */ 
            const void  *offsets; 
        } ptr; 
        uint8_t buf[8]; 
    } data; 
}; 
在这里,buffer和offsets分别代表传输内容的数据量以及Binder实体的偏移量(会遇到多个Binder实体)。
binder_transaction:该结构体主要C/S即请求进程和服务进程的相关信息,方便进程间通信,以及信息的调用
binder_work:理解为binder驱动中,进程所要处理的工作项。
binder_transactionbinder_transactionbinder_transactionbinder_transaction
2.2 binder驱动之ioctl解析:
和常用的ioctl相类似,在这里我们关注BINDER_WRITE_READ命令项的内容。
binder_thread_write和binder_thread_read会根据用户传入的write_size和read_size的有无来进行处理。在这里以Mediaplayservice和ServiceManager的通信来分析,调用的cmd如下:
MS首先传入cmd=BC_TRANSACTION:
调用binder_transaction:
[plain] 
static void binder_transaction(struct binder_proc *proc, 
                   struct binder_thread *thread, 
                   struct binder_transaction_data *tr, int reply) 

...else {//client请求service 
        if (tr->target.handle) {//SM时为target.handle=0 
            struct binder_ref *ref; 
            ref = binder_get_ref(proc, tr->target.handle); 
            if (ref == NULL) { 
                binder_user_error("binder: %d:%d got " 
                    "transaction to invalid handle\n", 
                    proc->pid, thread->pid); 
                return_error = BR_FAILED_REPLY; 
                goto err_invalid_target_handle; 
            } 
            target_node = ref->node; 补充:移动开发 , Android ,

CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,