您的位置:首页 > 其它

我的进阶曲线之八

2015-10-10 15:24 411 查看
Android Binder

什么是Binder?
http://blog.csdn.net/luoshengyang/article/details/6618363
Android 为什么选择Binder?

l轻量级
目前linux支持的IPC包括传统的管道,System V IPC,即消息队列/共享内存/信号量,以及socket。只有socket支持Client-Server的通信方式。当然也可以在这些底层机制上架设一套协议来实现Client-Server通信,但这样增加了系统的复杂性,在手机这种条件复杂,资源稀缺的环境下可靠性也难以保证。

l安全性
使用传统IPC只能由用户在数据包里填入UID/PID,但这样不可靠,容易被恶意程序利用。可靠的身份标记只有由IPC机制本身在内核中添加。

l传输性能
http://blog.csdn.net/universus/article/details/6211589/
共享内存虽然无需拷贝,但控制复杂,难以使用。

即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少有两次拷贝过程

binder传输过程只需一次拷贝,为发送发添加UID/PID身份

核心优势:内存拷贝一次

核心代码:

if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {

案例:注册MediaPlayerService服务

•1 创建服务进程

•2 获取ServiceManager引用
•3 在ServiceManager中注册服务

在Android系统中,提供了多媒体播放的功能,这个功能是以服务的形式来提供的。

sp<ProcessState> proc(ProcessState::self());

sp<IServiceManager> sm =defaultServiceManager();

ALOGI("ServiceManager: %p", sm.get());

AudioFlinger::instantiate();

MediaPlayerService::instantiate();

创建服务进程(1)

MediaPlayerService服务启动代码
framework\base\Media\MediaServer\Main_mediaserver.cpp

intmain(int argc,char** argv)

{

sp<ProcessState> proc(ProcessState::self());

sp<IServiceManager> sm = defaultServiceManager();

ALOGI("ServiceManager: %p", sm.get());

AudioFlinger::instantiate();

MediaPlayerService::instantiate();

CameraService::instantiate();

//获得一个ProcessState实例

//得到一个ServiceManager引用

/初始化MediaPlayerService服务

创建服务进程(2)

获得一个ProcessState实例,并打开binder设备
framework\native\libs\binder\ProcessState.cpp

ProcessState::ProcessState()

: mDriverFD(open_driver())

打开/dev/binder设备
framework\native\libs\binder\ProcessState.cpp

intfd = open("/dev/binder",O_RDWR);

设备内存映射
framework\native\libs\binder\ProcessState.cpp

mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ,MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
http://blog.csdn.net/luoshengyang/article/details/6627260
创建服务进程(3)

深入理解设备内存映射:binder mmap
framework\native\libs\binder\ProcessState.cpp

mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

kernel\common\drivers\staging\android\binder.c
static intbinder_mmap(struct file *filp, structvm_area_struct *vma)

第一次只申请一页的物理内存,后续按需申请。

kernel\common\drivers\staging\android\binder.c

binder_update_page_range(proc, 1,proc->buffer, proc->buffer + PAGE_SIZE, vma)
http://blog.csdn.net/luoshengyang/article/details/6621566
这里为什么会同时使用进程虚拟地址空间和内核虚拟地址空间来映射同一个物理页面呢?这就是Binder进程间通信机制的精髓所在了,同一个物理页面,一方映射到进程虚拟地址空间,一方面映射到内核虚拟地址空间,这样,进程和内核之间就可以减少一次内存拷贝了,提到了进程间通信效率。

创建服务进程(4)

深入理解设备内存映射:binder mmap

分配一个物理页面

kernel\common\drivers\staging\android\binder.c

*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM |__GFP_ZERO);

将这个物理页面插入到进程内核空间

kernel\common\drivers\staging\android\binder.c

ret = map_vm_area(&tmp_area, PAGE_KERNEL,&page_array_ptr);

进程虚拟空间地址

kernel\common\drivers\staging\android\binder.c

user_page_addr = (uintptr_t)page_addr + proc->user_buffer_offset;

创建服务进程(5)
http://blog.csdn.net/luoshengyang/article/details/6627260
创建服务进程(6)
http://www.cnblogs.com/zhangxinyan/archive/2013/12/27/3487909.html
一个process里有个实体对象,就有多少个binder_node;一个process有多少个代理对象指向远端,就有多少个binder_ref.

•2 获取ServiceManager引用

defaultServiceManager模板代入

frameworks\native\libs\binder\IServiceManager.cpp

framework\native\libs\binder\ProcessState.cpp

gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

frameworks\native\libs\binder\IServiceManager.cpp

gDefaultServiceManager = new BpServiceManager(new BpBinder(0));
http://blog.csdn.net/luoshengyang/article/details/6627260
l ProcessState有了。

l IPCThreadState有了,而且是主线程的。

l BpBinder有了,内部handle值为0

BpServiceManager UML
http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html
返回的实际是BpServiceManager,它的remote对象是BpBinder,传入的那个handle参数是0。

BpRefBase::BpRefBase(const sp<IBinder>& o)

:mRemote(o.get()), mRefs(NULL), mState(0)

//o.get(),这个是sp类的获取实际数据指针的一个方法,你只要知道

//它返回的是sp<xxxx>中xxx* 指针就行

{

//mRemote就是刚才的BpBinder(0)

•3 在ServiceManager中注册服务

调用ServiceManager方法:addservice
frameworks\av\media\libmediaplayerservice\ MediaPlayerService.cpp

void MediaPlayerService::instantiate() {

defaultServiceManager()->addService(

String16("media.player"), new MediaPlayerService());

}

frameworks\native\libs\binder\IServiceManager.cpp:

BpServiceManager : addService

status_t err =remote()->transact(ADD_SERVICE_TRANSACTION, data,

&reply);

mso-color-index:1;mso-font-kerning:12.0pt;language:en-US'>)) {
framework\base\libs\binder\BpBinder.cpp

status_t status = IPCThreadState::self()->transact(

mHandle, code, data, reply, flags);
http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html
IPCThreadState 对象是在创建 BpBinder对象时候创建的。 (framework\base\libs\binder\IPCThreadState.cpp)

基类BpInterface的构造函数(经过兑现后)

inline BpInterface< IServiceManager >::BpInterface(const sp<IBinder>& remote)

:BpRefBase(remote)

{

}

frameworks\native\libs\binder\binder.cpp

BpRefBase::BpRefBase(const sp<IBinder>& o)

:mRemote(o.get()), mRefs(NULL), mState(0)

//o.get(),这个是sp类的获取实际数据指针的一个方法,你只要知道

//它返回的是sp<xxxx>中xxx* 指针就行

{

//mRemote就是刚才的BpBinder(0)

通过IPCThreadState对象来和binder驱动交互
frameworks\native\libs\binder\IPCThreadState.cpp

IPCThreadState::transact

err = waitForResponse(reply);

frameworks\native\libs\binder\IPCThreadState.cpp

if ((err=talkWithDriver()) < NO_ERROR) break;

frameworks\native\libs\binder\IPCThreadState.cpp

if (ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr) >= 0)

在ServiceManager中注册服务(3)

IPCThreadState 对象是在创建 BpBinder对象时候创建的。 (framework\base\libs\binder\IPCThreadState.cpp)

终于来到了内核空间:binder驱动

kernel/common/drivers/staging/android/binder.c
static long binder_ioctl(struct file *filp, unsigned intcmd, unsigned long arg)

switch (cmd) {

case BINDER_WRITE_READ: {

if (bwr.write_size > 0) {

ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
http://blog.csdn.net/luoshengyang/article/details/6629298
binder事务

kernel/common/drivers/staging/android/binder.c

binder_thread_write
target_proc = target_node->proc;

注意,这里传进来的参数reply为0,tr->target.handle也为0。
case BC_TRANSACTION:

binder_transaction(proc, thread,&tr, cmd == BC_REPLY);

kernel/common/drivers/staging/android/binder.c

binder_transaction
if (tr->target.handle) {

} else {

target_node = binder_context_mgr_node;
http://blog.csdn.net/luoshengyang/article/details/6629298
核心动作:直接复制请求数据到目标进程空间

kernel/common/drivers/staging/android/binder.c

binder_transaction

t->buffer = binder_alloc_buf(target_proc, tr->data_size,

tr->offsets_size, !reply && (t->flags &TF_ONE_WAY));

.0pt;language:zh-CN'>mso-color-index:1;mso-font-kerning:12.0pt;language:en-US'>)) {

kernel/common/drivers/staging/android/binder.c

binder_transaction

if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {

if (target_wait)

wake_up_interruptible(target_wait);

在ServiceManager中注册服务(7)
http://my.oschina.net/youranhongcha/blog/152963
核心代码:

if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: