免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1197 | 回复: 0
打印 上一主题 下一主题

Android110215: Android binder driver的简记 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-02-15 18:17 |只看该作者 |倒序浏览
Android110215:Android binder driver的简记


Email:    zcatt@163.com
Blog    http://zcatt.cublog.cn

 
内容提要
文档简要整理binder driver的内容。以供备忘和参考。



声明
仅限学习交流,禁止商业用途。转载需注明出处。


版本记录
Date        Ver        Note
2011-02-15    0.1        Draft.  zcatt, Beijing
 
 
1.    缘起
  Binder是android提供的IPC, 由driver, framework, jni,和相应java程序组成. 其中binder driver是实现这个IPC的基石.这里简记了binder driver的分析.

2.    binder driver的轮廓
  binder driver基本组成如下, 其中重要的两个方法是open和ioctl. open完成设备的打开. ioctl完成IPC的具体通信, 定义了几条命令,最常用的命令是BINDER_WRITE_READ和BINDER_SET_CONTEXT_MGR. 这里将备忘open和ioctl的BINDER_WRITE_READ和BINDER_SET_CONTEXT_MGR。

        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,
        };

        static struct miscdevice binder_miscdev = {
            .minor = MISC_DYNAMIC_MINOR,
            .name = "binder",
            .fops = &binder_fops
        };
   
  本质上binder driver就是一块共享内存, 发送者进程发送数据到driver, 接收者从driver接收数据.这种机制属于c/s模型. c发送请求数据, 阻塞等待s的回应, s阻塞在读driver上, 如果有数据, 则处理, 然后将结果发回c, 继续阻塞读driver.
  app使用binder driver的方式是这样的, 每次传送称作一次write_read操作. 这样一次操作的参数中包括两部分: 1)write data, 需要传出的数据; 2)read data, 容纳读入数据的空间. 也就是每次传送实际有两个操作, 先写操作, 后读操作.如果write data为空, 则忽略写操作;read data大小为0, 则忽略读操作.
  为了方便表述, 数据的发送者进程/线程我们称为源,接收者进程/线程称为宿.在driver中, 每个进程/线程都有一个数据链表, 其它进程/线程发过来的数据都将先挂接到这个数据链表上等待处理. binder driver的read_write简要算法如下:

            write_read(writeData, readData)
            {
                if (writeData != null)
                {
                    wnode = new node(writeData);
                    append wnode to 宿.todoList;
                    wakeup(宿.wait);
                }

                if (readData != null)
                {
                    waitOn(当前.wait);
                    while(1)
                    {
                        rnode = detachNodeFrom(当前.todoList);
                        readData += dataIn(rnode);
                    }
                }
            }

  首先,writeData会被挂到宿的数据链表上,将来宿进程/线程会处理, 然后wakeup宿进程/线程的信号量. 接下来处理读操作. 阻塞(waitOn)在当前进程/线程的型号量, 随后从自己的数据链表上摘下其它进程/线程发过来的数据, 放入readData.

3.    proc和log
  binder driver提供了proc项, 如下
        /proc/binder/
            failed_transaction_log
            transaction_log
            transactions
            stats
            state
            proc/

           
