HIDL Hal 开发指南4 —— Binderized HALs 实例分析

整体框架

对于 Binderized HALs,HAL 层以进程的形式存在,内部有一个 HwBinder 服务端对象,对外提供 HwBinder 远程调用服务。Framework 通过 HwBinder 远程调用到 HAL 中的函数,这些函数直接访问具体的驱动。

在源码下 device/google/coral/vibrator/ 目录下,是 Google 为 pixel4、pixel4 xl 实现的振动器 HAL,其类型就是 Binderized HALs。本文分析其具体实现.

HAL 层服务端实现

HAL 层表现为一个进程:

进程对应的代码位于 device/google/coral/vibrator

整体结构如下:

我们从 Android.bp 下手:

json 复制代码
cc_defaults {
    name: "android.hardware.vibrator@1.3-defaults.coral",
    defaults: ["hidl_defaults"],
    relative_install_path: "hw",
    shared_libs: [
        "libhidlbase",
        "libcutils",
        "libhidltransport",
        "liblog",
        "libhwbinder",
        "libutils",
        "libhardware",
        "android.hardware.vibrator@1.0",
        "android.hardware.vibrator@1.1",
        "android.hardware.vibrator@1.2",
        "android.hardware.vibrator@1.3",
    ],
}

cc_defaults {
    name: "PtsVibratorHalFloralDefaults",
    defaults: ["android.hardware.vibrator@1.3-defaults.coral"],
    static_libs: ["android.hardware.vibrator@1.3-impl.coral"],
    test_suites: [
        "general-tests",
        "pts",
    ],
    multilib: {
        lib32: {
            suffix: "32",
        },
        lib64: {
            suffix: "64",
        },
    },
}

cc_library {
    name: "android.hardware.vibrator@1.3-impl.coral",
    defaults: ["android.hardware.vibrator@1.3-defaults.coral"],
    srcs: [
        "Hardware.cpp",
        "Vibrator.cpp",
    ],
    export_include_dirs: ["."],
    vendor_available: true,
}

cc_binary {
    name: "android.hardware.vibrator@1.3-service.coral",
    defaults: ["android.hardware.vibrator@1.3-defaults.coral"],
    init_rc: ["android.hardware.vibrator@1.3-service.coral.rc"],
    vintf_fragments: ["android.hardware.vibrator@1.3-service.coral.xml"],
    srcs: ["service.cpp"],
    static_libs: ["android.hardware.vibrator@1.3-impl.coral"],
    proprietary: true,
}

一个共享库 android.hardware.vibrator@1.3-impl.coral,一个 native 可执行程序 android.hardware.vibrator@1.3-service.coral

android.hardware.vibrator@1.3-impl.coral 共享库中 :

  • Hardware.cpp 中对振动器驱动的访问包装成了两个对象 HwApi HwCal。
  • Vibrator.cpp 链接了 android.hardware.vibrator@1.3 库,内部有一个 Vibrator类,继承自 android.hardware.vibrator@1.3 库中 IVibrator,IVibrator 是由 hardware/interfaces/vibrator/1.3/IVibrator.hal 编译出来的。Vibrator 类是一个 HwBinder 服务端类,对外提供了调用振动器的接口,内部实现是通过调用 HwApi HwCal 对象的成员函数实现的。

android.hardware.vibrator@1.3-service.coral 可执行程序:

cpp 复制代码
status_t registerVibratorService() {
    sp<Vibrator> vibrator = new Vibrator(std::make_unique<HwApi>(), std::make_unique<HwCal>());

    return vibrator->registerAsService();
}

int main() {
    configureRpcThreadpool(1, true);
    status_t status = registerVibratorService();

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

    joinRpcThreadpool();
}

实现上很简单:

  • 向 HwServiceManager 注册 Vibrator
  • 配置 HwBinder 线程

具体振动器的操作细节就不看了,这不是我们的重点。

Framework 层客户端实现

对于客户端,我们只要知道 Hal 对外提供的接口即可,这个接口又 hardware/interfaces/vibrator/1.3/IVibrator.hal 描述:

java 复制代码
package android.hardware.vibrator@1.3;

