Android HIDL 之 hal 进程启动及服务注册过程

1. 引言

前面章节 HAL 接口定义语言详解 中介绍了 HIDL 接口的设计架构,下面一节经过详解 Android 9.0 图形显示合成 Composer HAL 的启动与服务注册过程。android

咱们知道,在 HIDL 的设计理念中,HAL 服务端进程与 frameworks 客户端调用是分离开的,每一个 HAL 进程独立运行在本身的地址空间中,客户端经过 binder IPC 与 HAL 进程请求交互,完成接口调用。c++

咱们首先来看看 Composer HAL 进程是如何启动。web

2. HAL 进程启动过程分析

2.1 rc 启动脚本

console:/ $ ps -A | grep composer
system         239     1   29084   8928 0                   0 S android.hardware.graphics.composer@2.1-service

平台 HAL 进程以 “android.hardware” 打头,咱们很容易在系统进程表中找到 Composer HAL 服务进程。

在 Composer 模块 HAL 接口软件包目录,能找到这个进程 Android 编译 bp 文件以及源文件 service.cpp:

file path: hardware/interfaces/graphics/composer/2.1/default/Android.bp

cc_binary {
    name: "android.hardware.graphics.composer@2.1-service",
    defaults: ["hidl_defaults"],
    vendor: true,
    relative_install_path: "hw",
    srcs: ["service.cpp"],
    init_rc: ["android.hardware.graphics.composer@2.1-service.rc"],
    shared_libs: [
        "android.hardware.graphics.composer@2.1",
        "libbinder",
        "libhidlbase",
        "libhidltransport",
        "liblog",
        "libsync",
        "libutils",
    ],  
}

从编译 bp 文件中能够看出,编译的二进制 HAL bin 文件安装目录为 /vendor/lib/hw,使用下面 rc 脚本启动进程。

file path: hardware/interfaces/graphics/composer/2.1/default/
android.hardware.graphics.composer@2.1-service.rc

service vendor.hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
    class hal animation                                                            
    user system
    group graphics drmrpc
    capabilities SYS_NICE
    writepid /dev/cpuset/system-background/tasks

# Restart HWC when SurfaceFlinger stops. This turns off the display and prpares
# a new HWC instance for when SurfaceFlinger gets started again
on property:init.svc.surfaceflinger=stopped
    restart vendor.hwcomposer-2-1

Android 编译时会将该脚本文件拷贝到 /vendor/etc/init 目录,Android 启动 init 进程会读取并解析这个脚本文件,启动一个名为 <vendor.hwcomposer-2-1> 的服务,二进制文件路径在系统 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service。框架

rc 启动脚本最后指明当 SurfaceFlinger 关闭时会重启 Composer HAL 进程。ide

2.2 初始化进程 Binder IPC 通讯

经过 Android.bp 文件,咱们知道该二进制可执行文件对应源文件为 service.cpp。

int main() {
    // the conventional HAL might start binder services
    android::ProcessState::initWithDriver("/dev/vndbinder");
    android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
    android::ProcessState::self()->startThreadPool();

    // same as SF main thread
    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK,
                &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO: %d", errno);
    }

    return defaultPassthroughServiceImplementation<IComposer>(4);
}

从 Android O 开始,Android 框架和 HAL 都开始使用 Binder 相互通讯,这就致使以前的驱动设备节点 /dev/binder 可能因流量过大而致使 IPC 速度下降。函数

在 HIDL 架构中。为了明确地拆分框架(设备无关)和供应商(设备相关)代码之间的 Binder 流量,引入了 “Binder 上下文” 这一律念,每一个 Binder 上下文都有本身的设备节点和上下文(服务)管理器。进程只能经过上下文管理器对所属的设备节点对其进行访问。

Android O 支持供应商服务增长的 Binder 域:

IPC 域说明
/dev/binder框架/应用进程之间的 IPC,使用 AIDL 接口
/dev/hwbinder框架/供应商进程之间的 IPC,使用 HIDL 接口供应商进程之间的 IPC,使用 HIDL 接口
/dev/vndbinder供应商/供应商进程之间的 IPC,使用 AIDL 接口

HIDL 框架为了支持供应商 HAL 进程,提供了 libbinder 用户空间库用于操做 Binder 设备节点(hwbinder & vndbinder)。其中,::android::ProcessState() 方法为 libbinder 选择 Binder 驱动程序。以下面的初始化语句为进程选择 vndbinder Binder 驱动程序,而且指定 Binder 线程个数为 4,同时启动线程池。

android::ProcessState::initWithDriver("/dev/vndbinder");
android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
android::ProcessState::self()->startThreadPool();

 初始化完 Binder IPC 机制,就有了处理客户端请求的能力,才能够开始启动 Composer HAL。