4.    主要数据结构
  binder_proc结构代表的是进程相关的信息, 存放在filp->private_data. 使用binder driver的每个进程都有自己的binder_proc实例. 依赖于进程的数据都存放到binder_proc或能由此追溯到. 使用binder driver的所有binder_proc实例都链接到链表binder_procs中.

        struct 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;
            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;
            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;
        };

      .threads    进程中所有的线程。一个进程允许多进程。
      .nodes    进程中所有的binder_node实例. 关于binder_node后文介绍.
      .refs_by_desc    进程中指向binder_node的binder_ref实例, 这些实例的desc是当前进程中累加指定的.
      .refs_by_node 进程中指向binder_node的binder_ref实例。实际同.refs_by_desc。
      .todo        进程中的binder_work链表。WRITE_READ操作的read操作时应该处理的工作。
      .wait        进程的信号量。其它进程/线程向一进程.todo加入工作后,应当wakeup这个进程的.todo,唤醒这个进程的read操作,执行读取操作。

  binder_thread结构代表的是线程相关的信息。唯一标识thread的是pid。

          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; /* Write failed, return error code in read buf */
            uint32_t return_error2; /* Write failed, return error code in read */
                /* buffer. Used when sending a reply to a dead process that */
                /* we are also waiting on */
            wait_queue_head_t wait;
            struct binder_stats stats;
        };

    .*proc        所属进程的binder_proc。
    .rb_node    用于binder_proc.threads。
    .*transaction_stack    链表,node是线程发起的binder_transaction实例。
    .todo        线程中的binder_work链表。
    .wait        线程的信号量。其它进程/线程向一进程.todo加入工作后,应当wakeup这个线程的.todo,唤醒这个线程的read操作,执行读取操作。

  binder_work是一个链表的node结构。WRITE_READ操作中的write操作处理完writeData后会根据data的信息将工作分成不同的种类,也就是binder_work.type,然后加入到宿进程/线程的todo链表中。宿进程/线程执行read操作时根据binder_work.type进行不同的处理。binder_node, binder_ref_death, binder_transaction是binder_work的扩展结构。各种类型和binder_work及扩展结构的对应关系如下
    binder_work: BINDER_WORK_NODE, BINDER_WORK_TRANSACTION_COMPLETE
    binder_node: BINDER_WORK_NODE
    binder_ref_death: BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, BINDER_WORK_CLEAR_DEATH_NOTIFICATION
    binder_transaction: BINDER_WORK_TRANSACTION


        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;
        }; 

5.    open
  binder_open完成设备的打开操作,算法如下
        binder_open(*filp)
        {
            struct binder_proc *proc;

            proc = kzalloc();
            初始化各参数;
            proc加入到链表binder_procs中
            filp->private_data = proc;
            在/proc/binder/proc下创建以pid为名的file entry.
        }


6.    ioctl
  binder driver的具体操作是通过ioctl扩展命令的方式达到的。binder ioctl实现了几条命令,重要的当属BINDER_SET_CONTEXT_MGR和BINDER_WRITE_READ,这里分别记述。

6.1    BINDER_SET_CONTEXT_MGR
  虽然一般多个进程/线程同时使用,但binder driver有唯一一个线程称作binder driver的context mgr,使用静态变量binder_context_mgr_node存储。context mgr特殊的地方在于,往handle=0上发的所有数据都是发到context mgr的。android中, context mgr负责service的登记和查询工作。
 
            case BINDER_SET_CONTEXT_MGR:
                ... ... ...
                binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
                ... ... ...
                break;

6.2    BINDER_WRITE_READ
  IPC的通信操作最终靠的是这个命令。前面已经描述了它的基本算法。源码中可以参看binder_thread_write()和binder_thread_read()。

7.    HANDLE type和BINDER type
  Binder object做为对象IPC传递时binder driver有特别的处理。A进程中本地实现了BBinder的服务,如何将这个Binder obj传递到B进程,B进程才能使用? 显然直接传递obj的指针是不行的,因为两个进程各有自己的地址空间,并不能直接的互相引用。解决的办法是使用BpInterface, 也就是说Binder driver不会传给B进程obj,而是传给一个obj的引用ref. B进程拿到这个ref后,生成相应的BpInterface。在binder driver自己的数据结构中,这个ref就唯一对应了binder obj,当收到发往ref的数据时,driver就把数据发往这个obj。
  binder obj和ref的关系是1对n的关系。
  下面的源码可以参照
        binder_transaction() @ driver/binder.c
        writeStrongBinder() @ parcel.cpp
        IInterface.h

 




Locations of visitors to this page
 
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP