Binder驱动之设备控制 -- 概述&数据结构

由于这部分内容相对复杂,我们将其拆解为几部分来讲解,这里我们先来了解一下背景知识和相关的基础数据结构。

1. 背景

Binder做为Android中进程间高效通信的核心组件,其底层是以misc设备驱动的形式实现的,但它本身并没有实现read,write操作,所有的控制都是通过ioctl操作来实现。ioctl是Linux中常见的系统调用,它是系统提供给应用的对底层设备特性进行控制的用户态接口,应用程序在调用ioctl进行设备控制时,最后会调用到设备注册struct file_operations结构体对象时的unlocked_ioctl或者compat_ioctl两个钩子上,具体是调用哪个钩子判断标准如下:

  • compat_ioctl : 32位的应用运行在64位的内核上,这个钩子被调用。
  • unlocked_ioctl: 64位的应用运行在64位的内核或者32位的应用运行在32位的内核上,则调用这个钩子。

在Binder驱动的struct file_operations定义中,它compat_ioctlunlocked_ioctl两个钩子的的实现都是对应到binder_ioctl上的。

 static const struct file_operations binder_fops = {
      .owner = THIS_MODULE,
      .poll = binder_poll,
      .unlocked_ioctl = binder_ioctl,
      .compat_ioctl = binder_ioctl,
      .mmap = binder_mmap,
      .open = binder_open,
      .flush = binder_flush,
      .release = binder_release,
    };

接下来,我们来先看看binder_ioctl的实现有关的结构体。

2. 相关数据结构

2.1 struct binder_thread

struct binder_thread {
  struct binder_proc *proc;         /*该thread相关联的binder_proc*/
  struct rb_node rb_node;         /*用于链入proc的threads红黑树*/
  int pid;
  int looper;           /* 状态标识位,用于表示当前线程所处的状态,具体包括以下几种状态:
                             * enum {
                             *      BINDER_LOOPER_STATE_REGISTERED  = 0x01, /*进程的非主线程进入Binder循环状态*/
                             *      BINDER_LOOPER_STATE_ENTERED     = 0x02, /*进程的主线程进入Binder循环状态*/
                             *      BINDER_LOOPER_STATE_EXITED      = 0x04, /*线程退出Binder循环状态*/
                             *      BINDER_LOOPER_STATE_INVALID     = 0x08, /*线程处在一个无效的状态,表示出错*/
                             *      BINDER_LOOPER_STATE_WAITING     = 0x10, /*线程的todo队列为空,进入等待请求的状态*/
                             *      BINDER_LOOPER_STATE_NEED_RETURN = 0x20  /*线程是否需要返回数据给进程的用户态*/
                             *  };
                             */
  struct binder_transaction *transaction_stack;     /*该线程的事务栈。通过struct binder_transaction的
                                                    * from_parent和to_parent分别链入客户端和服务端线程的
                                                    * transaction_stack事务栈中(即本字段)。详见2.7 */
  struct list_head todo;                            /*binder_work队列,管理本线程所有待处理的binder_work*/
  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 。发送reply时发生错误,该错误码用于返回给发送进程 */
  wait_queue_head_t wait;  /*binder线程空闲时,用于等待队列相关的结构,是Linux内核的一个数据结构*/
  struct binder_stats stats; /*统计有关的结构*/
};

2.2 struct binder_proc中的相关成员

struct binder_proc{
  ...
  struct rb_root threads; /*管理thread的红黑树根节点,以线程的id为序*/
  struct rb_root nodes;            /*管理binder_node的红黑树根节点,以binder_node中的ptr大小为序*/
  struct rb_root refs_by_desc;  /*管理binder_ref的红黑树根节点,以binder_ref中的desc大小为序*/
  struct rb_root refs_by_node;  /*管理binder_ref的红黑树根节点,以binder_ref对应的binder_node的地址为序*/
  ...
  int max_threads; /*最大线程数*/
  ...
};

