binder 驱动数据结构详解手机开发

翻看2019年的自己整理的文章,才发现学习的东西都好肤浅,很多东西都不思其解。以此为契机,回来重新学习binder。2020加油!

binder驱动中的重要的数据结构

hlist_node: linux 内核哈希表

// hash桶的头结点 
struct hlist_head {
    
    struct hlist_node *first;//指向每一个hash桶的第一个结点的指针 
}; 
 
//hash桶的普通结点 
struct hlist_node {
    
    struct hlist_node *next;//指向下一个结点的指针 
    struct hlist_node **pprev;//指向上一个结点的next指针的地址 
} 

binder_work: binder工作类型

struct binder_work {
    
    struct list_head entry; // binder_work双向列表,存储所有binder_work 
 
    enum {
    // binder_work类型 
        BINDER_WORK_TRANSACTION = 1, 
        BINDER_WORK_TRANSACTION_COMPLETE, 
        BINDER_WORK_RETURN_ERROR, 
        BINDER_WORK_NODE, 
        BINDER_WORK_DEAD_BINDER, 
        BINDER_WORK_DEAD_BINDER_AND_CLEAR, 
        BINDER_WORK_CLEAR_DEATH_NOTIFICATION, 
    } type; 
}; 

binder_node: binder实体

struct binder_node {
    
    int debug_id; // 调试使用的创建时分派的id 
    spinlock_t lock; 
    struct binder_work work; // 工作类型 
    union {
    
        struct rb_node rb_node; // 正常使用的binder节点,会被链接到proc->nodes 
        struct hlist_node dead_node; // 已死的binder节点,但被其他proc引用,该实体会被通过dead_node存放在哈希表binder_dead_nodes 
    }; 
    struct binder_proc *proc; // binder所在进程 
    struct hlist_head refs; // Binder实体的所有Binder引用的链表 
    int internal_strong_refs; 
    int local_weak_refs; 
    int local_strong_refs; 
    int tmp_refs; 
    binder_uintptr_t ptr; // binder实体的对应用户空间的server端的内存地址 
    binder_uintptr_t cookie; // binder实体的对应用户空间的server端的其他数据的内存地址 
    struct {
    
        u8 has_strong_ref:1; 
        u8 pending_strong_ref:1; 
        u8 has_weak_ref:1; 
        u8 pending_weak_ref:1; 
    }; 
    struct {
    
        u8 accept_fds:1; 
        u8 txn_security_ctx:1; 
        u8 min_priority; 
    }; 
    bool has_async_transaction; // 是否有异步的事务 
    struct list_head async_todo; // 异步的todo队列 
}; 

binder_ref_death: binder 死亡结构体

binder server死亡时候,通知client端

struct binder_ref_death {
    
    struct binder_work work;  // binder死亡类型 
    binder_uintptr_t cookie; // 监听死亡通知的对象地址 
}; 

binder_ref: binder引用

struct binder_ref_data {
    
    int debug_id; // 调试id 
    uint32_t desc; // Binder引用的句柄值 
    int strong; // 强引用计数 
    int weak; // 弱引用计数 
}; 
struct binder_ref {
    
    struct binder_ref_data data; // binder_ref具体数据 
    struct rb_node rb_node_desc; // binder_proc->refs_by_desc 红黑树,记录着binder_ref的desc句柄,方便寻找binder_ref 
    struct rb_node rb_node_node; // binder_proc->refs_by_node 红黑树,记录着binder_ref 
 
    struct hlist_node node_entry; // 关联到binder_node->ref 
    struct binder_proc *proc; // binder 节点引用所在的进程 
    struct binder_node *node; // binder 实体 
    struct binder_ref_death *death; // 注册死亡通知 
} 
 
/* Lookups needed: */ 
/*   node + proc => ref (transaction) */ 
/*   desc + proc => ref (transaction, inc/dec ref) */ 
/*   node => refs + procs (proc exit) */ 

binder_proc: 在驱动中记录着进程的信息

struct binder_proc {
    
    struct hlist_node proc_node; // 在全局binder_proc哈希表中的位置 
    struct rb_root threads; // 红黑树,存储该进程下所有请求的线程 
    struct rb_root nodes; // 红黑树,存储所有binder节点 
    struct rb_root refs_by_desc; // 红黑树,存储binder引用的句柄 
    struct rb_root refs_by_node; // 红黑树,存储binder应用 
    struct list_head waiting_threads; // 等待的线程队列 
    int pid; // 进程id 
    struct task_struct *tsk; // 描述进程的数据结构 
    struct hlist_node deferred_work_node; 
    int deferred_work; 
    bool is_dead; // 进程是否已死 
 
