我的进阶曲线之八
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)) {
什么是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)) {
相关文章推荐
- lamp安装总结
- Last Defence - UVA7045
- 自学编程的那些事
- 在ViewPager中的Fragment添加控件及TextureView
- 我的进阶曲线之六
- 【未完】mail邮件报警系统搭建
- extjs中store的reload事件异步问题解决
- Redis详解——常用命令总结(完善中)
- 转载:个人电子技术经验积累
- centos7 nfs服务器配置
- @font-face
- openwrt增加自己应用步骤
- request_irq() | 注册中断服务参考
- android 学习 IPC机制
- 近期的总结
- 【学习】RecyclerView
- position与frame bounds anchorPoint的深入理解
- thinkpad不小心卸载内置蓝牙设备
- ubuntu 15.04 x64 安装 chrome
- linux编译安装PHP