[098]vnd binder和binder的共存问题

785 阅读3分钟

背景

我一直有一个观点,就是一个进程,vnd binder不能和binder同时使用,但是我发现我这个观点是错误的。

一、错误观点的由来

形成这个错误观点的两个理由如下:

1.1 官方图中,不允许同一个进程,同时打开vnd binder和binder的设备节点

从图中可以看到可以,没有一个进程可以同时打开dev/binderdev/vndbinder

1.2 看起里vnd binder和binder是同一套代码

可以看到没有专门对vndbinder的框架代码

官方文档也说,是通过调用ProcessState::initWithDriver("/dev/vndbinder");初始化vndbinder或binder

ProcessState是一个"进程单例",所以不能同时创建两个对象。

1.3 小结

因为这两个理由,让我天真的以为Google指导手册上不允许同一个进程同时使用vnd binder和binder,代码上通过一套框架代码来避免一个进程同时打开,是不是这两个理由天衣无缝,完美支持了我的观点。

二、引发我思考的一段代码

引发我思考的其实是如下这段代码

代码编号[2.1]
http://aospxref.com/android-14.0.0_r2/xref/device/google/felix/vibrator/cs40l26/service.cpp

int main() {

    ProcessState::initWithDriver("/dev/vndbinder");

    auto svcBinder = svc->asBinder();
    binder_status_t status = AServiceManager_addService(svcBinder.get(), svcName.c_str());
    LOG_ALWAYS_FATAL_IF(status != STATUS_OK);

    ProcessState::self()->setThreadPoolMaxThreadCount(1);
    ProcessState::self()->startThreadPool();
    //为什么反复调用setThreadPoolMaxThreadCount
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    ABinderProcess_joinThreadPool();

    return EXIT_FAILURE;  // should not reach
}

查看如下函数的实现:

AServiceManager_addService

http://aospxref.com/android-14.0.0_r2/xref/frameworks/native/libs/binder/ndk/service_manager.cpp


binder_exception_t AServiceManager_addService(AIBinder* binder, const char* instance) {
    if (binder == nullptr || instance == nullptr) {
        return EX_ILLEGAL_ARGUMENT;
    }

    sp<IServiceManager> sm = defaultServiceManager();
    status_t exception = sm->addService(String16(instance), binder->getBinder());
    return PruneException(exception);
}

ABinderProcess_setThreadPoolMaxThreadCount

#include <android/binder_process.h>

#include <mutex>

#include <android-base/logging.h>
#include <binder/IPCThreadState.h>

using ::android::IPCThreadState;
using ::android::ProcessState;

bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads) {
    return ProcessState::self()->setThreadPoolMaxThreadCount(numThreads) == 0;
}

疑点1:为什么不直接调用defaultServiceManager进行add

疑点2:为什么调用ProcessState::self()->setThreadPoolMaxThreadCount(1)后重复调用ProcessState::self()->setThreadPoolMaxThreadCount(0),参数还从1变成了0

2.1 小结

看到这里的时候,我已经蒙圈了,写代码的人不可能犯这种低级的错误,最关键的是在AS的Android 14的模拟器上,我已经看到有的进程同时打开三个binder设备节点。

三、真的有两个ProcessState的存在

唯一的解释代码编号[2.1]ProcessStateABinderProcess_setThreadPoolMaxThreadCount调用的ProcessState不是同一个,有两个ProcessState的存在。

3.1 vendor通过使用NDK使用AIDL,不能通过VNDK下libbinder使用AIDL

官网有这样一段话

source.android.google.cn/docs/core/a…

vendor通过使用NDK中libbinder_ndk使用AIDL,不能通过VNDK下libbinder使用AIDL

ABinderProcess_setThreadPoolMaxThreadCount通过libbinder_ndk链接/system/lib64/libbinder.so

3.2 Linker Namespace

官网提供了一种机制,来解决两个libbinder.so的相同库名称和不同符号的库的冲突问题。 source.android.com/docs/core/a…

3.4 小结

通过Linker Namespace机制,的确可以让vnd binder和binder共存。

总结

最后画一个图来表达一下这个功能,这个功能其实也在一定程度支持了hidl向aidl转移的技术可能性,因为如果一个进程之前是hwbinder和vndbinder,这个时候要把hwbinder切到了binder,如果无法让vnd binder和binder共存,就必须让这个进程摆脱vndbinder的使用,这个是很难的,尤其是这个进程依赖的vndbinder是第三方的。