博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Binder基础业务分析
阅读量:6177 次
发布时间:2019-06-21

本文共 8759 字,大约阅读时间需要 29 分钟。

ProcessState

一个单例类,打开了Binder设备、mHandleToObject缓存了一堆BpBinder、缓存了context_mgr、启动binder线程

IPCThreadState

一个单例,保持了mProcess、保存了进程pid和uid信息、joinThreadPool让Binder线程进入消息循环getAndExecuteCommand、transact用来发送消息并接受返回。

下面是几个通信最小操作单元:

writeTransactionData 将数据写入mOut缓冲器

talkWithDriver 一次ioctrl操作

waitForResponse 等待返回

executeCommand 执行命令

sendReply 发送返回消息

因此发送transact = writeTransactionData + talkWithDriver + waitForResponse getAndExecuteCommend = talkWithDriver + executeCommand + sendReply

service_manager.c

binder_open  ->  binder_become_context_mgr  ->  binder_loop  ->  binder_parse  ->  BR_TRANSACTION  -> func ->  svcmgr_handle  ->  binder_send_replyname, handle  ----->  svcinfo_list  ->   svcinfo  ->  handle、binder_node复制代码

main_mediaserver.cpp

sp
proc(ProcessState::self());MediaPlayerService::instantiate();ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();复制代码

因为ProcessState是单例,多以必然会在当前进程打开一次binder设备文件

其中MediaPlayerService继承自BnMediaPlayService

而BnMediaPlayerService继承自BnInterface

因此MediaPlayerService继承与BnMediaPlayerService和IMediaPlayerService

继承关系为:MediaPlayerService <- BnMediaPlayerService <- BnInterface 、IMediaPlayerService <- BBinder -> IBinder

因此MediaPlayerService可以看出是BBinder的包装类,onTransact最终交由前者重写的函数处理 数据最终根据code分发到IMediaPlayerService的接口中

IMediaPlayerService: sp createMediaRecorder() sp createMetadataRetriever() sp create(); status_t decode(...);

智慧时刻:

1.构造函数: 创建了XXXService -> IXXXService -> BnXXXService -> BBinder (消息最终交由BBinder路由,分发到IXXXService不同函数中)

2.instantiate: IServiceManager->defaultServiceManager->addService(xxx, new XXXService) 首先拿到了BpServiceManager即BpBinder(0), 不明白看下面的解释

调用了BpServiceManager-BpBinder(0)->transact, 代码看下面

IServiceManager

单例defaultServiceManager(),从ProcessState中取出了BpBinder,然后构建了IServiceManager和BpServiceManager的子类BpServiceManager (Bpxxx必须要继承自Ixxx和BpInterface)

函数理解一下:

virtual sp
getService( const String16& name) const { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); return reply.readStrongBinder(); }复制代码
virtual status_t addService(const String16& name, const sp
& service, bool allowIsolated) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err;}复制代码

总体上来说,是从ProcessState中利用handle拿到了BpBinder,然后构建了外观类BpServiceManager,但最终通信还是利用BpBinder->transact,实际上是利用IPCThreadState::transact发送消息,该函数利用mIn和mOut缓存数据,利用BpBinder(0)->transact(ADD_SERVICE_TRANSACTION, data, &reply)利用一次ioctrl(fd, BC_CMD, &bwr)写操作和一次ioctrl(fd, BC_CMD, &bwr)读操作,来与驱动通信。关注一下发送的命令,ADD_SERVICE_TRANSACTION居然还藏着一个秘密,看看它是在哪被接收的吧!

IInterface.h

inline sp
interface_cast(const sp
& obj)复制代码

该函数很常见,由一个BpBinder生成一个外观类BpXXXService(继承自BpRefBase、INTERFACE)

BpINTERFACE  ->  BpInterface 、INTERFACE、BpRefBase复制代码

因此interface_cast相当于new BpINTERFACE(obj)

interface_cast相当于生成了IServiceManager子类new BpServiceManager(obj)

下面的代码很魔性,理解一下:

