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模块


相关推荐
阿巴斯甜14 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker15 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952716 小时前
Andorid Google 登录接入文档
android
黄林晴17 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android