本文主要是自己阅读binder驱动时的注释。
大概会先描述下数据结构,然后贴上主要的代码部分。
//描述一个binder对象
struct flat_binder_object {
/* 8 bytes for large_flat_header. */
__u32 type;//binder类型,如BINDER_TYPE_BINDER
__u32 flags;//只对第一个传递binder实体时有效,因为需要在内核中创建相应的实体节点
/* 8 bytes of data. */
union {
binder_uintptr_t binder; //传递binder实体时使用,指向binder实体在应用程序中的地址
__u32 handle; //传递binder引用时使用,存放binder在进程中的引用
};
/* extra data associated with local object */
binder_uintptr_t cookie;//只对binder实体有效,存放与该binder有关的附加信息
};
/*
* On 64-bit platforms where user code may run in 32-bits the driver must
* translate the buffer (and local binder) addresses appropriately.
*/
//binder读写数据
struct binder_write_read {
binder_size_t write_size; /* bytes to write */
binder_size_t write_consumed; /* bytes consumed by driver */
binder_uintptr_t write_buffer;
binder_size_t read_size; /* bytes to read */
binder_size_t read_consumed; /* bytes consumed by driver */
binder_uintptr_t read_buffer;
};
/* Use with BINDER_VERSION, driver fills in fields. */
struct binder_version {
/* driver protocol version -- increment with incompatible change */
__s32 protocol_version;
};
//事务传递数据结构
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;//binder实体的句柄
/* target descriptor of return transaction */
binder_uintptr_t ptr;//指向binder对象的指针,binder驱动将handle转化为ptr
} target;//接收数据端
binder_uintptr_t cookie; //驱动不关心此值
__u32 code; //收发双方约定的命令码
/* General information about the transaction. */
__u32 flags;
pid_t sender_pid;//发送方的进程pid,驱动负责填入
uid_t sender_euid;//发送方的user id
binder_size_t data_size;//发送方填入,表示data.buffer指向的缓冲区存放的数据长度
binder_size_t offsets_size;//偏移数组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 */
binder_uintptr_t buffer;//存放发送或者接收的数据
/* offsets from buffer to flat_binder_object structs */
binder_uintptr_t offsets;//数组,指向每个binder引用在data中的偏移位置
} ptr;
__u8 buf[8];
} data;
};
//用来描述待处理的工作项,这些工作项可能属于同一个进程,也可能属于一个进程中的某一个线程
struct binder_work {
struct list_head entry;//binder work list
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;//工作类型
};
//binder本地对象
struct binder_node {
int debug_id;//标志binder实体对象的身份,帮助调试
struct binder_work work;
//一个进程可能用到多个binder对象(可能用到多个service),所有binder对象保存在rb tree中
union {
struct rb_node rb_node;
struct hlist_node dead_node;//如果实体对象的宿主进程死亡,实体对象就保存在全局的hash list中
};
struct binder_proc *proc;//binder实体对象的宿主进程
struct hlist_head refs;//保存引用该实体对象的引用对象的hash list
int internal_strong_refs;//强引用计数
int local_weak_refs;
int local_strong_refs;
binder_uintptr_t ptr;//指向用户空间service内部的引用计数的地址
binder_uintptr_t cookie;//指向用户空间service组件的地址
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;//binder实体对象是否在处理异步事务
unsigned accept_fds:1;
unsigned min_priority:8;//线程最小优先级
struct list_head async_todo;//异步事务队列
};
struct binder_ref_death {
struct binder_work work;
binder_uintptr_t cookie;
};
//binder代理对象
struct binder_ref {
/* Lookups needed: */
/* node + proc => ref (transaction) */
/* desc + proc => ref (transaction, inc/dec ref) */
/* node => refs + procs (proc exit) */
int debug_id;//引用对象id
struct rb_node rb_node_desc;//以引用对象句柄值作关键字保存到宿主进程的rb tree
struct rb_node rb_node_node;//以引用对应对应的实体对象的地址作关键字保存到宿主进程的rb tree
struct hlist_node node_entry;//每个binder实体对象使用一个hash表保存所有引用他的引用对象,该值就是hash表
struct binder_proc *proc;//binder引用对象的宿主进程
struct binder_node *node;//引用对象对应的实体对象
uint32_t desc;//应用对象的句柄,用来给用户进程使用,(对应binder代理对象)
int strong;//强引用计数
int weak;//弱引用计数
struct binder_ref_death *death;//死亡接收通知,client注册死亡接收通知时创建的结构体
};
/*
描述内核缓冲区
*/
struct binder_buffer {
struct list_head entry; //宿主进程内核缓冲区链表节点
struct rb_node rb_node; //buffer所属的rb tree(正在使用或者空闲的红黑树)
unsigned free:1;//如果缓冲区为空,该值为1,代表buffer在free rb tree中
unsigned allow_user_free:1;//是否允许用户使用这个buffer
unsigned async_transaction:1;//是否异步事务处理
unsigned debug_id:29;//buffer id
struct binder_transaction *transaction;//该缓冲区由哪个事务处理
struct binder_node *target_node;//该缓冲区由哪个binder实体对象使用
/*
data 指向一块大小可变的数据缓冲区,它是用来保存真正的通信数据
数据缓冲区保存的数据可分为两类,一种是普通数据,一种是Binder对象。Binder驱动程序不关心数据缓冲区的普通数据,
但必须知道里面的Binder对象,因为它需要根据它们 来维护内核中的Binder实体对象和Binder引用对象的生命周期。在数据缓冲区的后面,有一个偏移数组,
它记录了数据缓冲区中每一个Binder对象在数据缓冲区中的位置。
偏移数组的大小保存在成员变量 offsets_size 中,而数据缓冲区的大小保存在变量 data_size 中。
*/
size_t data_size;//data大小
size_t offsets_size;//数组,保存了每个binder对象的偏移
uint8_t data[0];//保存通信数据,这里面保存了普通数据跟binder对象
};
enum binder_deferred_state {
BINDER_DEFERRED_PUT_FILES = 0x01,//为binder缓冲区创建一个文件描述符
BINDER_DEFERRED_FLUSH = 0x02, //延迟工作项,用来唤醒进程binder处理线程
BINDER_DEFERRED_RELEASE = 0x04,//释放binder资源比较耗时,创建一个延迟工作项来进行
};
//描述一个正在使用Binder进程间通信机制的进程
struct binder_proc {
struct hlist_node proc_node;//所有binder_proc保存在一个hash list中
struct rb_root threads;//进程线程池,rb tree存储,threads是rb tree root node
//进程内部包含了一系列binder实体跟引用对象
struct rb_root nodes;//binder实体对象,存储实体对象的ptr
struct rb_root refs_by_desc;//引用对象,用desc作关键字查找
struct rb_root refs_by_node;//引用对象,用node作关键字查找
int pid;//进程pid
struct vm_area_struct *vma;//内核缓冲区对应的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;//内核缓冲区地址,被划分成若干小块,用binder_buffer来描述
ptrdiff_t user_buffer_offset;//用于内核地址跟用户空间地址转换
/*
binder_buffer小块缓冲区用list来组织,buffers指向list头。
这些小块内存区再分成已经使用的和空闲的缓冲区,组织在两个rb tree中
*/
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;//binder处理线程等待队列,进程有工作任务时唤醒队列中的处理线程
struct binder_stats stats;
struct list_head delivered_death;//用来向进程通知其使用的service dead 消息,
int max_threads;//对该进程来说,binder驱动最大可注册的线程数
int requested_threads;//binder驱动请求进程注册线程时的mutex值
int requested_threads_started;//binder驱动主动请求进程注册了多少个线程
int ready_threads;//当前进程空闲线程数(线程指的是专门用于处理binder通信的线程)
long default_priority;//进程优先级
struct dentry *debugfs_entry;
};
/*
* 一个线程注册到Binder驱动程序时,Binder驱动程序会为它创建一个binder_thread结构体,并且将它的状态初始化为 BINDER_LOOPER_STATE_NEED_RETURN,表示该线程需要马上返回
* 到用户空间。由于一个线程在注册为Binder线程时可能还没有准备好去处理进程间通信请求时,因此,最好返回到用户空间去做准备工作。此外,当进程调用函数 flush 来刷新它的Binder线程池
* 时,Binder线程池中的线程状态也会被重置为BINDER_LOOPER_STATE_NEED_RETURN.
* 一个线程注册到Binder驱动程序后,它接着就会通过BC_REGISTER_LOOPER或者BC_ENTER_LOOPER协议来通知Binder驱动程序,它可以处理进程间通信请求了,这时候Binder驱动程序
* 就会将它的状态设置为BINDER_LOOPER_STATE_REGISTERED或者BINDER_LOOPER_STATE_ENTERED.如果一个线程是应用程序主动注册的,那么它就通过BC_ENTER_LOOPER协议来通知Binder
* 驱动程序,它已经准备就绪处理进程间通信请求了;如果一个线程是Binder驱动程序请求创建的,那么它就通过BC_REGISTER_LOOPER协议来通知Binder驱动程序,这时候Binder驱动程序就会
* 增加它所请求进程创建的Binder线程数目。
* 当一个Binder线程处于空闲状态时,Binder驱动程序就会把它的状态设置为BINDER_LOOPER_STATE_WAITING;而当一个Binder线程退出时,它就会通过BC_EXIT_LOOPER协议来通知Binder
* 驱动程序,这时候Binder驱动程序就会将它的状态设置为BINDER_LOOPER_STATE_EXITED.在异常情况下,一个Binder线程的状态会被设置为BINDER_LOOPER_STATE_INVALID,例如,当该线程
* 已经处于BINDER_LOOPER_STATE_REGITERED状态时,如果它又再次通过BC_ENTER_LOOPER协议来通知Binder驱动程序它已经准备就绪,那么Binder驱动程序就会将它的状态设置为BINDER_LOOPER_STATE_INVALID.
* 当一个来自Client进程的请求指定要由某一个Binder线程处理时,这个请求就会加入到相应的binder_thread结构体的成员变量todo所表示的队列中,并且唤醒这个线程来处理。
* 当Binder驱动程序决定将一个事务交给一个Binder线程处理时,它就会将该事务封装成一个 binder_transaction 结构体,并且将它添加到线程结构体 binder_thread 的成员变量 transaction_stack
* 所描述的一个事务堆栈中。
* 一个Binder线程在处理一个事务时,如果出现了异常情况,那么Binder驱动程序就会将相应的错误码保存在 return_error 和 return_error2 中,这时候线程就会将错误码返回给用户空间应用程序处理。
* 最后,stats是用来统计Binder线程数据的。例如,Binder线程接收到的进程间通信请求的次数。
*/
enum {
BINDER_LOOPER_STATE_REGISTERED = 0x01,
BINDER_LOOPER_STATE_ENTERED = 0x02,
BINDER_LOOPER_STATE_EXITED = 0x04,
BINDER_LOOPER_STATE_INVALID = 0x08,
BINDER_LOOPER_STATE_WAITING = 0x10,
BINDER_LOOPER_STATE_NEED_RETURN = 0x20
};
//描述Binder线程池中的一个线程
struct binder_thread {
struct binder_proc *proc;//该线程所属进程
struct rb_node rb_node;//进程采用rb tree存储线程池
int pid;//binder线程id
int looper;//binder线程状态,取值为上面定义的enum BINDER_LOOPER_STATE_REGISTERED
struct binder_transaction *transaction_stack;//当Binder驱动程序决定将一个事务交给一个Binder线程处理时,它就会将该事务封装成一个 binder_transaction 结构体,并且将它添加到线程结构体 binder_thread 的成员变量 transaction_stack
struct list_head todo;//当一个来自Client进程的请求指定要由某一个Binder线程处理时,这个请求就会加入到相应的binder_thread结构体的成员变量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;//binder线程等待队列
struct binder_stats stats;//统计binder通信状态
};
//描述进程间通信过程,这个过程又称为一个事务
struct binder_transaction {
int debug_id;//事物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;
long priority;//源线程优先级
long saved_priority;//保存线程之前的优先级
kuid_t sender_euid;//源线程user id
//目标线程在处理一个事务时,它的线程优先级不能低于目标Service组件所要求的线程优先级,而且也不能低于源线程的优先级
};
//获取一个未使用的fd
static int task_get_unused_fd_flags(struct binder_proc *proc, int flags)
{
struct files_struct *files = proc->files;//进程打开文件表
unsigned long rlim_cur;
unsigned long irqs;
if (files == NULL)
return -ESRCH;
if (!lock_task_sighand(proc->tsk, &irqs))
return -EMFILE;
rlim_cur = task_rlimit(proc->tsk, RLIMIT_NOFILE);//打开文件数量限制
unlock_task_sighand(proc->tsk, &irqs);
return __alloc_fd(files, 0, rlim_cur, flags);//给此进程分配一个未使用的文件标识符
}
/*
* copied from fd_install
*/
static void task_fd_install(
struct binder_proc *proc, unsigned int fd, struct file *file)
{
if (proc->files)//file加入到进程fdt表中
__fd_install(proc->files, fd, file);
}
/*
* copied from sys_close
*/
//关闭进程fd对应的文件
static long task_close_fd(struct binder_proc *proc, unsigned int fd)
{
int retval;
if (proc->files == NULL)
return -ESRCH;
retval = __close_fd(proc->files, fd);
/* can't restart close syscall because file table entry was cleared */
if (unlikely(retval == -ERESTARTSYS ||
retval == -ERESTARTNOINTR ||
retval == -ERESTARTNOHAND ||
retval == -ERESTART_RESTARTBLOCK))
retval = -EINTR;
return retval;
}
//调整CFS进程nice值
static void binder_set_nice(long nice)
{
long min_nice;
if (can_nice(current, nice)) {//当前进程优先级能否修改成nice值
set_user_nice(current, nice);//修改进程优先级(调整load),然后重新入队等待调动
return;
}
//上面nice值过小,找到最小可设置的nice值再调整进程优先级
min_nice = 20 - current->signal->rlim[RLIMIT_NICE].rlim_cur;
binder_debug(BINDER_DEBUG_PRIORITY_CAP,
"%d: nice value %ld not allowed use %ld instead\n",
current->pid, nice, min_nice);
set_user_nice(current, min_nice);
if (min_nice < 20)
return;
binder_user_error("%d RLIMIT_NICE not set\n", current->pid);
}
//用来获取binder_buffer中存储data数据的大小,data_size用途???
//主要理解进程缓冲区存储方式:按照list方式将binder_buffer组织起来
static size_t binder_buffer_size(struct binder_proc *proc,
struct binder_buffer *buffer)
{ //buffer的内存缓冲区节点是否是进程proc进程缓冲区list的最后一个节点
if (list_is_last(&buffer->entry, &proc->buffers))
return proc->buffer + proc->buffer_size - (void *)buffer->data; //进程proc剩余的内存缓冲区大小
return (size_t)list_entry(buffer->entry.next,
struct binder_buffer, entry) - (size_t)buffer->data; //进程proc下个buffer节点地址减去data地址,
//这段空间用来保存data数据
}
/*
往进程rb tree 中插入一个新的free buffer
进程的binder_buffer组织分成了两种数据结构,一个是所有buffer都依次插入list struct list_head buffers,
这些buffer同时会构建成两颗rb tree struct rb_root free_buffers,struct rb_root allocated_buffers
*/
static void binder_insert_free_buffer(struct binder_proc *proc,
struct binder_buffer *new_buffer)
{
struct rb_node **p = &proc->free_buffers.rb_node;//free buffer rb tree
struct rb_node *parent = NULL;
struct binder_buffer *buffer;
size_t buffer_size;
size_t new_buffer_size;
BUG_ON(!new_buffer->free);
//获取binder_buffer有效存储data的大小
new_buffer_size = binder_buffer_size(proc, new_buffer);
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
"%d: add free buffer, size %zd, at %p\n",
proc->pid, new_buffer_size, new_buffer);
while (*p) {//rb tree查找,从free_buffers root节点开始,按照buffer size进行查找
parent = *p;
buffer = rb_entry(parent, struct binder_buffer, rb_node);
BUG_ON(!buffer->free);
buffer_size = binder_buffer_size(proc, buffer);
if (new_buffer_size < buffer_size)
p = &parent->rb_left;
else
p = &parent->rb_right;
}
//new_buffer插入到合适的节点
rb_link_node(&new_buffer->rb_node, parent, p);
rb_insert_color(&new_buffer->rb_node, &proc->free_buffers);//调整rb tree,使其满足着色要求
}