整体框架
对于 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。