Binder深入讲解底层 内核实现.docx
- 文档编号:23600774
- 上传时间:2023-05-18
- 格式:DOCX
- 页数:50
- 大小:215.16KB
Binder深入讲解底层 内核实现.docx
《Binder深入讲解底层 内核实现.docx》由会员分享,可在线阅读,更多相关《Binder深入讲解底层 内核实现.docx(50页珍藏版)》请在冰豆网上搜索。
Binder深入讲解底层内核实现
第一节AndroidBinder
星期四,06/17/2010-00:
03—william
AndroidBinder是一种在Android里广泛使用的一种远程过程调用接口。
从结构上来说AndroidBinder系统是一种服务器/客户机模式,包括BinderServer、BinderClient和AndroidBinder驱动,实际的数据传输就是通过AndroidBinder驱动来完成的,这里我们就来详细的介绍AndroidBinder驱动程序。
通常来说,Binder是Android系统中的内部进程通讯(IPC)之一。
在Android系统中共有三种IPC机制,分别是:
-标准LinuxKernelIPC接口
-标准D-BUS接口
-Binder接口
尽管Google宣称Binder具有更加简洁、快速,消耗更小内存资源的优点,但并没有证据表明D-BUS就很差。
实际上D-BUS可能会更合适些,或许只是当时Google并没有注意到它吧,或者Google不想使用GPL协议的D-BUS库。
我们不去探究具体的原因了,你只要清楚Android系统中支持了多个IPC接口,而且大部分程序使用的是我们并不熟悉的Binder接口。
Binder是OpenBinder的Google精简实现,它包括一个Binder驱动程序、一个Binder服务器及Binder客户端(?
)。
这里我们只要介绍内核中的Binder驱动的实现。
对于AndroidBinder,它也可以称为是Android系统的一种RPC(远程过程调用)机制,因为Binder实现的功能就是在本地“执行”其他服务进程的功能的函数调用。
不管是IPC也好,还是RPC也好,我们所要知道的就是AndroidBinder的功能是如何实现的。
Openbinder介绍
2.1.1AndroidBinder协议
Android的Binder机制是基于OpenBinder(
AndroidBinder的协议定义在binder.h头文件中,Android的通讯就是基于这样的一个协议的。
∙BinderType
(描述bindertype的功能)
Android定义了五个(三大类)Binder类型,如下:
enum{
BINDER_TYPE_BINDER=B_PACK_CHARS('s','b','*',B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER=B_PACK_CHARS('w','b','*',B_TYPE_LARGE),
BINDER_TYPE_HANDLE=B_PACK_CHARS('s','h','*',B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE=B_PACK_CHARS('w','h','*',B_TYPE_LARGE),
BINDER_TYPE_FD=B_PACK_CHARS('f','d','*',B_TYPE_LARGE),
};
∙BinderObject
进程间传输的数据被称为Binder对象(BinderObject),它是一个flat_binder_object,定义如下:
structflat_binder_object{
/*8bytesforlarge_flat_header.*/
unsignedlongtype;
unsignedlongflags;
/*8bytesofdata.*/
union{
void*binder;/*localobject*/
signedlonghandle;/*remoteobject*/
};
/*extradataassociatedwithlocalobject*/
void*cookie;
};
其中,类型字段描述了Binder对象的类型,flags描述了传输方式,比如同步、异步等。
enumtransaction_flags{
TF_ONE_WAY=0x01,/*thisisaone-waycall:
async,noreturn*/
TF_ROOT_OBJECT=0x04,/*contentsarethecomponent'srootobject*/
TF_STATUS_CODE=0x08,/*contentsarea32-bitstatuscode*/
TF_ACCEPT_FDS=0x10,/*allowreplieswithfiledescriptors*/
};
传输的数据是一个复用数据联合体,对于BINDER类型,数据就是一个binder本地对象,如果是HANDLE类型,这数据就是一个远程的handle对象。
该如何理解本地binder对象和远程handle对象呢?
其实它们都指向同一个对象,不过是从不同的角度来说。
举例来说,假如A有个对象X,对于A来说,X就是一个本地的binder对象;如果B想访问A的X对象,这对于B来说,X就是一个handle。
因此,从根本上来说handle和binder都指向X。
本地对象还可以带有额外的数据,保存在cookie中。
Binder对象的传递是通过binder_transaction_data来实现的,即Binder对象实际是封装在binder_transaction_data结构体中。
∙binder_transaction_data
这个数据结构才是真正要传输的数据。
它的定义如下:
structbinder_transaction_data{
/*ThefirsttwoareonlyusedforbcTRANSACTIONandbrTRANSACTION,
*identifyingthetargetandcontentsofthetransaction.
*/
union{
size_thandle;/*targetdescriptorofcommandtransaction*/
void*ptr;/*targetdescriptorofreturntransaction*/
}target;
void*cookie;/*targetobjectcookie*/
unsignedintcode;/*transactioncommand*/
/*Generalinformationaboutthetransaction.*/
unsignedintflags;
pid_tsender_pid;
uid_tsender_euid;
size_tdata_size;/*numberofbytesofdata*/
size_toffsets_size;/*numberofbytesofoffsets*/
/*Ifthistransactionisinline,thedataimmediately
*followshere;otherwise,itendswithapointerto
*thedatabuffer.
*/
union{
struct{
/*transactiondata*/
constvoid*buffer;
/*offsetsfrombuffertoflat_binder_objectstructs*/
constvoid*offsets;
}ptr;
uint8_tbuf[8];
}data;
};
结构体中的数据成员target是一个复合联合体对象,请参考前面的关于binder本地对象及handle远程对象的描述。
code是一个命令,描述了请求Binder对象执行的操作。
∙对象的索引和映射
Binder中的一个重要概念就是对象的映射和索引。
就是要把对象从一个进程映射到另一个进程中,以实现线程迁移的概念。
前面描述过Binder的一个重要概念是进程/线程迁移,即当一个进程需要同另一个进程通信时,它可以“迁移”远程的进程/线程到本地来执行。
对于调用进程来说,看起来就像是在本地执行一样。
这是Binder与其他IPC机制的不同点或者说是优点。
当然迁移的工作是由Binder驱动来完成的,而实现的基础和核心就是对象的映射和索引。
Binder中有两种索引,一是本地进程地址空间的一个地址,另一个是一个抽象的32位句柄(HANDLE),它们之间是互斥的:
所有的进程本地对象的索引都是本地进程的一个地址(address,ptr,binder),所有的远程进程的对象的索引都是一个句柄(handle)。
对于发送者进程来说,索引就是一个远端对象的一个句柄,当Binder对象数据被发送到远端接收进程时,远端接受进程则会认为索引是一个本地对象地址,因此从第三方的角度来说,尽管名称不同,对于一次Binder调用,两种索引指的是同一个对象,Binder驱动则负责两种索引的映射,这样才能把数据发送给正确的进程。
对于Android的Binder来说,对象的索引和映射是通过binder_node和binder_ref两个核心数据结构来完成的,对于Binder本地对象,对象的Binder地址保存在binder_node->ptr里,对于远程对象,索引就保存在binder_ref->desc里,每一个binder_node都有一个binder_ref对象与之相联系,他们就是是通过ptr和desc来做映射的,如下图:
flat_binder_object就是进程间传递的Binder对象,每一个flat_binder_object对象内核都有一个唯一的binder_node对象,这个对象挂接在binder_proc的一颗二叉树上。
对于一个binder_node对象,内核也会有一个唯一的binder_ref对象,可以这么理解,binder_ref的desc唯一的映射到binder_node的ptr和cookie上,同时也唯一的映射到了flat_binder_object的handler上。
而binder_ref又按照node和desc两种方式映射到binder_proc对象上,也就是可以通过binder_node对象或者desc两种方式在binder_proc上查找到binder_ref或binder_node。
所以,对于flat_binder_object对象来说,它的binder+cookie和handler指向了同一个binder_node对象上,即同一个binder对象。
∙BinderDriverCommandProtocol
Binder驱动的命令协议(BC_命令),定义了Binder驱动支持的命令格式及数据定义(协议)。
不同的命令所带有的数据是不同的。
Binder的命令由binder_write_read数据结构描述,它是ioctl命令(BINDER_WRITE_READ)的参数。
structbinder_write_read{
signedlongwrite_size;/*bytestowrite*/
signedlongwrite_consumed;/*bytesconsumedbydriver*/
unsignedlongwrite_buffer;
signedlongread_size;/*bytestoread*/
signedlongread_consumed;/*bytesconsumedbydriver*/
unsignedlongread_buffer;
};
对于写操作,write_buffer包含了一系列请求线程执行的Binder命令;对于读(返回)操作,read_buffer包含了一系列线程执行后填充的返回值。
Binder命令(BC_)用于BINDER_WRITE_READ的write操作。
Binder的BC的命令格式是:
|CMD|Data...|
BinderCommandsCMD
DataFormat
Notes
BC_TRANSACTION
BC_REPLY
binder_transaction_data
BC_ACQUIRE_RESULT
BC_ATTEMPT_ACQUIRE
Notimplement
BC_FREE_BUFFER
data_ptr
ptrtotransactiondatareceivedonaread
BC_INCREFS
BC_ACQUIRE
BC_RELEASE
BC_DECREFS
int
targetdescriptor
BC_INCREFS_DONE
BC_ACQUIRE_DONE
node_ptr|cookie
BC_REGISTER_LOOPER
BC_ENTER_LOOPER
BC_EXIT_LOOPER
Noparameters
BC_REQUEST_DEATH_NOTIFICATION
target_ptr|cookie
BC_DEAD_BINDER_DONE
cookie
∙BinderDriverReturnProtocol
Binder驱动的响应(返回,BR_)协议,定义了Binder命令的数据返回格式。
同Binder命令协议一样,Binder驱动返回协议也是通过BINDER_WRITE_READioctl命令实现的,不同的是它是read操作。
BinderBR的命令格式是:
|CMD|Data...|
BinderBR命令CMDS
DataFormat
Notes
BR_ERROR
int
Errorcode
BR_OK
BR_NOOP
BR_SPAWN_LOOPER
Noparameters
BR_TRANSACTION
BR_REPLY
binder_transaction_data
thereceivedcommand
BR_ACQUIRE_RESULT
BR_ATTEMPT_ACQUIRE
BR_FINISHED
Notimplement
BR_DEAD_REPLY
Thetargetofthelasttransactionisnolongerwithus.
bcTRANSACTIONorbcATTEMPT_ACQUIRE
BR_TRANSACTION_COMPLETE
Noparameters...
Alwaysreferstothelasttransactionrequested(includingreplies).
Notethatthiswillbesentevenforasynchronoustransactions
BR_INCREFS
BR_ACQUIRE
BR_RELEASE
BR_DECREFS
target_ptr|cookie
BR_DEAD_BINDER
BR_CLEAR_DEATH_NOTIFICATION_DONE
cookie
BR_FAILED_REPLY
Thethelasttransaction
(eitherabcTRANSACTIONorabcATTEMPT_ACQUIRE)failed
(e.g.outofmemory).
∙AndroidBinder进程/线程模型
(描述Android的进程模型)
2.1.2驱动接口
AndroidBinder设备驱动接口函数是
device_initcall(binder_init);
我们知道一般来说设备驱动的接口函数是module_init和module_exit,这么做是为了同时兼容支持静态编译的驱动模块(buildin)和动态编译的驱动模块(module)。
但是Android的Binder驱动显然不想支持动态编译的驱动,如果你需要将Binder驱动修改为动态的内核模块,可以直接将device_initcall修改为module_init,但不要忘了增加module_exit的驱动卸载接口函数。
∙binder_init
初始化函数首先创建了一个内核工作队列对象(workqueue),用于执行可以延期执行的工作任务:
staticstructworkqueue_struct*binder_deferred_workqueue;
binder_deferred_workqueue=create_singlethread_workqueue("binder");
挂在这个workqueue上的work是binder_deferred_work,定义如下。
当内核需要执行work任务时,就通过workqueue来调度执行这个work了。
staticDECLARE_WORK(binder_deferred_work,binder_deferred_func);
queue_work(binder_deferred_workqueue,&binder_deferred_work);
既然说到了binder_deferred_work,这里有必要来进一步说明一下,binder_deferred_work是在函数binder_defer_work里调度的:
staticvoid
binder_defer_work(structbinder_proc*proc,enumbinder_deferred_statedefer)
{
mutex_lock(&binder_deferred_lock);
proc->deferred_work|=defer;
if(hlist_unhashed(&proc->deferred_work_node)){
hlist_add_head(&proc->deferred_work_node,
&binder_deferred_list);
queue_work(binder_deferred_workqueue,&binder_deferred_work);
}
mutex_unlock(&binder_deferred_lock);
}
deferred_work有三种类型,分别是BINDER_DEFERRED_PUT_FILES,BINDER_DEFERRED_FLUSH和BINDER_DEFERRED_RELEASE。
它们都操作在binder_proc对象上。
enumbinder_deferred_state{
BINDER_DEFERRED_PUT_FILES=0x01,
BINDER_DEFERRED_FLUSH=0x02,
BINDER_DEFERRED_RELEASE=0x04,
};
就现介绍到这里了,关于deferred的具体操作在后面还会有详细的介绍。
下面回到我们的初始化函数主题上。
初始化函数接着使用proc_mkdir创建了一个Binder的proc文件系统的根节点(binder_proc_dir_entry_root,/proc/binder),并为binder创建了binderproc节点(binder_proc_dir_entry_proc,/proc/binder/proc),注意不要混淆LinuxProc和BinderProc。
然后Binder驱动使用misc_register把自己注册为一个Misc设备(/dev/misc/binder)。
最后,如果驱动成功的创建了/proc/binder根节点,就调用create_proc_read_entry创建只读proc文件:
/proc/binder/state,/proc/binder/stats,/proc/binder/transactions,/proc/binder/transaction_log,/proc/binder/failed_transaction_log。
这个初始化函数有个小小的问题,它没有判断Misc设备是否注册成功了,如果注册失败了,那么Binder就不能正常工作了,因此这里应该有个错误处理流程。
注:
workqueue是Linux2.6内核的一种延期执行任务的一种机制,用于提到古老的任务队列(taskqueue)机制,workqueue机制非常灵活,简单,易于使用。
mutex_lock和mutex_unlock是一种内核同步机制。
2.1.3Binder核心数据
在进一步介绍Binder驱动之前,我们有必要了解一下Binder的核心数据。
∙binder_proc
structbinder_proc{
structhlist_nodeproc_node;
structrb_rootthreads;
structrb_rootnodes;
structrb_rootrefs_by_desc;
structrb_rootrefs_by_node;
intpid;
structvm_area_struct*vma;
structtask_struct*tsk;
structfiles_struct*files;
structhlist_nodedeferred_work_node;
intdeferred_work;
void*buffer;
ptrdiff_tuser_buffer_offset;
structlist_headbuffers;
structrb_rootfree_buffers;
structrb_rootallocated_buffers;
size_tfree_async_space;
structpage**pages;
size_tbuffer_size;
uint32_tbuffer_free;
structlist_headtodo;
wait_queue_head_twait;
structbinder_statsstats;
structlist_headdelivered_death;
intmax_threads;
intrequested_threads;
intrequested_threads_started;
intready_threads;
longdefault_priority;
};
binder_proc用于保存调用b
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Binder深入讲解 底层 内核实现 Binder 深入 讲解 内核 实现