一、 问题现象:
vts_treble_vintf_vendor_test—DeviceManifest/SingleManifestTest#InterfacesAreReleased/0 Fail
具体报错信息:
Getting: android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint/default test/vts-testcase/hal/treble/vintf/SingleManifestTest.cpp:478: Failure Expected: (released_hashes.find(hash)) != (released_hashes.end()), actual: 8-byte object <60-FA 1D-65 73-00 00-00> vs 8-byte object <60-FA 1D-65 73-00 00-00> Hash not found. This interface was not released. Interface name: android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint Hash: a7f29858aa7d401b00765dab3ebca0d1c741747fb43445625fbcae19814991ad
Getting: vendor.goodix.hardware.biometrics.fingerprint@2.1::IGoodixFingerprintDaemon/default Timed out on: vendor.goodix.hardware.biometrics.fingerprint@2.1::IGoodixFingerprintDaemon default test/vts-testcase/hal/treble/vintf/SingleManifestTest.cpp:59: Failure Failed vendor.goodix.hardware.biometrics.fingerprint@2.1::IGoodixFingerprintDaemon/default not available. Getting: vendor.goodix.hardware.biometrics.fingerprint@2.1::IGoodixFingerprintDaemon/default Timed out on: vendor.goodix.hardware.biometrics.fingerprint@2.1::IGoodixFingerprintDaemontest/vts-testcase/hal/treble/vintf/SingleManifestTest.cpp:59: Failure Failed vendor.goodix.hardware.biometrics.fingerprint@2.1::IGoodixFingerprintDaemon/default not available. default
二、 原因分析
起初调试指纹时,为了实现framework-指纹HAL down功能在原生框架中添加接口厂商提供的patch,该patch是在原生的框架上修改的,google不允许这样操作,给出的解释如下:
ABI 稳定性
应用二进制接口 (ABI) 包括二进制文件关联/调用规范等信息。如果 ABI/API 发生更改,相应接口就不再适用于使用官方接口编译的常规 system.img。
确保接口带有版本编号且 ABI 稳定至关重要,具体有如下几个原因:
可确保您的实现能够通过供应商测试套件 (VTS) 测试,通过该测试后您将能够正常进行仅限框架的 OTA。
作为原始设备制造商 (OEM),您将能够提供简单易用且符合规定的板级支持包 (BSP)。
有助于您跟踪哪些接口可以发布。您可以将 current.txt 视为接口目录的“地图”,从中了解软件包根目录中提供的所有接口的历史记录和状态。
对于在 current.txt 中已有条目的接口,为其添加新的哈希时,应确保添加的哈希能够反映出接口具有良好的 ABI 稳定性。请查看以下更改类型:
允许的更改:
更改备注(除非这会更改方法的含义)。
更改参数的名称。
更改返回参数的名称。
更改注释。
不允许的更改:
重新排列参数、方法等…
重命名接口或将其移至新的软件包。
重命名软件包。
在接口的任意位置添加方法/结构体字段等等…
会破坏 C++ vtable 的任何更改。
等等
说明的很明确,我们新增了接口,并且更新了HASH值,虽然实现了功能,但是VTS过不了。参考网上搜集的资料和其他模块HIDL实现,我们是可以客制自己的HIDL接口,并且可以继承原生接口。
三、首先要对down功能流程熟悉,流程图大致如下:
① 指纹服务是在开机的时候注册好的
vendor.fp.hardware.fingerprint@2.1-service.rc(自建)
service vendor.fingerprint_hal /vendor/bin/hw/vendor.fp.hardware.fingerprint@2.1-service
# "class hal" causes a race condition on some devices due to files created
# in /data. As a workaround, postpone startup until later in boot once
# /data is mounted.
class core
user system
group system input uhid
writepid /dev/cpuset/system-background/tasks
service.cpp
int main() {
android::sp<IExtBiometricsFingerprint> bio = ExtBiometricsFingerprint::getInstance();
configureRpcThreadpool(1, true /*callerWillJoin*/);
if (bio != nullptr) {
if (::android::OK != bio->registerAsService()) {
return 1;
}
} else {
ALOGE("Can't create instance of ExtBiometricsFingerprint, nullptr");
}
joinRpcThreadpool();
return 0; // should never get here
}
② 手指按下上层到底层的流程如下
手指按下时,首先TP会上报对应的event,调试时可通过命令确认上报状态: getevent -l
上层下发down的流程,先获取指纹服务
Fingerprint21.java
try {
mDaemon = BiometricsFingerprint.getService();
} catch (java.util.NoSuchElementException e) {
// Service doesn't exist or cannot be opened.
Slog.w(TAG, "NoSuchElementException", e);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get fingerprint HAL", e);
}
public void onPointerDown(int x, int y, float minor, float major)
{ mIsPointerDown = true;
UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
}
public void onPointerUp() {
mIsPointerDown = false; UdfpsHelper.onFingerUp(getFreshDaemon());
}
此时调用了HIDL里我们新增的goodixcmd接口
private Runnable mDownRunnable = new Runnable() {
@Override
public void run() {
Slog.d(TAG, "mDownRunnable-s");
try {
getFreshDaemon().goodixExtCmd(1,0);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception when requesting cancel", e);
}
Slog.d(TAG, "mDownRunnable-e");
}
};
接下来是HIDL中goodixcmd的新增和实现
IBiometricsFingerprint.hal
/**
* Send an additional command to the HAL.
*
* @param cmd the command (set) id.
* @param param the command (set) param.
* @return debugErrno is a value the framework logs in case it is not 0.
*/
@callflow(next={"authenticate", "preEnroll", "enumerate", "remove", "cancel", "enroll", "postEnroll"})
goodixExtCmd(uint32_t cmd, uint32_t param) generates (RequestStatus debugErrno);
BiometricsFingerprint.h
Return<RequestStatus> goodixExtCmd(uint32_t cmd, uint32_t param) override;
BiometricsFingerprint.cpp
typedef int32_t(* FUNC_sendCustomizedCommand)(struct fingerprint_device __unused *,uint32_t ,uint32_t );
Return<RequestStatus> BiometricsFingerprint::goodixExtCmd(uint32_t cmd, uint32_t param) {
int32_t ret;
void *handle;
(int32_t *))mDevice->reserved[0]);
handle = dlopen("/vendor/lib64/hw/fingerprint.default.so", RTLD_LAZY);
if (!handle)
{
ALOGD("dlopen fingerprint.default.so fail");
return ErrorFilter(1);
}
fingerprint_device __unused *,uint32_t ,uint32_t))dlsym(handle, "goodixExtCmd");
FUNC_sendCustomizedCommand prize_sendCustomizedCommand = (FUNC_sendCustomizedCommand)dlsym(handle, "sendCustomizedCommand");
(*)(struct fingerprint_device __unused *,uint32_t ,uint32_t))dlsym(handle, "sendCustomizedCommand");
ALOGD("dlsym sendCustomizedCommand: %p", dlsym(handle, "sendCustomizedCommand"));
if (prize_sendCustomizedCommand == NULL) {
ALOGD("Cannot open prize_sendCustomizedCommand");
dlclose(handle);
return ErrorFilter(1);
}
ret = prize_sendCustomizedCommand(mDevice, cmd, param);
return ErrorFilter(ret);
}
在BiometricsFingerprint::goodixExtCmd中调用了fingerprint.default.so中的sendCustomizedCommand函数
int32_t sendCustomizedCommand(struct fingerprint_device __unused *pDev,uint32_t command,uint32_t extras){
ALOGV("fingerprint sendCustomizedCommand,command<%d>,extras<%d>",command,extras);
// assert(gpHalContext != nullptr);
ALOGV("no assert here");
gf_error_t err = GF_SUCCESS;
switch(command){
case CMD_FINGERPRINT_EVENT_DOWN:
{
ALOGE("[%s]Finger Down",__func__);
err = gpHalContext->mCenter->postEvent(EVENT_FINGER_DOWN);
if(err != GF_SUCCESS){
ALOGE("[%s]event_Finger_Down fail",__func__);
}
break;
}
case CMD_FINGERPRINT_EVENT_UP:
{
ALOGE("[%s]Finger Up",__func__);
err = gpHalContext->mCenter->postEvent(EVENT_FINGER_UP);
if(err != GF_SUCCESS){
ALOGE("[%s]event_Finger_Up fail",__func__);
}
break;
}
}
return err;
}
此时上层到HAL的流程到此完成,接下来采图、算法等一系列工作在TA中进行
四、新建继承原生HIDL接口
HIDL 代码样式类似于 Android 框架中的 C++ 代码,缩进 4 个空格,并且采用混用大小写的文件名。软件包声明、导入和文档字符串与 Java 中的类似,只有细微差别。
1. 新建目录vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/
其中vendor/mediatek/proprietary/hardware/fingerprint/interfaces/就是我们HIDL的root path
2. 创建文件
vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/IExtBiometricsFingerprint.hal
package vendor.fp.hardware.fingerprint@2.1;
import android.hardware.biometrics.fingerprint@2.1;
interface IExtBiometricsFingerprint extends android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint{
/**
* Send an additional command to the HAL.
*
* @param cmd the command (set) id.
* @param param the command (set) param.
* @return debugErrno is a value the framework logs in case it is not 0.
*/
@callflow(next={"authenticate", "preEnroll", "enumerate", "remove", "cancel", "enroll", "postEnroll"})
goodixExtCmd(uint32_t cmd, uint32_t param) generates (RequestStatus debugErrno);
};
① interface IExtBiometricsFingerprint extends android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint表明新建的IExtBiometricsFingerprint 继承于原生android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint
② 为每个参数/返回值添加 @param 和 @return:
- 必须为每个参数添加 @param。其后应跟参数的名称,然后是文档字符串。
- 必须为每个返回值添加 @return。其后应跟返回值的名称,然后是文档字符串。
③ 将汇顶FAE给的patch对应添加到该.hal文件
3. 指定HIDL包根目录
添加文件vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/Android.bp
hidl_interface {
name: "vendor.fp.hardware.fingerprint@2.1",
owner: "fp",
root: "vendor.fp.hardware",
system_ext_specific: true,
srcs: [
"IExtBiometricsFingerprint.hal",
],
interfaces: [
"android.hardware.biometrics.fingerprint@2.1",
"android.hidl.base@1.0",
],
gen_java: true,
}
如果不指定HIDL包根目录,编译会报错:Cannot find package root specification
4. 生成HIDL哈希
每个软件包根目录(即映射到 hardware/interfaces 的 android.hardware 或映射到 vendor/foo/hardware/interfaces 的 vendor.foo)都必须包含一个列出所有已发布 HIDL 接口文件的 current.txt 文件。
使用hidl-gen添加哈希
hidl-gen -L hash -r vendor.fp:vendor/mediatek/proprietary/hardware/fingerprint/interfaces -r android.hidl:system/libhidl/transport vendor.fp.hardware.fingerprint@2.1 >> vendor/mediatek/proprietary/hardware/fingerprint/interfaces/current.txt
5. 移植文件
将原生路径下的
hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.h
hardware/interfaces/biometrics/fingerprint/2.1/default/BiometricsFingerprint.cpp
拷贝到以下路径并更名做区分:
vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/default/ExtBiometricsFingerprint.h
vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/default/ExtBiometricsFingerprint.cpp
将汇顶FAE给的patch对应添加到.h和.cpp文件
ExtBiometricsFingerprint.h
struct ExtBiometricsFingerprint : public IExtBiometricsFingerprint {
public:
ExtBiometricsFingerprint();
~ExtBiometricsFingerprint();
……
……
……
Return<RequestStatus> goodixExtCmd(uint32_t cmd, uint32_t param) override;
……
……
……
}
ExtBiometricsFingerprint.cpp
typedef int32_t(* FUNC_sendCustomizedCommand)(struct fingerprint_device __unused *,uint32_t ,uint32_t );
Return<RequestStatus> ExtBiometricsFingerprint::goodixExtCmd(uint32_t cmd, uint32_t param) {
int32_t ret;
static void *handle;
handle = dlopen("/vendor/lib64/hw/fingerprint.default.so", RTLD_LAZY);
if (!handle)
{
ALOGD("dlopen fingerprint.default.so fail");
return ErrorFilter(1);
}
FUNC_sendCustomizedCommand prize_sendCustomizedCommand = (FUNC_sendCustomizedCommand)dlsym(handle, "sendCustomizedCommand");
ALOGD("dlsym sendCustomizedCommand: %p", dlsym(handle, "sendCustomizedCommand"));
if (prize_sendCustomizedCommand == NULL) {
ALOGD("Cannot open prize_sendCustomizedCommand");
dlclose(handle);
return ErrorFilter(1);
}
ret = prize_sendCustomizedCommand(mDevice, cmd, param);
return ErrorFilter(ret);
}
注意:将移植后的ExtBiometricsFingerprint.h和ExtBiometricsFingerprint.cpp内容BiometricsFingerprint替换为自己定义的ExtBiometricsFingerprint
6. 注册服务
HIDL 接口服务器(实现接口的对象)可注册为已命名的服务。注册的名称不需要与接口或软件包名称相关。如果没有指定名称,则使用名称“默认”;这应该用于不需要注册同一接口的两个实现的 HAL。例如,在每个接口中定义的服务注册的 C++ 调用是:
int main() {
android::sp<IExtBiometricsFingerprint> bio = ExtBiometricsFingerprint::getInstance();
configureRpcThreadpool(1, true /*callerWillJoin*/);
if (bio != nullptr) {
if (::android::OK != bio->registerAsService()) {
return 1;
}
} else {
ALOGE("Can't create instance of ExtBiometricsFingerprint, nullptr");
}
joinRpcThreadpool();
return 0; // should never get here
}
HIDL 接口的版本包含在接口本身中。版本自动与服务注册关联,并可通过每个 HIDL 接口上的方法调用(android::hardware::IInterface::getInterfaceVersion()) 进行检索。服务器对象不需要注册,并可通过 HIDL 方法参数传递到其他进程,相应的接收进程会向服务器发送 HIDL 方法调用。
7. 添加Android.bp、.xml、.rc文件
vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/default/vendor.fp.hardware.fingerprint@2.1-service.xml
<manifest version="1.0" type="device">
<hal format="hidl">
<name>vendor.fp.hardware.fingerprint</name>
<transport>hwbinder</transport>
<version>2.1</version>
<interface>
<name>IExtBiometricsFingerprint</name>
<instance>default</instance>
</interface>
</hal>
</manifest>
device/mediatek/system/common/device_framework_matrix.xml
<compatibility-matrix version="1.0" type="framework">
<hal format="hidl" optional="true">
<name>vendor.fp.hardware.fingerprint</name>
<transport>hwbinder</transport>
<version>2.1</version>
<interface>
<name>IExtBiometricsFingerprint</name>
<instance>default</instance>
</interface>
</hal>
</compatibility-matrix>
vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/default/vendor.fp.hardware.fingerprint@2.1-service.rc
service vendor.fingerprint_hal /vendor/bin/hw/vendor.fp.hardware.fingerprint@2.1-service
# "class hal" causes a race condition on some devices due to files created
# in /data. As a workaround, postpone startup until later in boot once
# /data is mounted.
class core
user system
group system input uhid
writepid /dev/cpuset/system-background/tasks
vendor/mediatek/proprietary/hardware/fingerprint/interfaces/fingerprint/2.1/default/Android.bp
cc_binary {
name: "vendor.fp.hardware.fingerprint@2.1-service",
defaults: ["hidl_defaults"],
init_rc: ["vendor.fp.hardware.fingerprint@2.1-service.rc"],
vintf_fragments: ["vendor.fp.hardware.fingerprint@2.1-service.xml"],
vendor: true,
relative_install_path: "hw",
srcs: [
"ExtBiometricsFingerprint.cpp",
"service.cpp",
],
shared_libs: [
"libcutils",
"liblog",
"libhidlbase",
"libhardware",
"libutils",
"android.hardware.biometrics.fingerprint@2.1",
"vendor.fp.hardware.fingerprint@2.1",
],
}
由hwservicemanager去解析并将服务启动,如果不更新device manifest,测试程序会找不到服务端,hwservicemanager会报以下错误:
W hwservicemanager: getTransport: Cannot find entry vendor.fp.hardware.fingerprint@2.1::ExtBiometricsFingerprint/default in either framework or device manifest.
8. 将服务编成java报供上层使用
PRODUCT_PACKAGES += vendor.fp.hardware.fingerprint-V2.1-java
五、 添加SElinux权限(这部分只讨论neverallow解决方案)
添加以下权限是触发了neverallow问题:
allow hal_fingerprint_default default_android_hwservice:hwservice_manager { add find };
allow system_server default_android_hwservice:hwservice_manager { find };
allow system_app hal_fingerprint_hwservice:hwservice_manager { find };
system/sepolicy/public/domain.te
neverallow * default_android_hwservice:hwservice_manager *;
解决方案:
在对应行将报错的主体减掉,这样存在未知风险,不过权限相关的CTS模块都可以测试过,所以暂不受影响。
neverallow { domain -hal_fingerprint_server -system_server } default_android_hwservice:hwservice_manager *;
六、 测试
修改了框架和权限,测试指纹的基本功能(校准、录入、解锁)和生物识别和SElinux权限相关CTS和VTS模块:
CtsBiometricsTestCases
CtsSecurityHostTestCases
vts_treble_vintf_vendor_test
VtsHalBiometricsFingerprintTargetTest
VtsHalBiometricsFingerprintV2_1TargetTest
VtsHalBiometricsFingerprintV2_2TargetTest
VtsHalBiometricsFingerprintV2_3TargetTest