2.3 用于用户态向内核态传输数据的结构体 — struct binder_write_read

struct binder_write_read {
  /* process ----> kernel */
  binder_size_t        write_size;    /* bytes to write, 进程用户态地址空间传递到内核数据的大小*/
  binder_size_t        write_consumed;    /* bytes consumed by driver 进程用户态地址空间传递到内核数据中已经被内核态处理的大小*/
  binder_uintptr_t    write_buffer;       /*进程用户态地址空间传递到内核数据的起始地址*/
/*  kernel ----> process */
  binder_size_t        read_size;    /* bytes to read, 总共可供给驱动写入的字节数,read_buffer可供内核使用的大小*/
  binder_size_t        read_consumed;    /* bytes consumed by driver, 内核Binder驱动发送给用户态进程的字节数*/
  binder_uintptr_t    read_buffer;  /*内核驱动发送给进程数据buffer的起始地址*/
};

2.4 Binder C/S通信架构中,C端的驱动层表示 —— struct binder_ref

struct binder_ref {
  /* Lookups needed: */
  /*   node + proc => ref (transaction) */
  /*   desc + proc => ref (transaction, inc/dec ref) */
  /*   node => refs + procs (proc exit) */
  int debug_id;                /*每个binder_ref的唯一标识符,主要用于debug*/
  struct rb_node rb_node_desc; /*用来链入proc->refs_by_desc红黑树中,该红黑树以desc域为序组织的*/
  struct rb_node rb_node_node; /*用来链入proc->refs_by_node红黑树中, 该红黑树以该binder_ref所对应的binder_node的地址为序组织的*/
  struct hlist_node node_entry; /*用来链入binder_node的refs哈希链表中。*/
  struct binder_proc *proc;     /*指向该binder_ref中所属的binder_proc*/
  struct binder_node *node;     /*指向该binder_ref所对应(引用)的binder_node*/
  uint32_t desc;                /*binder_ref的描述符。用来返回给进程用户态地址空间,标识所对应的binder_ref*/
  int strong;                   /*强引用计数*/
  int weak;                     /*弱引用计数*/
  struct binder_ref_death *death; /*Binder“死亡讣告”相关的一个结构体,详见:2.8*/ 
};

2.5 Binder C/S通信架构中,S端的驱动层表示 —— struct binder_node

struct binder_node {
  int debug_id;
  struct binder_work work;
  union {
    struct rb_node rb_node;   /*用来链入proc的nodes红黑树,该红黑树以binder_node的ptr的大小为序*/
    struct hlist_node dead_node;
  };
  struct binder_proc *proc;
  struct hlist_head refs; /*所有引用这个binder_node的binder_ref通过它的node_entry加入这个哈希链表中,
                        * 这样binder_node通过查看这个哈希链表就知道有哪些binder_ref在引用它*/
  int internal_strong_refs;  /*binder_ref的强引用计数,即有多少个binder_ref强引用这个binder_node*/
  int local_weak_refs;       /*BBinder弱引用计数*/
  int local_strong_refs;    /*binder_buffer.target_node及BBinder的强引用计数*/
  binder_uintptr_t ptr;      /*对应BBinder基类RefBase中mRef成员的的地址,它是一个引用计数器,类型为weakref_impl*/
  binder_uintptr_t cookie;   /*对应BBinder的地址*/**
  unsigned has_strong_ref:1;  /*标识是否已经增加了用户态对应binder service(BBinder)对象的强引用计数*/
  unsigned pending_strong_ref:1;  /*标识是否有未处理的BR_ACQUIRE命令,在执行BR_ACQUIRE请求命令前设为1,在BC_ACQUIRE_DONE中设为0*/
  unsigned has_weak_ref:1;   /*标识是否已经增加了用户态对应binder service(BBinder)对象的弱引用计数*/
  unsigned pending_weak_ref:1; /*标识是否有未处理的BR_INCREFS命令,在执行BR_INCREFS请求命令前设为1,在BC_INCREFS_DONE中设为0*/
  unsigned has_async_transaction:1; /*标识是否有异步事务要处理。异步事务的含义是:客户端发送了带有TF_ONE_WAY标识的请求。*/
  unsigned accept_fds:1;          /*是否接受文件描述符*/
  unsigned min_priority:8;
  struct list_head async_todo;  /*异步事务待处理链表*/
};