    struct list_head todo;// 该进程的待处理事务队列 
    struct binder_stats stats; 
    struct list_head delivered_death; 
    int max_threads; 
    int requested_threads; // 未运行的binder thread数量 
    int requested_threads_started; // 已经运行的binder thread数量 
    int tmp_ref; 
    long default_priority; // 默认优先级 
    struct dentry *debugfs_entry; 
    struct binder_alloc alloc; // mmap映射到用户空间的内存结构 
    struct binder_context *context; // binder_context,全局静态 
    spinlock_t inner_lock; 
    spinlock_t outer_lock; 
    struct dentry *binderfs_entry; 
}; 

binder_context:记录ServiceManager信息

struct binder_context {
     
	struct binder_node *binder_context_mgr_node; // ServiceManager 的binder_node 
	struct mutex context_mgr_node_lock;   
	kuid_t binder_context_mgr_uid; // ServiceManager进程的uid 
	const char *name; 
}; 

binder_alloc:管理和分配、映射buffer

struct binder_alloc {
    
    struct mutex mutex; 
    struct vm_area_struct *vma; 
    struct mm_struct *vma_vm_mm; 
    void __user *buffer; // mmap内存,指向用户空间的地    struct list_head buffers; // 所有 
    struct rb_root free_buffers; // 空闲buffer 
    struct rb_root allocated_buffers; // 已分配的buffer 
    size_t free_async_space; // 用于异步请求空间 
    struct binder_lru_page *pages; // 所有的page页 
    size_t buffer_size; // buffer大小 
    uint32_t buffer_free; // buffer 空闲 
    int pid; //进程id 
    size_t pages_high; 
}; 

binder_thread:在内核中表示线程

struct binder_thread {
    
    struct binder_proc *proc; // 所属的进程 
    struct rb_node rb_node; //  proc->thread红黑树的节点 
    struct list_head waiting_thread_node; // proc->waiting_hreads 列表的节点 
    int pid;  
    int looper;  //  线程状态,仅当前线程可以修改 
    bool looper_need_return; /* can be written by other thread */ 
    struct binder_transaction *transaction_stack; // 正在处理的事务栈 
    struct list_head todo; // 待处理的事务栈 
    bool process_todo; 
    struct binder_error return_error; // 返回错误码 
    struct binder_error reply_error;// 返回的错误码 
    wait_queue_head_t wait; // 等待队列 
    struct binder_stats stats; 
    atomic_t tmp_ref; 
    bool is_dead; // 是否已死 
}; 

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; // 是否需要回复 
    /* unsigned is_dead:1; */    /* not used at the moment */ 
    struct binder_buffer *buffer; // 数据缓存 
    unsigned int    code; // 通信方法 
    unsigned int    flags; // 标志: oneway 
    long    priority; // 优先级 
    long    saved_priority; // 保存的优先级 
    kuid_t    sender_euid; // 发送的uid 
    struct list_head fd_fixups; 
    binder_uintptr_t security_ctx; 
    /** 
     * @lock:  protects @from, @to_proc, and @to_thread 
     * 
     * @from, @to_proc, and @to_thread can be set to NULL 
     * during thread teardown 
     */ 
    spinlock_t lock; 
}; 
// binder.h 
struct binder_object_header {
    
    __u32 type; 
}; 
 
enum {
    
    //强类型Binder实体对象 
    BINDER_TYPE_BINDER 
    //弱类型Binder实体对象 
    BINDER_TYPE_WEAK_BINDER 
    // 强类型引用对象 
    BINDER_TYPE_HANDLE  
    // 弱类型引用对象 
    BINDER_TYPE_WEAK_HANDLE  
    // 文件描述符  
    BINDER_TYPE_FD     
    BINDER_TYPE_FDA    
    BINDER_TYPE_PTR  
}; 

flat_binder_object: 将binder扁平化,可以在进程间传递

struct flat_binder_object {
     
    struct binder_object_header hdr; // 头部数据,表示数据类型 
    __u32 flags; 
    union {
     
