Harmony鸿蒙南向外设驱动开发-Pin_auth

功能简介

口令认证是端侧设备不可或缺的一部分,为设备提供一种用户认证能力,可应用于设备解锁、支付、应用登录等身份认证场景。用户注册口令后,口令认证模块就可为设备提供密码解锁的功能,保证设备的安全使用。口令识别的整体架构如图1。

基于HDF(Hardware Driver Foundation)驱动框架开发的Pin_auth驱动,Pin_auth驱动模型屏蔽硬件差异,为上层用户IAM子系统基础框架和口令认证SA提供稳定的口令认证基础能力,包括口令认证执行器列表查询、执行器信息查询、指定模板防暴信息查询、用户认证和执行器间的模板信息对账,以及口令的录入、认证、删除。

图1 口令认证架构图

image

基本概念

用户认证框架与各个基础认证服务(包含口令认证、人脸识别等)组成的身份认证系统,支持用户认证凭据设置、删除、认证等基础功能。

  • 执行器

    执行器是能够提供数据采集、处理、存储及比对能力的模块,各基础认证服务提供执行器能力,被身份认证框架调度完成各项基础能力。

  • 执行器安全等级

    执行器提供能力时所在运行环境达到的安全级别。

  • 执行器角色

    • ​ 全功能执行器:执行器可独立处理一次凭据注册和身份认证请求,即可提供用户认证数据采集、处理、储存及比对能力。

    • ​ 采集器:执行器提供用户认证时的数据采集能力,需要和认证器配合完成用户认证。

    • ​ 认证器:认证器提供用户认证时的数据处理能力,读取存储的凭据模板与当前认证信息完成对比。

  • 执行器类型

    同一种身份认证类型的不同认证方式会产生认证算法差异,设备器件差异也会导致算法差异,执行器根据支持的算法类型差异或对接的器件差异,会定义不同的执行器类型。

  • 用户认证框架公钥 & 执行器公钥

    用户身份认证处理需要保证用户数据安全以及认证结果的准确性,用户认证框架与基础认证服务间的关键交互信息需要做数据完整性保护,各基础认证服务将提供的执行器能力对接到用户认证框架时,需要交换各自的公钥,其中:

    • 执行器通过用户认证框架公钥校验调度指令的准确性。

    • 执行器公钥可被用户认证框架用于校验认证结果的准确性,同时用于执行器交互认证时的校验交互信息的完整性。

  • 口令认证凭据模板

    认证凭据是在用户设置认证凭据时由认证服务产生并存储,每个模板有一个ID,用于索引模板信息文件,在认证时读取模板信息并用于与当次认证过程中产生的认证数据做对比,完成身份认证。

  • 执行器对账

    用户认证框架统一管理用户身份和凭据ID的映射关系,执行器对接到用户认证框架时,会读取用户身份认证框架内保存的该执行器的模板ID列表,执行器需要与自己维护的模板ID列表进行比对,并删除冗余信息。

  • IDL接口

    接口定义语言(Interface Definition Language)通过IDL编译器编译后,能够生成与编程语言相关的文件:客户端桩文件,服务器框架文件。本文主要是通过IDL接口生成的客户端和服务端来实现Pin_auth服务和驱动的通信,详细使用方法可参考IDL简介。

  • IPC通信

    IPC(Inter Process Communication),进程间通信是指两个进程的数据之间产生交互,详细原理可参考IPC通信简介。

  • HDI

    HDI(Hardware Device Interface),硬件设备接口,位于基础系统服务层和设备驱动层之间,是提供给硬件系统服务开发者使用的、统一的硬件设备功能抽象接口,其目的是为系统服务屏蔽底层硬件设备差异,具体可参考HDI规范。

运作机制

Pin_auth驱动的主要工作是为上层用户认证框架和Pin_auth服务提供稳定的口令认证的基础能力,保证口令认证的功能可以正常运行。开发者可基于HDF框架对不同芯片进行各自驱动的开发以及HDI层接口的调用。

图2 Pin_auth服务和pin_auth驱动接口

image

约束与限制

口令认证的实现需要在TEE安全环境中实现,口令凭据等数据的加密信息需要在安全环境中存储。

开发指导

场景介绍

