HIDL Hal 开发笔记5----Same-Process HALs 实例分析

目录


|----------------------------|
| Same-Process HALs 实例分析 |

一、整体框架

有的 HAL 模块有性能需求,调用它们不能太慢了,有的 hal 模块,是给当前进程提供某种功能,需要在当前进程下执行,跨进程通信的方式不能满足其需求。这类 HAL 以 so 库的形式存在,Framework 层会直接链接这些 so 库,以保证调用的性能。这类 Hal 称之为 Same-Process HALs,整体架构如下:

android.hardware.graphics.mapper hal 模块就是一个 Same-Process HALs

其源码在 hardware/interfaces/graphics/mapper 目录下:

这里有三个版本,我们以 2.0 为基础来做分析(模拟器使用的是 2.0)


二、HAL 层实现

我们从 hardware/interfaces/graphics/mapper/2.0/default/Android.bp 下手:

c 复制代码
cc_library_shared {
    name: "android.hardware.graphics.mapper@2.0-impl",
    defaults: ["hidl_defaults"],
    vendor: true,
    relative_install_path: "hw",
    srcs: ["passthrough.cpp"],
    header_libs: [
        "android.hardware.graphics.mapper@2.0-passthrough"
    ],
    shared_libs: [
        "android.hardware.graphics.mapper@2.0",
        "libbase",
        "libcutils",
        "libhardware",
        "libhidlbase",
        "libhidltransport",
        "liblog",
        "libsync",
        "libutils",
    ],
    cflags: ["-DLOG_TAG=\"MapperHal\""],
}

区别于前面讲的 hal 都有一个可执行程序和 so 共享库,这里只有一个 so 共享库。

库对应的源码是:

c 复制代码
// hardware/interfaces/graphics/mapper/2.0/default/passthrough.cpp

#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <mapper-passthrough/2.0/GrallocLoader.h>

using android::hardware::graphics::mapper::V2_0::IMapper;
using android::hardware::graphics::mapper::V2_0::passthrough::GrallocLoader;

extern "C" IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
    return GrallocLoader::load();
}

就一个函数 HIDL_FETCH_IMapper,具体实现我们等下来看。

我们接着看模拟器对应的 VINTF配置文件 device/generic/goldfish/manifest.xml 中配置了 mapper 的 VINTF信息

c 复制代码
<hal format="hidl">
    <name>android.hardware.graphics.mapper</name>
    <transport arch="32+64">passthrough</transport>
    <version>2.0</version>
    <interface>
        <name>IMapper</name>
        <instance>default</instance>
    </interface>
</hal>

注意一下,这里 transport 类型是 passthrough。


三、谁来链接 hal 库

在 SurfaceFlinger 中,在分配图形缓存内存的过程中会构建一个 Gralloc2Mapper 对象:

c 复制代码
// frameworks/native/libs/ui/Gralloc2.cpp
Gralloc2Mapper::Gralloc2Mapper() {
    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");
    }

    // IMapper 2.1 is optional
    mMapperV2_1 = IMapper::castFrom(mMapper);
}

这里调用 getService 函数获取 mapper 服务。

getService 定义在 hidl 生成的代码
out/soong/.intermediates/hardware/interfaces/graphics/mapper/2.0/android.hardware.graphics.mapper@2.0_genc++_headers/gen/android/hardware/graphics/mapper/2.0/IMapper.h

c 复制代码
static ::android::sp<IMapper> getService(const std::string &serviceName="default", bool getStub=false);

IMapper::getService 实现在 hidl 生成的代码 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 中:

c 复制代码
::android::sp<IMapper> IMapper::getService(const std::string &serviceName, const bool getStub) {
    return ::android::hardware::details::getServiceInternal<BpHwMapper>(serviceName, true, getStub);
}

这里调用没传参数,就是使用默认参数 "default" 和 false。

接着调用 getServiceInternal函数:

c 复制代码
// 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

