Binder深入讲解底层 内核实现.docx

上传人:b****7 文档编号:23600774 上传时间:2023-05-18 格式:DOCX 页数:50 大小:215.16KB
下载 相关 举报
Binder深入讲解底层 内核实现.docx_第1页
第1页 / 共50页
Binder深入讲解底层 内核实现.docx_第2页
第2页 / 共50页
Binder深入讲解底层 内核实现.docx_第3页
第3页 / 共50页
Binder深入讲解底层 内核实现.docx_第4页
第4页 / 共50页
Binder深入讲解底层 内核实现.docx_第5页
第5页 / 共50页
点击查看更多>>
下载资源
资源描述

Binder深入讲解底层 内核实现.docx

《Binder深入讲解底层 内核实现.docx》由会员分享,可在线阅读,更多相关《Binder深入讲解底层 内核实现.docx(50页珍藏版)》请在冰豆网上搜索。

Binder深入讲解底层 内核实现.docx

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1