Pin_auth驱动的主要工作是为上层用户认证框架和Pin_auth服务提供稳定的口令认证基础能力,保证设备上口令认证功能可以正常运行。

接口说明

注:以下接口列举的为IDL接口描述生成的对应C++语言函数接口,接口声明见idl文件(/drivers/interface/pin_auth)。 在本文中,口令凭据的录入、认证和删除相关的HDI接口如表1所示,表2中的回调函数分别用于口令执行器返回操作结果给框架和获取用户输入的口令信息。

表1 接口功能介绍

接口名称功能介绍
GetExecutorList(std::vector<sptr<V1_0::IExecutor>>& executorList)获取V1_0执行器列表。
GetExecutorListV1_1(std::vector<sptr<V1_1::IExecutor>>& executorList)获取V1_1版本执行器列表。
GetTemplateInfo(uint64_t templateId, TemplateInfo& info)获取指定templateId的模板信息。
OnRegisterFinish(const std::vector<uint64_t>& templateIdList,
const std::vector<uint8_t>& frameworkPublicKey,
const std::vector<uint8_t>& extraInfo)
执行器注册成功后,获取用户认证框架的公钥信息;获取用户认证框架的template 列表用于对账。
OnSetData(uint64_t scheduleId, uint64_t authSubType,
const std::vector<uint8_t> &data)
回调函数,返回用户录入的口令子类型和录入的口令脱敏数据。
Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,
const sptr<IExecutorCallback>& callbackObj)
录入pin码。
Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj)pin码认证。
Delete(uint64_t templateId)删除pin码模板。
Cancel(uint64_t scheduleId)通过scheduleId取消指定操作。
SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,
const sptr<IExecutorCallback>& callbackObj)
预留接口。
GetProperty(const std::vector<uint64_t>& templateIdList,
const std::vector<GetPropertyType>& propertyTypes, Property& property)
获取执行器属性信息。

表2 回调函数介绍

接口名称功能介绍
IExecutorCallback::OnResult(int32_t code, const std::vector<uint8_t>& extraInfo)返回操作的最终结果。
IExecutorCallback::OnGetData(uint64_t scheduleId, const std::vector<uint8_t>& salt,
uint64_t authSubType)
返回获取pin码数据信息。

开发步骤

以RK3568平台为例,我们提供了Pin_auth驱动DEMO实例,以下是目录结构及各部分功能简介。

// drivers/peripheral/pin_auth
├── BUILD.gn     # 编译脚本
├── bundle.json  # 组件描述文件
├── test         # 测试用例
└── hdi_service  # Pin_auth驱动实现├── BUILD.gn   # 编译脚本├── adaptor    # 相关算法实现├── common     # 公共接口实现├── database   # 数据库实现├── main       # 口令相关功能实现入口└── service    # Pin_auth驱动实现入口├── inc      # 头文件└── src      # 源文件├── executor_impl.cpp               # 认证、录入等功能接口实现├── pin_auth_interface_driver.cpp   # Pin_auth驱动入口└── pin_auth_interface_service.cpp  # 获取执行器列表接口实现

