zoukankan      html  css  js  c++  java
  • Android系统--Binder系统具体框架分析(二)Binder驱动情景分析

    Android系统--Binder系统具体框架分析(二)Binder驱动情景分析

    1. Binder驱动情景分析

    1.1 进程间通信三要素

    • 目的:handle表示“服务”,即向实现该“服务”的进程发送数据;handle是“服务”的引用

    int binder_call(struct binder_state *bs, struct binder_io *msg, struct binder_io *reply,   uint32_t target, uint32_t code)
    
     // bs:驱动信息
    
     // msg:含有服务的名字
    
     // reply:它会含有回复的数据
    
     // target:表示目的
    
     // code:调用的函数
    
    • 数据

    1.2 handle的深入剖析

    1.2.1 涉及handle的重要结构体

    • Binder中的handle:进程A对进程B提供的服务S的引用

      • 引用:通过struct binder_ref结构体关联服务节点
    struct binder_ref {//就是 refs_by_desc、refs_by_node 这两个引用树种的数据结构.
    
    	int debug_id;
    
    	struct rb_node rb_node_desc;//连接des的引用树.
    
    	struct rb_node rb_node_node;//连接node的引用树.
    
    	struct hlist_node node_entry;
    
    	struct binder_proc *proc; //该binder引用所属的进程,
    
    	struct binder_node *node;//和远程的binder实体binder_node关联的地方.相对应.
    
    	uint32_t desc;
    
    	int strong;
    
    	int weak;
    
    	struct binder_ref_death *death;
    
    };	    
    
    • 服务:创建binder_node服务节点,指向进程B
    
    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;  
    
    };
    
    
    • 进程B:用结构体struct binder_proc表示
    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; //进程的id.
    
    	struct vm_area_struct *vma;
    
    	struct mm_struct *vma_vm_mm;
    
    	struct task_struct *tsk;
    
    	struct files_struct *files;
    
    	struct hlist_node deferred_work_node;
    
    	int deferred_work;
    
    	void *buffer;//表示要映射的物理内存在内核空间中的起始位置
    
        //内核使用的虚拟地址与进程使用的虚拟地址之间的差值,即如果某个物理页面在内核空间中对应的虚拟地址是addr的话,
    
       //那么这个物理页面在进程空间对应的虚拟地址就为addr + user_buffer_offset
    
    	ptrdiff_t user_buffer_offset; 
    
                                    
    
    	struct list_head buffers;//通过mmap映射的内存空间.
    
    	struct rb_root free_buffers;//空闲的binder_buffer通过成员变量rb_node连入到struct binder_proc中的free_buffers表示的红黑树中去,
    
    	struct rb_root allocated_buffers;//正在使用的binder_buffer通过成员变量rb_node连入到struct binder_proc中的allocated_buffers表                                        示的红黑树中去。
    
    	size_t free_async_space;
    
     
    
    	struct page **pages;// struct page 用来描述物理页面的数据结构
    
    	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;
    
    	struct dentry *debugfs_entry;
    
    };
    
    
    • 真实场景中有多个客户端服务对进程B要求服务,进程B创建多个线程提供服务,用struct rb_root结构体(红黑树)管理线程,线程用struct binder_thread描述
    
    struct binder_thread {
    
    	struct binder_proc *proc; //当前线程所属的进程。
    
    	struct rb_node rb_node; //来连入binder_proc的threads红黑树.
    
    	int pid;
    
    	int looper;//表示线程的状态  就是上面enum的类型。
    
    	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; //用来保存一些统计信息
    
    };
    
    

    1.2.2 解析handle对Binder节点操作流程

    (1)server传入一个flat_binder_object结构体给驱动,在内核态驱动里为每一个服务创建binder_node,biner_node.proc关联描述进程的结构体

    (2)ServiceManager 在驱动中创建binder_ref结构体,引用binder_node服务节点

    • 在用户态创建服务链表(name,handle)

    • binder_ref.desc关联handle

    (3)client向ServiceManager传入name查询对应服务

    (4)servicemanager返回hanle给驱动程序

    (5)驱动程序在servicemanager的binder_ref红黑树中根据handle找到binder_ref结构体,在根据binder_ref.node找到binder_node结构体,最后为client创建新的binder_ref,并关联找到的binder_node节点,他的结构体成员desc从1开始,驱动返回的desc给client,即为handle。

    (6)总结client如何得到hanled:驱动根据handle找到binder_ref结构体->binder_node->进程server

    1.3 client与server数据传输过程

    • client端(先读后写)

    (1)client构造数据,调用ioctl发送数据

    (2)驱动根据handle找到server进程

    (3)将数据存入进程的binder_proc.todo

    (4)等待唤醒(等待server传回数据)

    (5)被唤醒

    (6)从todo链表中取出数据,返回用户空间

    • server端(先写后读)

    (1)等待数据传入,休眠

    (2)client有数据写入,唤醒

    (3)从binder_proc.todo链表当中取出数据,返回用户空间

    (4)进行数据处理

    (5)将结果写给client,也是放入client中的binder_proc.todo

    (6)唤醒client

    1.4 数据复制详解

    • 一般方法(需要两次)

    (1)client构造数据

    (2)client:copy_from_user

    (3)server:copy_to_user

    (4)用户态处理

    • Binder方法(一次)

    (1)server mmap:用户态可以直接访问驱动中的某块内存

    (2)client构造数据:copy_from_user,存放在server mmap映射的内存

    (3)server直接获取使用数据

    • 描述一段通过mmap映射的内存空间--结构体binder_buffer来描述
    
    struct binder_buffer {
    
    	struct list_head entry; //连入 binder_proc的buffers
    
        //空闲的binder_buffer通过成员变量rb_node连入到binder_proc中的free_buffers表示的红黑树中.
    
        //正在使用的binder_buffer通过成员变量rb_node连入到binder_proc中的allocated_buffers表示的红黑树中去。
    
    	struct rb_node rb_node;		
    
    	unsigned free:1; //每一个binder_buffer又分为正在使用的和空闲的,通过free成员变量来区分.
    
    	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];
    
    };
    
    
    注:一次数据复制是针对传输数据,其binder_write_read还是需要两次复制。client调用ioctl发送数据,ioctl发送的是binder_write_read结构,其结构体中的成员指向传送数据。

    1.5 改进binder分析一代码

    • 注册服务,直接将函数作为指针注册
    
    /* add service */	
    
    ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler);
    
    //注册    
    
    if (ret) {
    
          fprintf(stderr, "failed to publish hello service
    ");
    
          return -1;
    
    }	
    
    ret = svcmgr_publish(bs, svcmgr, "goodbye", goodbye_service_handler);
    
    if (ret) {
    
          fprintf(stderr, "failed to publish goodbye service
    ");
    
    }
    
    
    • 将被调用函数指向handler,返回handler函数
    
    int test_server_handler(struct binder_state *bs,struct binder_transaction_data *txn,struct binder_io *msg, struct binder_io *reply)
    
    {	
    
        int (*handler)(struct binder_state *bs,struct binder_transaction_data *txn,struct binder_io *msg,struct binder_io *reply);  //构造处理方法	
    
        handler = (int (*)(struct binder_state *bs,struct binder_transaction_data *txn,struct binder_io *msg,struct binder_io *reply))txn->target.ptr;  //根据txn->target.ptr返回处理相应方法		
    
        return handler(bs, txn, msg, reply);  //返回所调用的处理方法
    
    }
    
    
  • 相关阅读:
    教你在Linux用飞信(fetion)免费发短信
    date 和 hwclock 命令 (RTC用的着)
    同学会催生“恐聚族” 攀比成风成为炫耀展示会
    35款基于terminal的Linux应用
    探访山东各地旱情 田里麦苗用手一搓成粉末
    多城市近期将出台楼市限购细则 全面限购第三套
    Linux下刻录光盘—cdrecord
    RHEL 6教程:使用本地光盘做yum源
    RHEL6 root登陆问题
    初学者学习LINUX之困惑?方向迷失?GUI?
  • 原文地址:https://www.cnblogs.com/lkq1220/p/6480964.html
Copyright © 2011-2022 走看看