binder 原理
一. binder 概述 本文以社区master分支代码、rk3568设备为参考。binder 是解决进程间通信的框架, 起源于OpenBinder项目,发展于Android项目,现在已经和入Linux Kernel,目前演变成RPC工具。 OpenHarmony中对应层次: 驱动://kernel/linux/l
一. binder 概述
本文以社区master分支代码、rk3568设备为例/参照。
binder 是解决进程间通信的框架, 起源于OpenBinder项目,发展于Android项目,现在已经和入Linux Kernel,目前演变成RPC工具。
- OpenHarmony中对应层次:
- 驱动://kernel/linux/linux-5.10/drivers/android
- 服务://foundation/communication/ipc
- 框架:各种NAPI里面和对应的服务接口:如//base/powermgr/power_manager/frameworks/napi和//base/powermgr/power_manager/services
功能描述:
提供CS(Client-Server)模型,服务请求方(Client)可获取提供服务提供方(Server)的代理 (Proxy),并通过此代理读写数据来实现进程间的数据通信。通常,系统能力(System Ability)Server侧会先注册到系统能力管理者(System Ability Manager,缩写SAMgr)中,SAMgr负责管理这些SA并向Client提供相关的接口。Client要和某个具体的SA通信,必须先通过SAMgr获取该SA的代理,然后使用代理和SA通信。通过napi可以对外提供js接口,三方应用可以通过js接口调用client接口与服务端进行通信。
注意:单个设备上跨进程通信时,传输的数据量最大约为1MB,若数据太大,可以通过共享内存方式传递。编译使用:
内核态的Binder驱动实现代码,在 //kernel/linux/linux-5.10/drivers/android/ 目录下。在编译Linux内核时,通过kernel/linux/config/linux-5.10/arch/arm64/configs/rk3568_standard_defconfig 文件中的配置,可将Binder驱动模块编译进内核:
#
# Android
#
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
# CONFIG_ANDROID_BINDERFS is not set
CONFIG_ANDROID_BINDER_DEVICES="binder,hwbinder,vndbinder"
# CONFIG_ANDROID_BINDER_IPC_SELFTEST is not set
CONFIG_BINDER_TRANSACTION_PROC_BRIEF=y
# end of Android
二. binder 原理
ipc 通信已有较详细文档,不再细述,此处大体将一下binder的工作原理/流程
proxy: 客户端获取代理,在代理中调用sendrequest 向stub发送请求,含消息码; proxy继承peerholder,peerholder中有Remote函数,返回IRemoteObject对象, IRemoteObject对象中有SendRequest接口,proxy子类实现SendRequest接口
stub: 继承IPCObjectStub (也是iremoteObject对象),其实peerhold是IPCObjectStub 的引用对象,实际类型是 IPCObjectProxy 。
这两者在ipc框架中,IPCObjectProxy 实际使用sendrequest ,IPCObjectStub便会调用OnremoteRequest,如下面代码。
注册服务:IPCObjectStub的对象经binder驱动,注册到samgr系统服务管理进程中去。 据注册的IPCObjectStub new一个IPCObjectProxy对象存储在samgr的map中。客户端可通过samgr获取此proxy建立联系。
int IPCObjectStub::SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
std::map<uint32_t, OHOS::IPCObjectStub::IPCObjectStubFunc>::iterator it = funcMap_.find(code);
if (it != funcMap_.end()) {
OHOS::IPCObjectStub::IPCObjectStubFunc itFunc = it->second;
if (itFunc != nullptr) {
return (this->*itFunc)(code, data, reply, option);
}
}
return IPCObjectStub::SendRequestInner(code, data, reply, option);
}
int IPCObjectStub::SendRequestInner(uint32_t code,
MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
int result = ERR_NONE;
std::unique_lock<std::recursive_mutex> lockGuard(serialRecursiveMutex_, std::defer_lock);
if (serialInvokeFlag_) {
lockGuard.lock();
}
auto start = std::chrono::steady_clock::now();
lastRequestTime_ = static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::milliseconds>(
start.time_since_epoch()).count());
result = OnRemoteRequest(code, data, reply, option);
auto finish = std::chrono::steady_clock::now();
uint32_t duration = static_cast<uint32_t>(std::chrono::duration_cast<std::chrono::microseconds>(
finish - start).count());
if (duration >= IPC_CMD_PROCESS_WARN_TIME) {
ZLOGW(LABEL, "stub:%{public}s deal request code:%{public}u cost time:%{public}ums",
ProcessSkeleton::ConvertToSecureDesc(Str16ToStr8(GetObjectDescriptor())).c_str(),
code, duration / COEFF_MILLI_TO_MICRO);
}
IPCPayloadStatisticsImpl& instance = IPCPayloadStatisticsImpl::GetInstance();
if (instance.GetStatisticsStatus()) {
int32_t currentPid = IPCSkeleton::GetCallingPid();
std::u16string currentDesc = GetObjectDescriptor();
int32_t currentCode = static_cast<int32_t>(code);
if (!instance.UpdatePayloadInfo(currentPid, currentDesc, currentCode, duration)) {
ZLOGE(LABEL, "Process load information update failed");
}
}
return result;
}
数据传递:数据传递过程中要传递类对象时,可通过Parcel类处理,会通过Marshalling, Unmarshalling函数通过invoker将参数指定的IRemoteObject对象扁平化(序列化),传送到binder
bool IRemoteObject::Marshalling(Parcel &parcel) const
{
IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT);
if (invoker != nullptr) {
return invoker->FlattenObject(parcel, this);
}
return false;
}
bool IRemoteObject::Marshalling(Parcel &parcel, const sptr<IRemoteObject> &object)
{
IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT);
if (invoker != nullptr) {
return invoker->FlattenObject(parcel, object);
}
return false;
}
sptr<IRemoteObject> IRemoteObject::Unmarshalling(Parcel &parcel)
{
IRemoteInvoker *invoker = IPCThreadSkeleton::GetRemoteInvoker(IRemoteObject::IF_PROT_DEFAULT);
if (invoker != nullptr) {
return invoker->UnflattenObject(parcel);
}
return nullptr;
}
更多推荐
所有评论(0)