下面结合DEMO实例介绍驱动开发的具体步骤。

  1. 基于HDF驱动框架,按照驱动Driver Entry程序,完成pin_auth驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现,详细代码参见pin_auth_interface_driver.cpp文件。

    // 通过自定义的HdfPinAuthInterfaceHost对象包含IoService对象和真正的HDI Service实现PinAuthInterfaceService对象
    struct HdfPinAuthInterfaceHost {struct IDeviceIoService ioService;OHOS::sptr<OHOS::IRemoteObject> stub;
    };// 服务接口调用响应接口
    static int32_t PinAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,  struct HdfSBuf *reply)
    {IAM_LOGI("start");auto *hdfPinAuthInterfaceHost = CONTAINER_OF(client->device->service,struct HdfPinAuthInterfaceHost, ioService);OHOS::MessageParcel *dataParcel = nullptr;OHOS::MessageParcel *replyParcel = nullptr;OHOS::MessageOption option;if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__);return HDF_ERR_INVALID_PARAM;}if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__);return HDF_ERR_INVALID_PARAM;}return hdfPinAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
    }// 初始化接口
    static int HdfPinAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
    {IAM_LOGI("start");std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi =OHOS::UserIAM::Common::MakeShared<OHOS::UserIAM::PinAuth::PinAuth>();constexpr uint32_t SUCCESS = 0;if (pinHdi == nullptr || pinHdi->Init() != SUCCESS) {IAM_LOGE("Pin hal init failed");return HDF_FAILURE;}return HDF_SUCCESS;
    }// PinAuth驱动对外提供的服务绑定到HDF框架
    static int HdfPinAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
    {IAM_LOGI("start");auto *hdfPinAuthInterfaceHost = new (std::nothrow) HdfPinAuthInterfaceHost;if (hdfPinAuthInterfaceHost == nullptr) {IAM_LOGE("%{public}s: failed to create create HdfPinAuthInterfaceHost object", __func__);return HDF_FAILURE;}hdfPinAuthInterfaceHost->ioService.Dispatch = PinAuthInterfaceDriverDispatch;hdfPinAuthInterfaceHost->ioService.Open = NULL;hdfPinAuthInterfaceHost->ioService.Release = NULL;auto serviceImpl = IPinAuthInterface::Get(true);if (serviceImpl == nullptr) {IAM_LOGE("%{public}s: failed to get of implement service", __func__);return HDF_FAILURE;}hdfPinAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,IPinAuthInterface::GetDescriptor());if (hdfPinAuthInterfaceHost->stub == nullptr) {IAM_LOGE("%{public}s: failed to get stub object", __func__);return HDF_FAILURE;}deviceObject->service = &hdfPinAuthInterfaceHost->ioService;IAM_LOGI("success");return HDF_SUCCESS;
    }// 释放PinAuth驱动中的资源
    static void HdfPinAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
    {IAM_LOGI("start");auto *hdfPinAuthInterfaceHost = CONTAINER_OF(deviceObject->service,struct HdfPinAuthInterfaceHost, ioService);delete hdfPinAuthInterfaceHost;IAM_LOGI("success");
    }static struct HdfDriverEntry g_pinAuthInterfaceDriverEntry = {.moduleVersion = 1,.moduleName = "pinauth_interface_service",.Bind = HdfPinAuthInterfaceDriverBind,.Init = HdfPinAuthInterfaceDriverInit,.Release = HdfPinAuthInterfaceDriverRelease,
    };// 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出
    HDF_INIT(g_pinauthinterfaceDriverEntry);
  2. 完成获取执行器列表接口实现,详细代码参见pin_auth_interface_service.cpp文件。

    // 执行器实现类
    class ExecutorImpl : public V1_1::IExecutor, public NoCopyable {
    public:explicit ExecutorImpl(std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi);virtual ~ExecutorImpl() {}int32_t GetExecutorInfo(ExecutorInfo &info) override;int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo &info) override;int32_t OnRegisterFinish(const std::vector<uint64_t> &templateIdList,const std::vector<uint8_t> &frameworkPublicKey, const std::vector<uint8_t> &extraInfo) override;int32_t OnSetData(uint64_t scheduleId, uint64_t authSubType, const std::vector<uint8_t> &data) override;int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t> &extraInfo,const sptr<IExecutorCallback> &callbackObj) override;int32_t Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t> &extraInfo,const sptr<IExecutorCallback> &callbackObj) override;int32_t Delete(uint64_t templateId) override;int32_t Cancel(uint64_t scheduleId) override;int32_t SendCommand(int32_t commandId, const std::vector<uint8_t> &extraInfo,const sptr<IExecutorCallback> &callbackObj) override;int32_t GetProperty(const std::vector<uint64_t> &templateIdList, const std::vector<GetPropertyType> &propertyTypes,Property &property) override;private:class ScheduleMap {public:uint32_t AddScheduleInfo(const uint64_t scheduleId, const uint32_t commandId,const sptr<IExecutorCallback> callback, const uint64_t templateId, const std::vector<uint8_t> salt);uint32_t GetScheduleInfo(const uint64_t scheduleId, uint32_t &commandId, sptr<IExecutorCallback> &callback,uint64_t &templateId, std::vector<uint8_t> &salt);uint32_t DeleteScheduleId(const uint64_t scheduleId);private:struct ScheduleInfo {uint32_t commandId;sptr<IExecutorCallback> callback;uint64_t templateId;std::vector<uint8_t> salt;};std::mutex mutex_;std::map<uint64_t, struct ScheduleInfo> scheduleInfo_;};private:uint32_t NewSalt(std::vector<uint8_t> &salt);void CallError(const sptr<IExecutorCallback> &callbackObj, const uint32_t errorCode);std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi_;ScheduleMap scheduleMap_;
    };// 获取V1_1执行器列表实现,创建执行器(仅作示例)
    int32_t PinAuthInterfaceService::GetExecutorListV1_1(std::vector<sptr<V1_1::IExecutor>> &executorList)
    {IAM_LOGI("start");std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi =OHOS::UserIAM::Common::MakeShared<OHOS::UserIAM::PinAuth::PinAuth>();if (pinHdi == nullptr) {IAM_LOGE("Generate pinHdi failed");return HDF_FAILURE;}sptr<IExecutor> executor = new (std::nothrow) ExecutorImpl(pinHdi);if (executor == nullptr) {IAM_LOGE("Generate executor failed");return HDF_FAILURE;}executorList.push_back(executor);IAM_LOGI("end");return HDF_SUCCESS;
    }// 获取V1_0执行器列表实现,使用V1_1版本执行器实现V1_0版本执行器的功能
    int32_t PinAuthInterfaceService::GetExecutorList(std::vector<sptr<V1_0::IExecutor>> &executorList)
    {std::vector<sptr<V1_1::IExecutor>> executorListV1_1;int32_t result = GetExecutorListV1_1(executorListV1_1);for (auto &executor : executorListV1_1) {executorList.push_back(executor);}return result;
    }
  3. 完成执行器每个功能接口实现,详细代码参见executor_impl.cpp文件。

    // 实现获取执行器信息接口(仅作示例)
    int32_t ExecutorImpl::GetExecutorInfo(ExecutorInfo &info)
    {IAM_LOGI("start");constexpr unsigned short SENSOR_ID = 1;info.sensorId = SENSOR_ID;info.executorType = EXECUTOR_TYPE;info.executorRole = ExecutorRole::ALL_IN_ONE;info.authType = AuthType::PIN;if (pinHdi_ == nullptr) {IAM_LOGE("pinHdi_ is nullptr");return HDF_FAILURE;}uint32_t eslRet = 0;int32_t result = pinHdi_->GetExecutorInfo(info.publicKey, eslRet);if (result != SUCCESS) {IAM_LOGE("Get ExecutorInfo failed, fail code : %{public}d", result);return result;}info.esl = static_cast<ExecutorSecureLevel>(eslRet);return HDF_SUCCESS;
    }// 实现获取指定templateId的模板信息接口
    int32_t ExecutorImpl::GetTemplateInfo(uint64_t templateId, TemplateInfo &info)
    {IAM_LOGI("start");if (pinHdi_ == nullptr) {IAM_LOGE("pinHdi_ is nullptr");return HDF_FAILURE;}OHOS::UserIAM::PinAuth::PinCredentialInfo infoRet = {};int32_t result = pinHdi_->QueryPinInfo(templateId, infoRet);if (result != SUCCESS) {IAM_LOGE("Get TemplateInfo failed, fail code : %{public}d", result);return result;}/* subType is stored in extraInfo */info.extraInfo.resize(infoRet.subType);if (memcpy_s(&(info.extraInfo[0]), sizeof(infoRet.subType), &(infoRet.subType), sizeof(infoRet.subType)) != EOK) {IAM_LOGE("copy subType to extraInfo fail!");return HDF_FAILURE;}info.executorType = EXECUTOR_TYPE;info.remainAttempts = infoRet.remainTimes;info.lockoutDuration = infoRet.freezingTime;return HDF_SUCCESS;
    }// 实现执行器注册成功后,获取用户认证框架的公钥信息、获取用户认证框架的template 列表接口,将公钥信息保存,template列表用于和本地的template做对账
    int32_t ExecutorImpl::OnRegisterFinish(const std::vector<uint64_t> &templateIdList,const std::vector<uint8_t> &frameworkPublicKey, const std::vector<uint8_t> &extraInfo)
    {IAM_LOGI("start");static_cast<void>(frameworkPublicKey);static_cast<void>(extraInfo);if (pinHdi_ == nullptr) {IAM_LOGE("pinHdi_ is nullptr");return HDF_FAILURE;}int32_t result = pinHdi_->VerifyTemplateData(templateIdList);if (result != SUCCESS) {IAM_LOGE("Verify templateData failed");return result;}return HDF_SUCCESS;
    }// 实现口令录入接口
    int32_t ExecutorImpl::Enroll(uint64_t scheduleId, const std::vector<uint8_t> &extraInfo,const sptr<IExecutorCallback> &callbackObj)
    {IAM_LOGI("start");if (callbackObj == nullptr) {IAM_LOGE("callbackObj is nullptr");return HDF_FAILURE;}static_cast<void>(extraInfo);std::vector<uint8_t> salt;if (NewSalt(salt) != HDF_SUCCESS) {IAM_LOGE("new salt failed");CallError(callbackObj, HDF_FAILURE);return HDF_FAILURE;}int32_t result = scheduleMap_.AddScheduleInfo(scheduleId, ENROLL_PIN, callbackObj, 0, salt);if (result != HDF_SUCCESS) {IAM_LOGE("Add scheduleInfo failed, fail code : %{public}d", result);CallError(callbackObj, HDF_FAILURE);return result;}result = callbackObj->OnGetData(scheduleId, salt, 0);if (result != SUCCESS) {IAM_LOGE("Enroll Pin failed, fail code : %{public}d", result);// If the enroll fails, delete scheduleId of scheduleMapif (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {IAM_LOGI("delete scheduleId failed");}return result;}return HDF_SUCCESS;
    }// 实现回调数据获取的接口
    int32_t ExecutorImpl::OnSetData(uint64_t scheduleId, uint64_t authSubType, const std::vector<uint8_t> &data)
    {IAM_LOGI("start");if (pinHdi_ == nullptr) {IAM_LOGE("pinHdi_ is nullptr");return HDF_FAILURE;}std::vector<uint8_t> resultTlv;int32_t result = SUCCESS;constexpr uint32_t INVALID_ID = 2;uint32_t commandId = INVALID_ID;sptr<IExecutorCallback> callback = nullptr;uint64_t templateId = 0;std::vector<uint8_t> salt(0, 0);if (scheduleMap_.GetScheduleInfo(scheduleId, commandId, callback, templateId, salt) != HDF_SUCCESS) {IAM_LOGE("Get ScheduleInfo failed, fail code : %{public}d", result);return HDF_FAILURE;}switch (commandId) {case ENROLL_PIN:result = pinHdi_->EnrollPin(scheduleId, authSubType, salt, data, resultTlv);if (result != SUCCESS) {IAM_LOGE("Enroll Pin failed, fail code : %{public}d", result);}break;case AUTH_PIN:result = pinHdi_->AuthPin(scheduleId, templateId, data, resultTlv);if (result != SUCCESS) {IAM_LOGE("Auth Pin failed, fail code : %{public}d", result);}break;default:IAM_LOGE("Error commandId");}if (callback->OnResult(result, resultTlv) != SUCCESS) {IAM_LOGE("callbackObj Pin failed");}// Delete scheduleId from the scheduleMap_ when the enroll and authentication are successfulif (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {IAM_LOGI("delete scheduleId failed");}return HDF_SUCCESS;
    }
    // 实现口令认证接口
    int32_t ExecutorImpl::Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t> &extraInfo,const sptr<IExecutorCallback> &callbackObj)
    {IAM_LOGI("start");if (callbackObj == nullptr) {IAM_LOGE("callbackObj is nullptr");return HDF_FAILURE;}if (pinHdi_ == nullptr) {IAM_LOGE("pinHdi_ is nullptr");CallError(callbackObj, HDF_FAILURE);return HDF_FAILURE;}static_cast<void>(extraInfo);std::vector<uint8_t> salt;int32_t result = pinHdi_->GetSalt(templateId, salt);if (result  != SUCCESS) {IAM_LOGE("get salt failed, fail code : %{public}d", result);CallError(callbackObj, HDF_FAILURE);return result;}result = scheduleMap_.AddScheduleInfo(scheduleId, AUTH_PIN, callbackObj, templateId, salt);if (result != HDF_SUCCESS) {IAM_LOGE("Add scheduleInfo failed, fail code : %{public}d", result);CallError(callbackObj, HDF_FAILURE);return result;}result = callbackObj->OnGetData(scheduleId, salt, 0);if (result != SUCCESS) {IAM_LOGE("Authenticate Pin failed, fail code : %{public}d", result);// If the authentication fails, delete scheduleId of scheduleMapif (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {IAM_LOGI("delete scheduleId failed");}return result;}return HDF_SUCCESS;
    }// 实现删除口令模板接口
    int32_t ExecutorImpl::Delete(uint64_t templateId)
    {IAM_LOGI("start");if (pinHdi_ == nullptr) {IAM_LOGE("pinHdi_ is nullptr");return HDF_FAILURE;}int32_t result = pinHdi_->DeleteTemplate(templateId);if (result != SUCCESS) {IAM_LOGE("Verify templateData failed, fail code : %{public}d", result);return result;}return HDF_SUCCESS;
    }// 实现通过scheduleId取消指定操作接口
    int32_t ExecutorImpl::Cancel(uint64_t scheduleId)
    {IAM_LOGI("start");if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {IAM_LOGE("scheduleId is not found");return HDF_FAILURE;}return HDF_SUCCESS;
    }// 口令预留接口
    int32_t ExecutorImpl::SendCommand(int32_t commandId, const std::vector<uint8_t> &extraInfo,const sptr<IExecutorCallback> &callbackObj)
    {IAM_LOGI("Extension interface, temporarily useless");static_cast<void>(commandId);static_cast<void>(extraInfo);static_cast<void>(callbackObj);return HDF_SUCCESS;
    }// 获取执行器属性信息接口
    int32_t ExecutorImpl::GetProperty(const std::vector<uint64_t> &templateIdList, const std::vector<GetPropertyType> &propertyTypes, Property &property)
    {IAM_LOGI("start");if (pinHdi_ == nullptr) {IAM_LOGE("pinHdi_ is nullptr");return HDF_FAILURE;}if (templateIdList.size() != 1) {IAM_LOGE("templateIdList size is not 1");return HDF_FAILURE;}uint64_t templateId = templateIdList[0];OHOS::UserIam::PinAuth::PinCredentialInfo infoRet = {};int32_t result = pinHdi_->QueryPinInfo(templateId, infoRet);if (result != SUCCESS) {IAM_LOGE("Get TemplateInfo failed, fail code : %{public}d", result);return HDF_FAILURE;}property.authSubType = infoRet.subType;property.remainAttempts = infoRet.remainTimes;property.lockoutDuration = infoRet.freezingTime;return HDF_SUCCESS;
    }

调测验证

驱动开发完成后,可基于RK3568平台验证, 通过设备的设置和锁屏功能验证口令认证功能是否正常,测试步骤如下:

  1. 点击设备的 “ 设置 > 生物识别和密码 > 锁屏密码" 后,录入锁屏密码。
  2. 按设备电源键进行锁屏,再次按设备的电源键进行解锁,输入锁屏密码进行解锁验证,至此就完成了口令的录入和认证功能。
  3. 进入设置中的生物识别和密码,点击关闭锁屏密码或者更改锁屏密码,来验证口令的删除和更新功能是否正常。
  4. 在步骤1完成后,进行步骤2的输入锁屏密码时,输入错误密码达到一定的次数来验证,防暴力破解能力是否正常(例如:连续输入5次错误密码,设备将被冻结60s)。

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/615697.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python使用】python高级进阶知识md总结第8篇:TCP 网络应用程序开发流程,1. TCP 网络应用程序开发流程的介绍【附代码文档】

python高级进阶全知识知识笔记总结完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;操作系统&#xff0c;虚拟机软件。ls命令选项&#xff0c;mkdir和rm命令选项。压缩和解压缩命令&#xff0c;文件权限命令。编辑器 vim&#xff0c;软件安装。获取进程编号…

Solana 上创建自己的 SLPToken:简明指南

Solana 定义 Solana 是由 Solana Labs 创建的区块链平台&#xff0c;旨在提供高吞吐量和低延迟的去中心化应用&#xff08;DApps&#xff09;开发环境。它采用一系列创新技术&#xff0c;如 PoH&#xff08;Proof of History&#xff09;共识机制和 Tower BFT&#xff08;BFT …

APIGateway的认证

APIGateway的支持的认证如下&#xff1a; 我们从表格中可以看到&#xff0c;HTTP API 不支持资源策略的功能&#xff0c;另外是通过JWT的方式集成Cognito的。 对于REST API则是没有显示说明支持JWT认证&#xff0c;这个我们可以通过Lambda 自定义的方式来实现。 所以按照这个…

深入理解 Python 中的浅拷贝与深拷贝

文章目录 1. 基本概念1.1 前置知识1.2 浅拷贝&#xff08;Shallow Copy&#xff09;1.3 深拷贝&#xff08;Deep Copy&#xff09; 2. 如何实现浅拷贝和深拷贝3. 深入分析 在 Python 中&#xff0c;数据复制是常见需求。复制机制分为“浅拷贝&#xff08;shallow copy&#xff…

Python项目1 外星人入侵_记分

在本章中&#xff0c;我们将结束游戏《外星人入侵》的开发。我们将添加一个Play按钮&#xff0c;用于根据需要启动游戏以及在游戏结束后重启游戏。我们还将修改这个游戏&#xff0c;使其在玩 家的等级提高时加快节奏&#xff0c;并实现一个记分系统。阅读本章后&#xff0c;你将…

安装 k8s集群的问题:默认容器运行时从 Docker 改为 Containerd

安装 k8s集群的问题&#xff1a;默认容器运行时从 Docker 改为 Containerd 1、背景2、容器运行时从 Docker 改为 Containerd2.1、安装 Containerd&#xff1a;2.2、生成 Containerd 的配置文件2.3 、创建 /etc/crictl.yaml 文件2.4 、配置 Containerd 服务开机自启 &#x1f49…

虹科Pico汽车示波器 | 免拆诊断案例 | 2011款东风悦达起亚K5车发动机偶尔起动困难

一、故障现象 一辆2011款东风悦达起亚K5车&#xff0c;搭载G4KD发动机&#xff0c;累计行驶里程约为24.5万km。车主反映&#xff0c;第1次起动发动机时偶尔无法起动着机&#xff0c;第2次能够正常起动着机&#xff0c;但发动机故障灯异常点亮。为此在其他维修厂维修过&#xf…

在线客服业务架构:构建智能互动与个性化服务

随着数字化时代的到来&#xff0c;在线客服业务正成为企业与客户沟通互动的重要渠道。在这个快节奏的时代&#xff0c;如何构建一个高效、智能的在线客服业务架构成为了企业关注的焦点。本文将探讨在线客服业务架构的重要性&#xff0c;并介绍如何构建智能互动与个性化服务的在…

高清视频素材,免费下载,收藏好这6个网站。

国内大部分视频素材网站都需要付费购买&#xff0c;这让很多从事视频剪辑的朋友不知道去哪里找免费的视频素材&#xff0c;本期就给大家分享我收藏多年的6个视频素材网站&#xff0c;都可以免费下载&#xff0c;还可以商用&#xff0c;而且国内外的都有哦&#xff0c;有需要的朋…

(1)半导体设备之sorter机【下】:HOW TO 业务的开发

sorter 的全面科普文章见 文章 &#xff08;1&#xff09;半导体设备之sorter机&#xff08;上&#xff09;_晶圆倒片机-CSDN博客 00、背景&#xff1a;晶圆Sorter如何与生产线其他设备协同工作 晶圆Sorter的自动化传输系统是半导体制造过程中的关键组成部分&#xff0c;它与…

Elasticsearch8.x 设置密码

文章目录 一、环境说明二、使用elasticsearch-reset-password工具修改1、elasticsearch-reset-password工具位置2、设置密码 一、环境说明 elasticsearch版本&#xff1a;8.13.0 系统版本&#xff1a;Ubuntu 18.04.6 二、使用elasticsearch-reset-password工具修改 1、elast…

根据状态转移图实现时序电路

描述 某同步时序电路的状态转换图如下&#xff0c;→上表示“C/Y”&#xff0c;圆圈内为现态&#xff0c;→指向次态。 请使用D触发器和必要的逻辑门实现此同步时序电路&#xff0c;用Verilog语言描述。 如图所示&#xff1a; 电路的接口如下图所示&#xff0c;C是单bit数据…