一. binder 概述

本文以社区master分支代码、rk3568设备为例/参照。
binder 是解决进程间通信的框架, 起源于OpenBinder项目,发展于Android项目,现在已经和入Linux Kernel,目前演变成RPC工具。

  1. OpenHarmony中对应层次:
  • 驱动://kernel/linux/linux-5.10/drivers/android
  • 服务://foundation/communication/ipc
  • 框架:各种NAPI里面和对应的服务接口:如//base/powermgr/power_manager/frameworks/napi和//base/powermgr/power_manager/services
  1. 功能描述:
    提供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,若数据太大,可以通过共享内存方式传递。

  2. 编译使用:
    内核态的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的工作原理/流程

img

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;
}

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