defaultPassthroughServiceImplementation<IComposer>(4);

2.3 Passthrough 方式启动 HAL

Google HIDL 设计的目的是让 HAL 服务与用户调用在不一样的进程空间,HAL 被写成 Binder Service,而用户调用如 frameworks 做为 Binder Clinet 经过 IPC 机制实现跨进程接口调用。可是不少厂商还停留在 Android 老版本 HAL,为了给厂商改变时间,同时保持 Android 向前兼容性,Google 另外设计了 Passthrough 类型的 HAL 框架。

Passthrough Hal 模式是为了兼容旧版的 HAL,旧版 HAL 实现仍以动态库的方式提供,只是 binder service 连接了动态库 HAL 实现,即 binder service 经过 hw_get_module 连接了旧版的 hal 实现,而用户端经过与 binder service IPC 通讯,间接实现了与旧版 HAL 的交互。

Android 9.0 代码 HAL Module 目前都是采用 Passthrough 方式建立 HAL 服务进程。

file path: /system/libhidl/transport/include/hidl/LegacySupport.h

template<class Interface>
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(std::string name,
                                            size_t maxThreads = 1) {
    // 配置 Binder IPC 最大线程个数
    // ProcessState::self()->setThreadPoolConfiguration(maxThreads, callerWillJoin /*callerJoinsPool*/)
    configureRpcThreadpool(maxThreads, true);
    status_t result = registerPassthroughServiceImplementation<Interface>(name);

    if (result != OK) {
        return result;
    }

    // IPCThreadState::self()->joinThreadPool()
    joinRpcThreadpool();
    return UNKNOWN_ERROR;
}

registerPassthroughServiceImplementation 函数是 HAL 服务的注册过程,在 Treble 框架中,HAL Module 服务统一由 hwservicemanager 管理,因此若是 HAL 进程须要对外提供接口,首先须要向 hwservicemanager 注册一个服务。

file path: /system/libhidl/transport/include/hidl/LegacySupport.h

template<class Interface>
__attribute__((warn_unused_result))
status_t registerPassthroughServiceImplementation(
        std::string name = "default") {
    // Interface 传递进来的是 IComposer
    // 1. 获取 IComposer 接口类对象
    sp<Interface> service = Interface::getService(name, true /* getStub */);

    if (service == nullptr) {
        ALOGE("Could not get passthrough implementation for %s/%s.",
            Interface::descriptor, name.c_str());
        return EXIT_FAILURE;
    }

    LOG_FATAL_IF(service->isRemote(), "Implementation of %s/%s is remote!",
            Interface::descriptor, name.c_str());

    // 2. 将 IComposer 服务注册到 hwservicemanager 中
    status_t status = service->registerAsService(name);

    if (status == OK) {
        ALOGI("Registration complete for %s/%s.",
            Interface::descriptor, name.c_str());
    } else {
        ALOGE("Could not register service %s/%s (%d).",
            Interface::descriptor, name.c_str(), status);
    }

    return status;
}

整个注册过程只有两步,首先实例化传入的 IComposer 接口对象,而后经过 registerAsService 将服务注册到 hwservicemanager,下面具体分析一下。

2.4 HAL 进程获取 IComposer 接口对象

在 Composer HAL 进程启动时,首先调用 IComposer 的 getService(“default”, true) 来获取 IComposer 的接口对象。

这个 IComposer 的实现类经过 hidl-gen 工具生成。最终生成路径在:
out/soong/.intermediates/hardware/interfaces/graphics/composer/2.1/android.hardware.graphics.composer@2.1_genc++/gen/android/hardware/graphics/composer/2.1\ComposerAll.cpp。

// static
::android::sp<IComposer> IComposer::getService(const std::string &serviceName, const bool getStub) {
    return ::android::hardware::details::getServiceInternal<BpHwComposer>(serviceName, true, getStub);
}

details::getServiceInternal 是 libhidl 提供的方法。getServiceInternal 最终调用到 getRawServiceInternal。

file path: 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::base::V1_0::IBase;
    using ::android::hidl::manager::V1_0::IServiceManager;
    sp<Waiter> waiter;

    const sp<IServiceManager1_1> sm = defaultServiceManager1_1();
    if (sm == nullptr) {
        ALOGE("getService: defaultServiceManager() is null");
        return nullptr;
    }

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

    if (!transportRet.isOk()) {
        ALOGE("getService: defaultServiceManager()->getTransport returns %s",
              transportRet.description().c_str());
        return nullptr;
    }
    Transport transport = transportRet;
    const bool vintfHwbinder = (transport == Transport::HWBINDER);
    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();
        }
    }

    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;
}

}; // namespace details

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值