背景
我一直有一个观点,就是一个进程,vnd binder不能和binder同时使用,但是我发现我这个观点是错误的。
一、错误观点的由来
形成这个错误观点的两个理由如下:
1.1 官方图中,不允许同一个进程,同时打开vnd binder和binder的设备节点
从图中可以看到可以,没有一个进程可以同时打开dev/binder
和dev/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]
中ProcessState
和ABinderProcess_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是第三方的。