c 复制代码
// 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 = ::android::hidl::manager::V1_0::IServiceManager::Transport;
    using ::android::hidl::manager::V1_0::IServiceManager;
    sp<Waiter> waiter;

    sp<IServiceManager1_1> sm;
    Transport transport = Transport::EMPTY;
    if (kIsRecovery) {
        transport = Transport::PASSTHROUGH;
    } else {
        sm = defaultServiceManager1_1();
        if (sm == nullptr) {
            ALOGE("getService: defaultServiceManager() is null");
            return nullptr;
        }

        // passthrough
        Return<Transport> transportRet = sm->getTransport(descriptor, instance);

        if (!transportRet.isOk()) {
            ALOGE("getService: defaultServiceManager()->getTransport returns %s",
                  transportRet.description().c_str());
            return nullptr;
        }
        transport = transportRet;
    }

    // false
    const bool vintfHwbinder = (transport == Transport::HWBINDER);
    // true
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH);

#ifdef ENFORCE_VINTF_MANIFEST

#ifdef LIBHIDL_TARGET_DEBUGGABLE
    const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
    const bool trebleTestingOverride = env && !strcmp(env, "true");
    const bool vintfLegacy = (transport == Transport::EMPTY) && trebleTestingOverride;
#else   // ENFORCE_VINTF_MANIFEST but not LIBHIDL_TARGET_DEBUGGABLE
    const bool trebleTestingOverride = false;
    const bool vintfLegacy = false;
#endif  // LIBHIDL_TARGET_DEBUGGABLE

#else   // not ENFORCE_VINTF_MANIFEST
    const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
    const bool trebleTestingOverride = env && !strcmp(env, "true");
    const bool vintfLegacy = (transport == Transport::EMPTY);
#endif  // ENFORCE_VINTF_MANIFEST

    // 不走这儿
    for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
        if (waiter == nullptr && tries > 0) {
            waiter = new Waiter(descriptor, instance, sm);
        }
        if (waiter != nullptr) {
            waiter->reset();  // don't reorder this -- see comments on reset()
        }
        Return<sp<IBase>> ret = sm->get(descriptor, instance);
        if (!ret.isOk()) {
            ALOGE("getService: defaultServiceManager()->get returns %s for %s/%s.",
                  ret.description().c_str(), descriptor.c_str(), instance.c_str());
            break;
        }
        sp<IBase> base = ret;
        if (base != nullptr) {
            Return<bool> canCastRet =
                details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);

            if (canCastRet.isOk() && canCastRet) {
                if (waiter != nullptr) {
                    waiter->done();
                }
                return base; // still needs to be wrapped by Bp class.
            }

            if (!handleCastError(canCastRet, descriptor, instance)) break;
        }

        // In case of legacy or we were not asked to retry, don't.
        if (vintfLegacy || !retry) break;

        if (waiter != nullptr) {
            ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
            waiter->wait(true /* timeout */);
        }
    }

    if (waiter != nullptr) {
        waiter->done();
    }

    // 走这儿
    if (getStub || vintfPassthru || vintfLegacy) {
        const sp<IServiceManager> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
            if (!getStub || trebleTestingOverride) {
                base = wrapPassthrough(base);
            }
            return base;
        }
    }

    return nullptr;
}

接着调用 getPassthroughServiceManager

c 复制代码
// system/libhidl/transport/ServiceManagement.cpp
sp<IServiceManager1_0> getPassthroughServiceManager() {
    return getPassthroughServiceManager1_1();
}
sp<IServiceManager1_1> getPassthroughServiceManager1_1() {
    static sp<PassthroughServiceManager> manager(new PassthroughServiceManager());
    return manager;
}

就是 new 一个 PassthroughServiceManager,PassthroughServiceManager 实现了 IServiceManager 接口。

接着调用 PassthroughServiceManager 的 get 函数:

c 复制代码
Return<sp<IBase>> get(const hidl_string& fqName,
                      const hidl_string& name) override {
    sp<IBase> ret = nullptr;

    openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
        IBase* (*generator)(const char* name);
        *(void **)(&generator) = dlsym(handle, sym.c_str());
        if(!generator) {
            const char* error = dlerror();
            LOG(ERROR) << "Passthrough lookup opened " << lib
                       << " but could not find symbol " << sym << ": "
                       << (error == nullptr ? "unknown error" : error);
            dlclose(handle);
            return true;
        }

        ret = (*generator)(name.c_str());

        if (ret == nullptr) {
            dlclose(handle);
            return true; // this module doesn't provide this instance name
        }

        // Actual fqname might be a subclass.
        // This assumption is tested in vts_treble_vintf_test
        using ::android::hardware::details::getDescriptor;
        std::string actualFqName = getDescriptor(ret.get());
        CHECK(actualFqName.size() > 0);
        registerReference(actualFqName, name);
        return false;
    });

    return ret;
}

调用 openlib 并传入一个 lamda:

c 复制代码
// fqName:android.hardware.graphics.mapper@2.0::IMapper
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;
        }
        // android.hardware.graphics.mapper@2.0
        std::string packageAndVersion = fqName.substr(0, idx);
        // IMapper
        std::string ifaceName = fqName.substr(idx + strlen("::"));
        // android.hardware.graphics.mapper@2.0-impl
        const std::string prefix = packageAndVersion + "-impl";
        // HIDL_FETCH_IMapper
        const std::string sym = "HIDL_FETCH_" + ifaceName;

        constexpr int dlMode = RTLD_LAZY;
        void* handle = nullptr;

        dlerror(); // clear

        static std::string halLibPathVndkSp = android::base::StringPrintf(
            HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, details::getVndkVersionStr().c_str());
        // 从固定的几个目录查找 so 库
        std::vector<std::string> paths = {
            HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
#ifndef __ANDROID_VNDK__
            HAL_LIBRARY_PATH_SYSTEM,
#endif
        };

#ifdef LIBHIDL_TARGET_DEBUGGABLE
        const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
        const bool trebleTestingOverride = env && !strcmp(env, "true");
        if (trebleTestingOverride) {
            // Load HAL implementations that are statically linked
            handle = dlopen(nullptr, dlMode);
            if (handle == nullptr) {
                const char* error = dlerror();
                LOG(ERROR) << "Failed to dlopen self: "
                           << (error == nullptr ? "unknown error" : error);
            } else if (!eachLib(handle, "SELF", sym)) {
                return;
            }

            const char* vtsRootPath = std::getenv("VTS_ROOT_PATH");
            if (vtsRootPath && strlen(vtsRootPath) > 0) {
                const std::string halLibraryPathVtsOverride =
                    std::string(vtsRootPath) + HAL_LIBRARY_PATH_SYSTEM;
                paths.insert(paths.begin(), halLibraryPathVtsOverride);
            }
        }
#endif

        // 从固定的几个目录查找 android.hardware.graphics.mapper@2.0-impl.so 库
        for (const std::string& path : paths) {
            std::vector<std::string> libs = findFiles(path, prefix, ".so");

            for (const std::string &lib : libs) {
                const std::string fullPath = path + lib;

                if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
                    // dlopen 打开 so 库
                    handle = dlopen(fullPath.c_str(), dlMode);
                } else {
#if !defined(__ANDROID_RECOVERY__)
                    handle = android_load_sphal_library(fullPath.c_str(), dlMode);
#endif
                }

                if (handle == nullptr) {
                    const char* error = dlerror();
                    LOG(ERROR) << "Failed to dlopen " << lib << ": "
                               << (error == nullptr ? "unknown error" : error);
                    continue;
                }

                // 调用传入的回调
                if (!eachLib(handle, lib, sym)) {
                    return;
                }
            }
        }
    }

再看 lamda 回调:

c 复制代码
openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
    IBase* (*generator)(const char* name);
    // 加载 HIDL_FETCH_IVibrator 符号
    *(void **)(&generator) = dlsym(handle, sym.c_str());
    if(!generator) {
        const char* error = dlerror();
        LOG(ERROR) << "Passthrough lookup opened " << lib
                   << " but could not find symbol " << sym << ": "
                   << (error == nullptr ? "unknown error" : error);
        dlclose(handle);
        return true;
    }
    // 调用 HIDL_FETCH_IMapper 函数
    ret = (*generator)(name.c_str());

    if (ret == nullptr) {
        dlclose(handle);
        return true; // this module doesn't provide this instance name
    }

    // Actual fqname might be a subclass.
    // This assumption is tested in vts_treble_vintf_test
    using ::android::hardware::details::getDescriptor;
    std::string actualFqName = getDescriptor(ret.get());
    CHECK(actualFqName.size() > 0);
    registerReference(actualFqName, name);
    return false;
});

HIDL_FETCH_IMapper 函数实现在 hardware/interfaces/graphics/mapper/2.0/default/passthrough.cpp

c 复制代码
extern "C" IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
    return GrallocLoader::load();
}

这里接着调用 load 方法:

c 复制代码
// hardware/interfaces/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
static IMapper* load() {
    // 加载到 mmaper 传统 hal 的 hw_module_t
    const hw_module_t* module = loadModule();
    if (!module) {
        return nullptr;
    }
    auto hal = createHal(module);
    if (!hal) {
        return nullptr;
    }
    return createMapper(std::move(hal));
}

调用 loadModule 加载传统 hal:

c 复制代码
// hardware/interfaces/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
// 加载传统 hal 
static const hw_module_t* loadModule() {
    const hw_module_t* module;
    int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
    if (error) {
        ALOGE("failed to get gralloc module");
        return nullptr;
    }

    return module;
}

传统的 HAL 一般由芯片/厂商提供,比如 hardware/qcom/display/msm8909/libgralloc/gralloc.cpp 就是高通针对 msm8909 芯片提供的传统 mapper hal。

接着调用 createHal 创建一个 MapperHal 对象返回,MapperHal 就是对 hw_module_t 接口的包装。

c 复制代码
static std::unique_ptr<hal::MapperHal> createHal(const hw_module_t* module) {
    int major = getModuleMajorApiVersion(module);
    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 对象返回,GrallocMapper 实现了 IMapper 接口:

c 复制代码
// hardware/interfaces/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
    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;
    }

层层返回后,Gralloc2Mapper 中 getService 拿到的就是 GrallocMapper 对象,实际的功能调用是通过加载 so 库,调用具体符号实现的,并没有跨进程调用,减少调用 hal 过程的性能损耗。

c 复制代码
// frameworks/native/libs/ui/Gralloc2.cpp
Gralloc2Mapper::Gralloc2Mapper() {
    //拿到的是 GrallocMapper 对象 
    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");
    }

    // IMapper 2.1 is optional
    mMapperV2_1 = IMapper::castFrom(mMapper);
}

四、参考资料

Hidl直通式Passthrough分析案例-Mapper模块


相关推荐
robotx21 小时前
安卓16 设置壁纸中应用网格,有两个5X5的选项
android
Yyuanyuxin1 天前
保姆级学习开发安卓手机软件(三)--安装模拟机并开始简单的进入开发
android·学习
Android小码家1 天前
llama.cpp+Android应用定制
android·llama
龚礼鹏1 天前
Android应用程序 c/c++ 崩溃排查流程二——AddressSanitizer工具使用
android·c语言·c++
Android-Flutter1 天前
android compose DropdownMenu 菜单项列表 使用
android
青莲8431 天前
Java内存模型(JMM)与JVM内存区域完整详解
android·前端·面试
林栩link1 天前
【车载Android】「场景引擎」设计思路分享
android
锅拌饭1 天前
IM 推拉的道与术(四)
android
火柴就是我1 天前
学习一些常用的混合模式之BlendMode. SRC_OVER
android·flutter