HIDL 学习

官方介绍

https://source.android.com/devices/architecture/hidl/

Google Android从O开始添加了HIDL,用来解决厂商不能快速跟进新版本升级的问题,官方说法:

1
The goal of HIDL is that the framework can be replaced without having to rebuild HALs

整体理解了一下,实现方式类似AIDL,AIDL是解决APP和Framework之间的通信,HIDL是解决Framework和HAL之间的通信,前者向上,后者向下。因此Google把从kernel、HAL到FW重新添加了另一套binder业务,很多代码看起来都是似曾相识,比如Bp,B,Proxy之类的。

关键概念

HIDL为了适配原来版本的HAL,所以分为了两种类型。

绑定式HAL(Binderized)

用HIDL语言定义接口,取代了传统HAL实现,在此模式下,Android 框架和HAL之间通过binder通信,在后续的版本中的硬件只支持此模式。

直通式HAL(Passthrough)

用HIDL封装了传统HAL,同时支持绑定和直通模式

image

①传统(Legacy)的实现,FW -> Legacy HAL -> Ventor Implementation(此实现方式在Android O开始不支持了)

②③ 绑定式的实现,其中③要想调用Ventor implementation需要通过dlopen打开传统HAL的动态库(so),对上面FW的接口实现是使用HIDL的

④是完全使用HIDL来实现FW和Vendor的通信的

其中直通模式在Java中不支持,因为传统HAL的实现不是使用Java实现的,而HIDL新添加的绑定模式会生成动态库(android.hardware.foo-V1.0-java.jar),这样前端就是通过此jar进行通信。

Java实现

在FW前端Java要使用HAL需要使用绑定式的HAL,也就是上图中的③的形式 ,可以参照指纹识别的hal实现,简单看见次实现的方式。

hardware/interfaces/biometrics中的接口定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
└── fingerprint
└── 2.1
├── Android.bp
├── default
│?? ├── Android.bp
│?? ├── android.hardware.biometrics.fingerprint@2.1-service.rc
│?? ├── BiometricsFingerprint.cpp
│?? ├── BiometricsFingerprint.h
│?? └── service.cpp
├── IBiometricsFingerprintClientCallback.hal
├── IBiometricsFingerprint.hal
├── types.hal
└── vts
└── functional
├── Android.bp
└── VtsHalBiometricsFingerprintV2_1TargetTest.cpp

IBiometricsFingerprint.hal中定义了操作HAL的接口,而IBiometricsFingerprintClientCallback.hal定义了HAL变动后回调到上层的接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

package android.hardware.biometrics.fingerprint@2.1;

import IBiometricsFingerprintClientCallback;

interface IBiometricsFingerprint {
/**
* Set notification callback:
* Registers a user function that must receive notifications from the HAL
* This call must block if the HAL state machine is in busy state until HAL
* leaves the busy state.
*
* @return deviceId is a unique handle for this fingerprint device
*/
@callflow(next={"setActiveGroup"})
@entry
setNotify(IBiometricsFingerprintClientCallback clientCallback)
generates (uint64_t deviceId);

setNotify接口就是把IBiometricsFingerprintClientCallback注册到下面。
IBiometricsFingerprintClientCallback需要客户端来实现。

针对.hal文件的编译可以参见google官方说明

1
https://source.android.com/devices/architecture/hidl-java/

在Android.mk中也可以看出针对.hal的编译过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# This file is autogenerated by hidl-gen. Do not edit manually.

LOCAL_PATH := $(call my-dir)

################################################################################

include $(CLEAR_VARS)
#生成动态库的名称
LOCAL_MODULE := android.hardware.biometrics.fingerprint-V2.1-java
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
#输出目录
intermediates := $(call local-generated-sources-dir, COMMON)

HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)

LOCAL_JAVA_LIBRARIES := \
android.hidl.base-V1.0-java \


#
# Build types.hal (FingerprintAcquired)
#
GEN := $(intermediates)/android/hardware/biometrics/fingerprint/V2_1/FingerprintAcquired.java
#编译指令
$(GEN): $(HIDL)
$(GEN): PRIVATE_HIDL := $(HIDL)
$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
$(GEN): PRIVATE_CUSTOM_TOOL = \
$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-Ljava \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
android.hardware.biometrics.fingerprint@2.1::types.FingerprintAcquired

$(GEN): $(LOCAL_PATH)/types.hal
$(transform-generated-source)
LOCAL_GENERATED_SOURCES += $(GEN)

最终的输出路径在

1
out/target/common/gen/JAVA_LIBRARIES/android.hardware.biometrics.fingerprint-V2.1-java-static_intermediates/android/hardware/biometrics/fingerprint/V2_1

1
2
3
4
5
6
7
8
9
10
11
12
.
├── FingerprintAcquiredInfo.java
├── FingerprintAcquired.java
├── FingerprintAuthenticated.java
├── FingerprintEnroll.java
├── FingerprintError.java
├── FingerprintFingerId.java
├── FingerprintIterator.java
├── FingerprintMsgType.java
├── IBiometricsFingerprintClientCallback.java
├── IBiometricsFingerprint.java
└── RequestStatus.java

最终hidl会把这些自动生成的文件打包成jar,这样在FW上层就可以使用引用
frameworks/base/services/core/Android.mk