template
class BnInterface : public INTERFACE, public BBinder{public: virtual sp
queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const;protected: virtual IBinder* onAsBinder();};复制代码
template
class BpInterface : public INTERFACE, public BpRefBase{public: BpInterface(const sp
& remote);protected: virtual IBinder* onAsBinder();};复制代码
74#define DECLARE_META_INTERFACE(INTERFACE)                               75    static const android::String16 descriptor;                          76    static android::sp
asInterface( const android::sp
& obj); 78 virtual const android::String16& getInterfaceDescriptor() const; 79 I##INTERFACE(); 80 virtual ~I##INTERFACE(); 818283#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) 84 const android::String16 I##INTERFACE::descriptor(NAME); 85 const android::String16& I##INTERFACE::getInterfaceDescriptor() const { 87 return I##INTERFACE::descriptor; 88 } 89 android::sp
I##INTERFACE::asInterface(const android::sp
& obj) 91 { 92 android::sp
intr; 93 if (obj != NULL) { 94 intr = static_cast
(obj->queryLocalInterface( I##INTERFACE::descriptor).get());97 if (intr == NULL) { 98 intr = new Bp##INTERFACE(obj); 99 } 100 } 101 return intr; 102 } 103 I##INTERFACE::I##INTERFACE() { } 104 I##INTERFACE::~I##INTERFACE() { } 复制代码

BpBinder

继承自IBinder,成员变量mHandle,关键函数transact调用IPCThreadState::transact

IPCThreadState::self()->transact(mHandle, code, data, reply, flags);复制代码

最终调用了talkWithDriver调用得到reply

Parcel.cpp

杂项数据和Binder的包装类,主要包含mData和mObjects

依靠(uint8_t*)malloc(desired)来分配内存,并不断扩容

status_t Parcel::writeStrongBinder(const sp
& val){ return flatten_binder(ProcessState::self(), val, this);}复制代码
status_t flatten_binder(const sp
& /*proc*/, const sp
& binder, Parcel* out){ flat_binder_object obj; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder != NULL) { IBinder *local = binder->localBinder(); if (!local) { BpBinder *proxy = binder->remoteBinder(); if (proxy == NULL) { ALOGE("null proxy"); } const int32_t handle = proxy ? proxy->handle() : 0; obj.type = BINDER_TYPE_HANDLE; obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */ obj.handle = handle; obj.cookie = 0; } else { obj.type = BINDER_TYPE_BINDER; obj.binder = reinterpret_cast
(local->getWeakRefs()); obj.cookie = reinterpret_cast
(local); } } else { obj.type = BINDER_TYPE_BINDER; obj.binder = 0; obj.cookie = 0; } return finish_flatten_binder(binder, obj, out);}复制代码

1.以上函数说明BpBinder传递时,最终创建了一个flat_binder_object,并将handle写入了flat_binder_object.handle中,最终记录到了内核驱动binder_node.handle中

2.同理对于BBinder,将BBinder的对象地址写到了flat_binder_object.binder和flat_binder_object.cookie中,最终记录到了binder_node的binder和cookie中。发送端发送消息时,先根据handle在内核中找到binder_ref,即找到了binder_proc和binder_node,选择唤醒binder_proc上的等待队列即唤醒binder线程,并将消息交由binder线程返回给用户空间,用户空间取出flat_binder_object,根据里面的cookie可以得到BBinder对象。最终根据code分发给BBinder的处理函数onTransact中,由BpXXX来分发给IXXX。

binder驱动

binder线程ioctrl读数据进入休眠

IPCThreadState::transact 进行写数据

第一步:开始写数据,记录到binder_work, 并唤醒binder线程,binder_thread_read从wait_event中醒来,并将binder_work中的buffer数据取出来放到binder_transaction_data中,最后利用copy_to_user(ptr, &tr, sizeof(tr))写入用户空间binder_write_read bwr的ptr,函数返回。至此,上层就可以从ptr取出数据,并进行数据分发了。

从这里可以看出来:

A.用户空间BpXXX里面使用Parcel写入strongBinder数据flat_binder_object

B.用户空间IPCThreadState中首先将flat_binder_object写入binder_transaction_data的中,并写入mOut中,接着从mOut中取出数据放入到binder_write_read.write_buffer中,最后调用ioctrl(fd, BC_CMD, bwr)发送数据了

binder_transaction_data tr;tr.data_size = data.ipcDataSize();tr.data.ptr.buffer = data.ipcData();tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);tr.data.ptr.offsets = data.ipcObjects();复制代码

数据包装的结构为 binder_write_read包含binder_transaction_data包含flat_binder_object,额外数据放到了binder_transaction_data->data.ptr.buffer中,而flat_binder_object放到了data_ptr_offsets中

应用层Parcel -> flat_binder_object + data -> binder_transaction_data -> binder_write_read

进入内核空间 -> 发送端的binder_write_read 取出binder_transaction_data,放入接收端的binder_write_read.buffer中,至此已经将数据传入到应用接收层了

binder通信总结

  • 第一阶段:新建服务,在内核中创建binder_node (第一次与实名binder通信时,在内核中创建)
  • 第一阶段:发送binder_node到一个进程,建立binder_ref引用
  • 第三阶段:利用binder_ref发送数据到binder_node进程,并进入等待reply
  • 第四阶段:binder_node进程接收并处理数据,发送binder_reply

binder数据流向

发送端 接收端
XXXService->IXXXService
BpXXXService BnXXXService
BpInterface BnInterface
BpBinder BBinder
IPCThreadState::transact IPCThreadState::getAndExecuteCommand
/dev/binder /dev/binder
binder_ioctl binder_ioctl
binder_write_thread binder_read_transaction
binder_transaction binder_transaction

转载地址:http://mnzda.baihongyu.com/

你可能感兴趣的文章
Amoeba新版本MYSQL读写分离配置
查看>>
制作XPE启动光盘的教程
查看>>
计算机网络基础
查看>>
一步步打造漂亮的新闻列表(无刷新分页、内容预览)(2)
查看>>
cron任务计划
查看>>
我也参加了唐骏一手推动的【2015年微创中国运动会】
查看>>
认证模式之SSL模式
查看>>
如何在 Linux 中统计一个进程的线程数
查看>>
NVIDIA新作解读:用GAN生成前所未有的高清图像(附PyTorch复现) | PaperDaily #15
查看>>
CString、CTime和COleDateTime转换
查看>>
在linux虚机中装vmtools
查看>>
WCF技术剖析之十三:序列化过程中的已知类型(Known Type)
查看>>
linux设备驱动程序--类class的实现
查看>>
中国云计算应用进入集中爆发期
查看>>
算法精解---计数排序
查看>>
DockOne微信分享(一二八):容器如何监控?
查看>>
谈谈分布式事务(Distributed Transaction)[共5篇]
查看>>
如何确保快递“最后一公里” ,亚马逊打算送到你的汽车后备箱
查看>>
Gartner:财务应用迁移到云 速度超出预期
查看>>
阿里云向物流业渗透 货运司机受益
查看>>