    binder_uintptr_t binder; // 本进程下的binder,记录binder_node地址 
    __u32 handle;  // 非本进程下的binder,记录binder_ref的句柄 
    }; 
    binder_uintptr_t cookie; // 用户进程空间下的额外数据 
};  

binder_fd_object: 文件描述符

struct binder_fd_object {
    
    struct binder_object_header hdr; // 头部数据,表示数据类型 
    __u32 pad_flags; // 兼容旧的代码 
    union {
    
        binder_uintptr_t pad_binder; // 兼容旧的代码 
        __u32 fd; // 文件描述符 
    }; 
    binder_uintptr_t cookie; // 用户进程空间下的额外数据 
}; 

binder_buffer_object:用于描述用户空间下的缓存

struct binder_buffer_object {
    
    struct binder_object_header hdr; // 头部数据,表示数据类型 
    __u32 flags; 
    binder_uintptr_t buffer; 
    binder_size_t length; 
    binder_size_t parent; 
    binder_size_t parent_offset; 
}; 

binder_write_read:用户向驱动ioctl的交互数据

struct binder_write_read {
    
    binder_size_t write_size; // 写操作的字节数  
    binder_size_t write_consumed; // binder驱动已写完的字节数 
    binder_uintptr_t write_buffer; // 写缓存 
    binder_size_t read_size; // 读操作的字节数  
    binder_size_t read_consumed; // binder驱动已读完的字节数 
    binder_uintptr_t read_buffer; // 读缓存 
}; 

这个是很重要的数据结构,用户进程通过binder_ioctl(binder_write_read)交互数据

binder_transaction_data:表示传输内容,是用户层和 binder 驱动传递数据的数据结构

struct binder_transaction_data {
    
    /* The first two are only used for bcTRANSACTION and brTRANSACTION, 
    * identifying the target and contents of the transaction. 
    */ 
    union {
    
        __u32 handle; // binder_ref 句柄 
        binder_uintptr_t ptr; // binder_node 地址 
    } target; // 对于BpBinder则使用handle,对于BBinder则使用ptr 
    binder_uintptr_t cookie; // 在处于binder进程下才有意义,指向BBinder对象 
    __u32 code; // 事务编码,请求以BC_开头;回复则以BR_开头 
    __u32 flags; // 标志位:one_way 
    pid_t sender_pid; // 发送端pid 
    uid_t sender_euid; // 发送端uid 
 
    binder_size_t data_size; //data数据的总大小 
    binder_size_t offsets_size; // 缓存位移 
    /* If this transaction is inline, the data immediately 
    * follows here; otherwise, it ends with a pointer to 
    * the data buffer. 
    */ 
   // 如果该transaction传递普通数据,data会指向具体的数据,如果是Binder实体或者Binder引用,传递的是flat_binder_object, 
    union {
    
        struct {
    
            /* transaction data */ 
            binder_uintptr_t buffer; 
            /* offsets from buffer to flat_binder_object structs */ 
            binder_uintptr_t offsets; 
        } ptr; 
        __u8 buf[8]; 
    } data; 
}; 

binder_buffer:缓存

表示binder利用mmap创建的内存,在用户空间和内核空间通用的,因此会跟对应的进程

binder_proc相关联

空闲的挂在binder_proc->free_buffers,已分配的挂在binder_proc->allocated_buffers

struct binder_buffer {
    
    struct list_head entry; //  /* free and allocated entries by address */ 
    struct rb_node rb_node; /* free entry by size or allocated entry */ 
    unsigned free:1; // 是否是空闲的buffer 
    unsigned allow_user_free:1; /// 是否允许用户释放 
    unsigned async_transaction:1; // 异步事务 
    unsigned debug_id:29; // 调试id 
    struct binder_transaction *transaction; // 指向binder_transaction事务 
    struct binder_node *target_node;  // 指向binder_node 
    size_t data_size; // 数据大小 
    size_t offsets_size; // 数据偏移量 
    size_t extra_buffers_size; // 剩余的大小 
    void __user *user_data; // 缓存数据地址 
}; 

四个驱动动作

  • binder_init:初始化字符设备
  • binder_open:打开驱动设备
  • binder_mmap:申请内存空间
  • binder_ioctl:执行相应的ioctl操作

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/tech/app/6244.html

(0)
上一篇 2021年7月17日 00:44
下一篇 2021年7月17日 00:44

相关推荐

发表回复

登录后才能评论