1
2
3
4
5
6
7
8
9
10
LOCAL_STATIC_JAVA_LIBRARIES := \
time_zone_distro \
time_zone_distro_installer \
android.hidl.base-V1.0-java-static \
android.hardware.weaver-V1.0-java-static \
android.hardware.biometrics.fingerprint-V2.1-java-static \
android.hardware.oemlock-V1.0-java-static \
android.hardware.tetheroffload.control-V1.0-java-static \
android.hardware.vibrator-V1.0-java-constants \
android.hardware.configstore-V1.0-java-static

可以看到services.core.jar的mk文件引用了jar包

android.hardware.biometrics.fingerprint-V2.1-java-static

1
frameworks/base/services/core/java/com/android/server/fingerprint/FingerprintService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

public synchronized IBiometricsFingerprint getFingerprintDaemon() {
if (mDaemon == null) {
Slog.v(TAG, "mDeamon was null, reconnect to fingerprint");
try {
//获取IBiometricsFingerprint Service
mDaemon = IBiometricsFingerprint.getService();
} catch (java.util.NoSuchElementException e) {
// Service doesn't exist or cannot be opened. Logged below.
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get biometric interface", e);
}
if (mDaemon == null) {
Slog.w(TAG, "fingerprint HIDL not available");
return null;
}

mDaemon.asBinder().linkToDeath(this, 0);

try {
//注册HAL的回调
mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to open fingerprint HAL", e);
mDaemon = null; // try again later!
}

if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
if (mHalDeviceId != 0) {
loadAuthenticatorIds();
updateActiveGroup(ActivityManager.getCurrentUser(), null);
doFingerprintCleanup(ActivityManager.getCurrentUser());
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");
MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
mDaemon = null;
}
}
return mDaemon;
}

其中mDaemon = IBiometricsFingerprint.getService()的getService是HIDL自动生成的(上面有说明,通过hidl在out的输出目录)

1
2
3
4
5
6
7
public static IBiometricsFingerprint getService(String serviceName) throws android.os.RemoteException {
return IBiometricsFingerprint.asInterface(android.os.HwBinder.getService("android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",serviceName));
}

public static IBiometricsFingerprint getService() throws android.os.RemoteException {
return IBiometricsFingerprint.asInterface(android.os.HwBinder.getService("android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint","default"));
}

从代码中我们可以看出getService接口最后调用的android.os.HwBinder中的getService

frameworks/base/core/java/android/os/HwBinder.java

1
2
3
4
public static native final IHwBinder getService(
String iface,
String serviceName)
throws RemoteException, NoSuchElementException;

再找JNI代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
static jobject JHwBinder_native_getService(
JNIEnv *env,
jclass /* clazzObj */,
jstring ifaceNameObj,
jstring serviceNameObj) {

using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;

if (ifaceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}
if (serviceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}

auto manager = hardware::defaultServiceManager();

if (manager == nullptr) {
LOG(ERROR) << "Could not get hwservicemanager.";
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}

const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL);
if (ifaceNameCStr == NULL) {
return NULL; // XXX exception already pending?
}
std::string ifaceName(ifaceNameCStr);
env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr);
::android::hardware::hidl_string ifaceNameHStr;
ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size());

const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL);
if (serviceNameCStr == NULL) {
return NULL; // XXX exception already pending?
}
std::string serviceName(serviceNameCStr);
env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr);
::android::hardware::hidl_string serviceNameHStr;
serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size());

LOG(INFO) << "Looking for service "
<< ifaceName
<< "/"
<< serviceName;

Return<IServiceManager::Transport> transportRet =
manager->getTransport(ifaceNameHStr, serviceNameHStr);

if (!transportRet.isOk()) {
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}

IServiceManager::Transport transport = transportRet;

#ifdef __ANDROID_TREBLE__
#ifdef __ANDROID_DEBUGGABLE__
const char* testingOverride = std::getenv("TREBLE_TESTING_OVERRIDE");
const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY)
&& testingOverride && !strcmp(testingOverride, "true");
#else // __ANDROID_TREBLE__ but not __ANDROID_DEBUGGABLE__
const bool vintfLegacy = false;
#endif // __ANDROID_DEBUGGABLE__
#else // not __ANDROID_TREBLE__
const bool vintfLegacy = (transport == IServiceManager::Transport::EMPTY);
#endif // __ANDROID_TREBLE__";

if (transport != IServiceManager::Transport::HWBINDER && !vintfLegacy) {
LOG(ERROR) << "service " << ifaceName << " declares transport method "
<< toString(transport) << " but framework expects hwbinder.";
signalExceptionForError(env, NAME_NOT_FOUND, true /* canThrowRemoteException */);
return NULL;
}

Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr);

if (!ret.isOk()) {
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
return NULL;
}

sp<hardware::IBinder> service = hardware::toBinder<hidl::base::V1_0::IBase>(ret);

if (service == NULL) {
signalExceptionForError(env, NAME_NOT_FOUND);
return NULL;
}

LOG(INFO) << "Starting thread pool.";
::android::hardware::ProcessState::self()->startThreadPool();

return JHwRemoteBinder::NewObject(env, service);
}

调用类图
image