import @1.0::EffectStrength;
import @1.0::Status;
import @1.2::IVibrator;

interface IVibrator extends @1.2::IVibrator {
  
  supportsExternalControl() generates (bool supports);

  setExternalControl(bool enabled) generates (Status status);

  perform_1_3(Effect effect, EffectStrength strength)
          generates (Status status, uint32_t lengthMs);
};

frameworks/base/services/core/java/com/android/server/VibratorService.java 本身是一个 Binder 服务端向 App 提供服务,同时也是一个 HwBinder 客户端通过 JNI 访问到 HAL 服务端。

java 复制代码
public class VibratorService extends IVibratorService.Stub
        implements InputManager.InputDeviceListener {
    // ......
    static native boolean vibratorExists();
    static native void vibratorInit();
    static native void vibratorOn(long milliseconds);
    static native void vibratorOff();
    static native boolean vibratorSupportsAmplitudeControl();
    static native void vibratorSetAmplitude(int amplitude);
    static native long vibratorPerformEffect(long effect, long strength);
    static native boolean vibratorSupportsExternalControl();
    static native void vibratorSetExternalControl(boolean enabled);
    // ......     
}

VibratorService 中有多个 native 方法,这些方法用于远程调用 Hal 层。

对应的 JNI 函数实现在 frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

cpp 复制代码
#define LOG_TAG "VibratorService"

#include <android/hardware/vibrator/1.0/IVibrator.h>
#include <android/hardware/vibrator/1.0/types.h>
#include <android/hardware/vibrator/1.0/IVibrator.h>
#include <android/hardware/vibrator/1.1/types.h>
#include <android/hardware/vibrator/1.2/IVibrator.h>
#include <android/hardware/vibrator/1.2/types.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/vibrator.h>

#include <inttypes.h>
#include <stdio.h>

using android::hardware::Return;
using android::hardware::vibrator::V1_0::EffectStrength;
using android::hardware::vibrator::V1_0::Status;
using android::hardware::vibrator::V1_1::Effect_1_1;

namespace V1_0 = android::hardware::vibrator::V1_0;
namespace V1_1 = android::hardware::vibrator::V1_1;
namespace V1_2 = android::hardware::vibrator::V1_2;
namespace V1_3 = android::hardware::vibrator::V1_3;

namespace android {

static constexpr int NUM_TRIES = 2;

// Creates a Return<R> with STATUS::EX_NULL_POINTER.
template<class R>
inline Return<R> NullptrStatus() {
    using ::android::hardware::Status;
    return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)};
}

// Helper used to transparently deal with the vibrator HAL becoming unavailable.
template<class R, class I, class... Args0, class... Args1>
Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
    // Assume that if getService returns a nullptr, HAL is not available on the
    // device.
    static sp<I> sHal = I::getService();
    static bool sAvailable = sHal != nullptr;

    if (!sAvailable) {
        return NullptrStatus<R>();
    }

    // Return<R> doesn't have a default constructor, so make a Return<R> with
    // STATUS::EX_NONE.
    using ::android::hardware::Status;
    Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)};

    // Note that ret is guaranteed to be changed after this loop.
    for (int i = 0; i < NUM_TRIES; ++i) {
        ret = (sHal == nullptr) ? NullptrStatus<R>()
                : (*sHal.*fn)(std::forward<Args1>(args1)...);

        if (ret.isOk()) {
            break;
        }

        ALOGE("Failed to issue command to vibrator HAL. Retrying.");
        // Restoring connection to the HAL.
        sHal = I::tryGetService();
    }
    return ret;
}

template<class R>
bool isValidEffect(jlong effect) {
    if (effect < 0) {
        return false;
    }
    R val = static_cast<R>(effect);
    auto iter = hardware::hidl_enum_range<R>();
    return val >= *iter.begin() && val <= *std::prev(iter.end());
}

static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
{
    halCall(&V1_0::IVibrator::ping).isOk();
}

static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
{
    return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
}

static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{
    Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
    if (retStatus != Status::OK) {
        ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
    }
}

static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{
    Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
    if (retStatus != Status::OK) {
        ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
    }
}

static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jobject) {
    return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
}

