背景知识
hi,粉丝朋友们大家好:
今天带大家分析一下mapper模块的Hidl相关内容,主要目的就是带大家看看直通式passthrough的方式是怎么样的,有哪些明显特点,及系统源码具体是怎么实现的直通式。
1、首先知道直通式和绑定式最重要区别就是hal相关代码是否运行在客户端进程
如上图展示直通式情况就是无论经过多少hidl包装始终hal代码都是运行在客户端systemserver进程
绑定式这个时候就涉及从systemserver跨进程到对应的hal进程
2、那么具体看hal代码啥的怎么区分呢,怎么知道他是直通还是绑定式呢?
manifest中看看hal注册的情况
可以去以下路径查看,这个就是最后编译出来的vendor下面的manifest文件
out/target/product/nx563j/vendor/etc/vintf/manifest.xml
比如我们要看mapper模块,可以看到这里transport写的是passthrough所以他就在直通式
<hal format="hidl">
<name>android.hardware.graphics.mapper</name>
<transport arch="32+64">passthrough</transport>
<version>2.1</version>
<interface>
<name>IMapper</name>
<instance>default</instance>
</interface>
<fqname>@2.1::IMapper/default</fqname>
</hal>
再看看其他模块比如android.hardware.bluetooth模块,明显看到这里的transport就是hwbinder他就是绑定式
<hal format="hidl">
<name>android.hardware.bluetooth</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>IBluetoothHci</name>
<instance>default</instance>
</interface>
<fqname>@1.0::IBluetoothHci/default</fqname>
</hal>
还有也可以通过源码分析方法:
比如mapper模块
明显看到这里mapper最后的编译只是一个so文件即cc_library_shared标签,没见到有其他cc_binary标签,所以最终产物只有一个android.hardware.graphics.mapper@2.0-impl.so
大家想想本身mapper就该在客户端进程运行,没有自己的进程,所以自然要以so形式存在,而不是可执行文件存在
再看看蓝牙模块android.hardware.bluetooth,这里明显看出编译的是一个cc_binary可执行文件android.hardware.bluetooth@1.0-servicee而且还是开机自启动有对于的rc文件的
源码分析
从应用层面构造Gralloc2Mapper开始分析
Gralloc2Mapper::Gralloc2Mapper() {
ATRACE_CALL();
mMapper = hardware::graphics::mapper::V2_0::IMapper::getService();
if (mMapper == nullptr) {
ALOGW("mapper 2.x is not supported");
return;
}
if (mMapper->isRemote()) {
LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
}
ALOGW("mapper 2.x is supported");
// IMapper 2.1 is optional
mMapperV2_1 = IMapper::castFrom(mMapper);
}
明显看到这里关键地方其实就是调用了hardware::graphics::mapper::V2_0::IMapper::getService()获取的,这里的大家注意了客户端调用hardware::graphics::mapper::V…就代表这个代码不会在应用业务代码里面,一般是在这个hal文件模块生成的相关文件中去看。
到了hal生成文件的方法:
out/soong/.intermediates/hardware/interfaces/graphics/mapper/2.0/android.hardware.graphics.mapper@2.0_genc++/gen/android/hardware/graphics/mapper/2.0/MapperAll.cpp
::android::sp<IMapper> IMapper::getService(const std::string &serviceName, const bool getStub) {
return ::android::hardware::details::getServiceInternal<BpHwMapper>(serviceName, true, getStub);
}
接下来看看getServiceInternal方法:
在如下路径
system/libhidl/transport/include/hidl/HidlTransportSupport.h
template <typename BpType, typename IType = typename BpType::Pure,
typename = std::enable_if_t<std::is_same<i_tag, typename IType::_hidl_tag>::value>,
typename = std::enable_if_t<std::is_same<bphw_tag, typename BpType::_hidl_tag>::value>>
sp<IType> getServiceInternal(const std::string& instance, bool retry, bool getStub) {
using ::android::hidl::base::V1_0::IBase;
sp<IBase> base = getRawServiceInternal(IType::descriptor, instance, retry, getStub);
if (base == nullptr) {
return nullptr;
}
if (base->isRemote()) {
// getRawServiceInternal guarantees we get the proper class
return sp<IType>(new BpType(getOrCreateCachedBinder(base.get())));
}
return IType::castFrom(base);
}
接下来又看看getRawServiceInternal方法:
system/libhidl/transport/ServiceManagement.cpp
sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
const std::string& instance,
bool retry, bool getStub) {
using Transport = IServiceManager1_0::Transport;
sp<Waiter> waiter;
sp<IServiceManager1_1> sm;
Transport transport = Transport::EMPTY;
sm = defaultServiceManager1_1();
//获取transport类型,其实就是获取一下是PASSTHROUGH还是HWBINDER,即直通式还是绑定式
//这里其实本质是访问一下写hidl注册的mainfest为依据
Return<Transport> transportRet = sm->getTransport(descriptor, instance);
transport = transportRet;
const bool vintfHwbinder = (transport == Transport::HWBINDER);
const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
const bool trebleTestingOverride = isTrebleTestingOverride();
const bool allowLegacy = !kEnforceVintfManifest || (trebleTestingOverride && isDebuggable());
const bool vintfLegacy = (transport == Transport::EMPTY) && allowLegacy;
//vintfHwbinder为true则会进入下面
for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
Return<sp<IBase>> ret = sm->get(descriptor, instance);
}
//vintfPassthru为true则会进入下面
if (getStub || vintfPassthru || vintfLegacy) {
//获取相应的getPassthroughServiceManager
const sp<IServiceManager1_0> pm = getPassthroughServiceManager();
if (pm != nullptr) {
//调用对应的getPassthroughServiceManager的get方法
sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
return base;
}
}
ALOGE(" getRawServiceInternal end 2");
return nullptr;
}
这里看看manifest中mapper的是hwbinder还是passthrough
<hal format="hidl">
<name>android.hardware.graphics.mapper</name>
<transport arch="32+64">passthrough</transport>
<version>2.1</version>
<interface>
<name>IMapper</name>
<instance>default</instance>
</interface>
<fqname>@2.1::IMapper/default</fqname>
</hal>
可以看到这里显示2.1版本,实际如果是2.0版本其实也没有关系,一样可以正常返回哈
识别为passthrough模式后,那么接下来就要获取相关的hal对象这个hal对象是直接调用的getPassthroughServiceManager获取的manager,这个manager就是个本地的,不需要进行跨进程获取获取
看看是怎么获取的
system/libhidl/transport/ServiceManagement.cpp
Return<sp<IBase>> get(const hidl_string& fqName,
const hidl_string& name) override {
openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
IBase* (*generator)(const char* name);
*(void **)(&generator) = dlsym(handle, sym.c_str());
//最重要调用到了HIDL_FETCH_IMapper
ret = (*generator)(name.c_str());
return false;
});
return ret;
}
先看看openLibs方法
system/libhidl/transport/ServiceManagement.cpp
```cpp
static void openLibs(
const std::string& fqName,
const std::function<bool /* continue */ (void* /* handle */, const std::string& /* lib */,
const std::string& /* sym */)>& eachLib) {
//fqName looks like android.hardware.foo@1.0::IFoo
size_t idx = fqName.find("::");
if (idx == std::string::npos ||
idx + strlen("::") + 1 >= fqName.size()) {
LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
return;
}
std::string packageAndVersion = fqName.substr(0, idx);
std::string ifaceName = fqName.substr(idx + strlen("::"));
const std::string prefix = packageAndVersion + "-impl";
const std::string sym = "HIDL_FETCH_" + ifaceName;
//主要为了拼出相关的的so文件名字,prefix: android.hardware.graphics.mapper@2.0-impl sym HIDL_FETCH_IMapper
for (const std::string& path : paths) { //开始相关的odm,vendor目录寻找so
std::vector<std::string> libs = findFiles(path, prefix, ".so");
LOG(ERROR) << "findFiles path " << path;
for (const std::string &lib : libs) {
const std::string fullPath = path + lib;
//dlopen加载对于的so
if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
handle = dlopen(fullPath.c_str(), dlMode);
} else {
handle = android_load_sphal_library(fullPath.c_str(), dlMode);
}
//加载后,回调eachLib方法
if (!eachLib(handle, lib, sym)) {
return;
}
}
}
}
这个地方openLibs干的关键事情:
1、通过descriptor把so名字拼出来:so名字:android.hardware.graphics.mapper@2.0-impl ,并且进行dlopen,变成handle
2、同时也拼出一个so里面含有的符号:HIDL_FETCH_IMapper
3、回调eachLib方法
下面来分析eachLib方法,就是一个lamada表达式
openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
IBase* (*generator)(const char* name);
*(void **)(&generator) = dlsym(handle, sym.c_str());
//最重要调用到了HIDL_FETCH_IMapper
ret = (*generator)(name.c_str());
return false;
});
这个HIDL_FETCH_IMapper一调用就到了正式的hidl的mapper模块了
hardware/interfaces/graphics/mapper/2.0/default/passthrough.cpp
extern "C" IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
return GrallocLoader::load();
}
看看GrallocLoader::load()方法
static IMapper* load() {
const hw_module_t* module = loadModule();//调用了loadModule获取hw_module_t
if (!module) {
return nullptr;
}
auto hal = createHal(module);
if (!hal) {
return nullptr;
}
return createMapper(std::move(hal));
}
来看看loadModule
// load the gralloc module
static const hw_module_t* loadModule() {
const hw_module_t* module;
int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
return module;
}
这里其实就是开始打开一个id为GRALLOC_HARDWARE_MODULE_ID的硬件抽象模块
再看看createHal方法
// create a MapperHal instance
static std::unique_ptr<hal::MapperHal> createHal(const hw_module_t* module) {
int major = getModuleMajorApiVersion(module);
//根据主版本号来创建初始化不一样的Gralloc
switch (major) {
case 1: {
auto hal = std::make_unique<Gralloc1Hal>();
return hal->initWithModule(module) ? std::move(hal) : nullptr;
}
case 0: {
auto hal = std::make_unique<Gralloc0Hal>();
return hal->initWithModule(module) ? std::move(hal) : nullptr;
}
default:
ALOGE("unknown gralloc module major version %d", major);
return nullptr;
}
}
再看看createMapper
//主要就是返回GrallocMapper指针
static IMapper* createMapper(std::unique_ptr<hal::MapperHal> hal) {
auto mapper = std::make_unique<GrallocMapper<hal::Mapper>>();
return mapper->init(std::move(hal)) ? mapper.release() : nullptr;
}
};
哪里触发的创建Mapper
这个其实是在第一次dequeueBuffer时候会有这个触发
具体trace如下:
在dequeueBuffer时候会构造GraphicBuffer对象
这里的GraphicBuffer构造调用了GraphicBufferMapper方法
流程总结图
本文章对应视频手把手教你学framework:
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
私聊作者+v(androidframework007)
点击这里 https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw
视频:https://www.bilibili.com/video/BV1wc41117L4/