2.6 用于Binder用户态向内核驱动传输事务数据 —— struct binder_transaction_data

struct binder_transaction_data {
  /* The first two are only used for bcTRANSACTION and brTRANSACTION,
   * identifying the target and contents of the transaction.
   */
  union {
    /* target descriptor of command transaction */
    __u32    handle;
    /* target descriptor of return transaction */
    binder_uintptr_t ptr;
  } target;
  binder_uintptr_t    cookie;    /* target object cookie */
  __u32        code;        /* transaction command */
  /* General information about the transaction. */
  __u32            flags;                      /*标志位,如:TF_ONE_WAY*/
  pid_t        sender_pid;                /*发送者进程id*/
  uid_t        sender_euid;             /*发送者有效用户id*/
  binder_size_t    data_size;    /* number of bytes of data */
  binder_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 {     /*存放事务的数据部分,如果是inline,则数据直接放在buf数组中;
               * 如果不是,则放在ptr结构体中的buffer和offsets的指针中。一般情况都是通过ptr结构体*/
    struct {
        /* transaction data */
        binder_uintptr_t    buffer;
        /* offsets from buffer to flat_binder_object structs */
        binder_uintptr_t    offsets;
      } ptr;
    __u8    buf[8]; /*inline数据直接放在这个buf中, 在4.0.9的内核中,这个字段没有看见使用的地方*/
  } data;
};

2.7 用于Binder内核态驱动表示Binder通信事务数据结构 —— struct binder_transaction

struct binder_transaction {
  int debug_id;
  struct binder_work work;                   /*用于链入线程/进程todo队列的成员*/
  struct binder_thread *from;               /*事务发起线程thread的地址,如果是binder server回复给client,该域为NULL*/
  struct binder_transaction ***from_parent**;  /* 用于链入事务发起线程的事务栈中,
                                                * 加入的时机是binder_transaction_data传入驱动并被binder_transaction处理的时候*/
  struct binder_proc *to_proc;        /*目标线程的proc地址*/
  struct binder_thread *to_thread;    /*事务目标线程thread的地址*/
  struct binder_transaction *to_parent; /* 用于链入目标线程的事务栈中,
                                         * 加入的时机是目标线程在调用binder_thread_read处理thread->todo队列
                                         * 类型为BINDER_WORK_TRANACTION的binder_work时*/
  unsigned need_reply:1;
  /* unsigned is_dead:1; */    /* not used at the moment */
  struct binder_buffer *buffer;    /*存储数据的地方*/
  unsigned int    code;                /*一个binder调用所对应的代号*/
  unsigned int    flags;
  long    priority;                /*请求/回复 线程的优先级*/
  long    saved_priority;     /*存储线程优先级备份,当需要修改一个线程的优先级时,先将它当前值放在该变量中,以便于稍后恢复。*/
  kuid_t    sender_euid;
};

进程用户态传输进来的struct binder_transaction_data到内核态后,会转化成相应的struct binder_transaction。该数据结构主要用于承载Binder请求和回复通信中的数据。

2.8 用于注册Binder service死亡通知的数据结构 —— binder_ref_death

struct binder_ref_death {
  struct binder_work work;  /*binder service死亡时,通过该work的entry域链入thread或者proc的todo队列*/
  binder_uintptr_t cookie; /*binder service死亡时,要通知的BpBinder对象的地址*/
};

你可能感兴趣的:(#,Binder,android,内核,linux,经验分享,面试)