static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) {
    Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
        .withDefault(Status::UNKNOWN_ERROR);
    if (status != Status::OK) {
      ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
            static_cast<uint32_t>(status));
    }
}

static jboolean vibratorSupportsExternalControl(JNIEnv*, jobject) {
    return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
}

static void vibratorSetExternalControl(JNIEnv*, jobject, jboolean enabled) {
    Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
        .withDefault(Status::UNKNOWN_ERROR);
    if (status != Status::OK) {
      ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
            static_cast<uint32_t>(status));
    }
}

static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) {
    Status status;
    uint32_t lengthMs;
    auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
        status = retStatus;
        lengthMs = retLengthMs;
    };
    EffectStrength effectStrength(static_cast<EffectStrength>(strength));

    Return<void> ret;
    if (isValidEffect<V1_0::Effect>(effect)) {
        ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
                effectStrength, callback);
    } else if (isValidEffect<Effect_1_1>(effect)) {
        ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
                           effectStrength, callback);
    } else if (isValidEffect<V1_2::Effect>(effect)) {
        ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
                           effectStrength, callback);
    } else if (isValidEffect<V1_3::Effect>(effect)) {
        ret = halCall(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(effect),
                           effectStrength, callback);
    } else {
        ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
                static_cast<int32_t>(effect));
        return -1;
    }

    if (!ret.isOk()) {
        ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
        return -1;
    }

    if (status == Status::OK) {
        return lengthMs;
    } else if (status != Status::UNSUPPORTED_OPERATION) {
        // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
        // doesn't have a pre-defined waveform to perform for it, so we should just give the
        // opportunity to fall back to the framework waveforms.
        ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
                ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
                static_cast<int32_t>(strength), static_cast<uint32_t>(status));
    }

    return -1;
}

static const JNINativeMethod method_table[] = {
    { "vibratorExists", "()Z", (void*)vibratorExists },
    { "vibratorInit", "()V", (void*)vibratorInit },
    { "vibratorOn", "(J)V", (void*)vibratorOn },
    { "vibratorOff", "()V", (void*)vibratorOff },
    { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
    { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
    { "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect},
    { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
    { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
};

int register_android_server_VibratorService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
            method_table, NELEM(method_table));
}

};

所有的函数都通过 hascall 来实现,hascall 中会去从 HwServiceManager 中去获取 Vibrator Hal 的代理对象,然后通过这个代理对象发起远程调用,从而调用到 HAL 层。

最后我们再来看 HAL 端的 vintf 配置文件 /home/zzh0838/Project/android-10.0.0_r41/device/google/coral/vibrator/android.hardware.vibrator@1.3-service.coral.xml

xml 复制代码
<manifest version="1.0" type="device">
    <hal format="hidl">
        <name>android.hardware.vibrator</name>
        <transport>hwbinder</transport>
        <version>1.3</version>
        <interface>
            <name>IVibrator</name>
            <instance>default</instance>
        </interface>
    </hal>
</manifest>

注意这里 transport 指定了 hal 的类型为 hwbinder,也就是我们说的 Binderized hal。

相关推荐
莫名有雪9 小时前
BUUCTF_[网鼎杯 2020 朱雀组]phpweb(反序列化绕过命令)
android
爱写代码的山山12 小时前
虚幻UE5手机安卓Android Studio开发设置2025
android·ue5·虚幻
dal118网工任子仪14 小时前
94,【2】buuctf web [安洵杯 2019]easy_serialize_php
android·前端·php
Kevin Coding17 小时前
Flutter使用Flavor实现切换环境和多渠道打包
android·flutter·ios
yashunan17 小时前
Web_php_unserialize
android·前端·php
taopi202418 小时前
android java系统弹窗的基础模板
android·java·开发语言
志尊宝19 小时前
深入探索 Android 技术:从基础到前沿
android
字节全栈_BjO20 小时前
mysql死锁排查_mysql 死锁问题排查
android·数据库·mysql
恋猫de小郭1 天前
Android Studio 正式版 10 周年回顾,承载 Androider 的峥嵘十年
android·ide·android studio
aaaweiaaaaaa2 天前
php的使用及 phpstorm环境部署
android·web安全·网络安全·php·storm