【HIDL】指纹创建并继承原生HIDL接口复盘

一、 问题现象:

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

}

FingerprintDetectClient.java

 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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值