1e41f4b71Sopenharmony_ci# Facial Authentication 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ci## Overview 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ci### Function 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ciFacial authentication provides user authentication capabilities in identity authentication scenarios, such as device unlocking, payment, and app logins. It uses biometric recognition technologies to identify individuals based on facial characteristics. A camera is used to collect images or video streams that contain human faces, and automatically detect, track, and recognize human faces. Facial authentication is also called facial recognition. The figure below shows the architecture of facial authentication. 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ciThe face authentication (Face_auth) driver is developed based on the Hardware Driver Foundation (HDF). It shields hardware differences and provides stable facial authentication capabilities for the user authentication framework (User_auth) and Face_auth service. The facial authentication capabilities include obtaining facial recognition executor list, executor information, and template information by template ID, comparing face image template information of the executor and that of User_auth, enrolling or deleting face images, and performing facial authentication. 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci**Figure 1** Facial authentication architecture 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ci 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ci### Basic Concepts 16e41f4b71Sopenharmony_ci 17e41f4b71Sopenharmony_ciThe identity authentication consists of User_auth and basic authentication services (including PIN authentication and facial authentication). It supports basic functions such as setting and deleting user credentials and performing authentication. The system supports user identity authentication and data collection, processing, storage, and comparison. 18e41f4b71Sopenharmony_ci- Executor 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci The executor collects, processes, stores, and compares data for authentication. Each authentication service provides the executor capabilities, which are scheduled by User_auth to implement basic capabilities. 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ci- Executor security level 23e41f4b71Sopenharmony_ci 24e41f4b71Sopenharmony_ci Security level of the runtime environment when an executor provides capabilities. 25e41f4b71Sopenharmony_ci 26e41f4b71Sopenharmony_ci- Executor role 27e41f4b71Sopenharmony_ci 28e41f4b71Sopenharmony_ci - Executor: independently completes the entire process of credential registration and identity authentication. The executor can collect, process, store, and compare data to complete the authentication. 29e41f4b71Sopenharmony_ci 30e41f4b71Sopenharmony_ci - Collector: only collects data during user authentication. It needs to work with the authenticator to complete user authentication. 31e41f4b71Sopenharmony_ci 32e41f4b71Sopenharmony_ci - Authenticator: only processes data, obtains the stored credential template, and compares it with the authentication information generated. 33e41f4b71Sopenharmony_ci 34e41f4b71Sopenharmony_ci- Executor type 35e41f4b71Sopenharmony_ci 36e41f4b71Sopenharmony_ci The authentication algorithm varies depending on the authentication mode and device used. Different executor types are defined based on the supported algorithm type or the device in use. 37e41f4b71Sopenharmony_ci 38e41f4b71Sopenharmony_ci- User_auth public key & executor public key 39e41f4b71Sopenharmony_ci 40e41f4b71Sopenharmony_ci To ensure user data security and authentication result accuracy, measures must be taken to protect the integrity of the key information exchanged between User_auth and basic authentication services. Public keys must be exchanged when the executor provided by a basic authentication service interworks with User_auth. 41e41f4b71Sopenharmony_ci 42e41f4b71Sopenharmony_ci The executor uses the User_auth public key to verify scheduling instructions. 43e41f4b71Sopenharmony_ci 44e41f4b71Sopenharmony_ci User_auth uses the executor public key to verify the authentication result accuracy and the integrity of the information exchanged with the executor. 45e41f4b71Sopenharmony_ci 46e41f4b71Sopenharmony_ci- Authentication credential template 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci Authentication credentials are generated and stored by the authentication service when users set authentication credentials. Each template has an ID to index a set of template information files. The template information needs to be compared with the authentication data generated during authentication to complete identity authentication. 49e41f4b71Sopenharmony_ci 50e41f4b71Sopenharmony_ci- Data verification by the executor 51e41f4b71Sopenharmony_ci 52e41f4b71Sopenharmony_ci User_auth manages the mappings between user identities and credential IDs in a unified manner. When connecting to User_auth, the executor obtains the template ID list from User_auth and updates its template ID list based on the template ID list obtained. 53e41f4b71Sopenharmony_ci 54e41f4b71Sopenharmony_ci- HAPs 55e41f4b71Sopenharmony_ci 56e41f4b71Sopenharmony_ci In a broad sense, Harmony Ability Packages (HAPs) are application packages that can be installed on OpenHarmony. In this document, the HAPs only refer to the upper-layer applications of the Face_auth driver. 57e41f4b71Sopenharmony_ci 58e41f4b71Sopenharmony_ci- IDL interface 59e41f4b71Sopenharmony_ci 60e41f4b71Sopenharmony_ci An Interface Definition Language (IDL) is a language that lets a program or object written in one language communicate with another program written in an unknown language. An IDL compiler generates client stub files and server framework files. This document describes how to use the client and server generated by the IDL interface to implement communication between the Face_auth service and driver. For details, see [IDL](https://gitee.com/openharmony/ability_idl_tool/blob/master/README.md). 61e41f4b71Sopenharmony_ci 62e41f4b71Sopenharmony_ci- IPC 63e41f4b71Sopenharmony_ci 64e41f4b71Sopenharmony_ci Inter-process communication (IPC) implements data exchange between two processes. For details, see [IPC](https://gitee.com/openharmony/communication_ipc/blob/master/README.md). 65e41f4b71Sopenharmony_ci 66e41f4b71Sopenharmony_ci- HDI 67e41f4b71Sopenharmony_ci 68e41f4b71Sopenharmony_ci The hardware device interface (HDI) is located between the basic system service layer and the device driver layer. It provides APIs for abstracting hardware device functions, which shields underlying hardware device differences for system services. For details, see [HDI Specifications](../../design/hdi-design-specifications.md). 69e41f4b71Sopenharmony_ci 70e41f4b71Sopenharmony_ci### Working Principles 71e41f4b71Sopenharmony_ci 72e41f4b71Sopenharmony_ciThe Face_auth driver provides basic facial authentication capabilities for the User_auth and Face_auth service to ensure successful facial authentication. 73e41f4b71Sopenharmony_ciYou can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use. 74e41f4b71Sopenharmony_ci 75e41f4b71Sopenharmony_ci**Figure 2** Face_auth service and Face_auth driver interaction 76e41f4b71Sopenharmony_ci 77e41f4b71Sopenharmony_ci 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ci### Constraints 80e41f4b71Sopenharmony_ci 81e41f4b71Sopenharmony_ci- To implement facial authentication, the device must have a camera and the face image must be greater than 100 x 100 pixels. 82e41f4b71Sopenharmony_ci- A Trusted Execution Environment (TEE) must be available, and facial feature information must be encrypted and stored in a TEE. 83e41f4b71Sopenharmony_ci- The face matching accuracy varies with people with similar looks and children whose facial features keep changing. If you are concerned about this, consider using other authentication modes. 84e41f4b71Sopenharmony_ci 85e41f4b71Sopenharmony_ci## Development Guidelines 86e41f4b71Sopenharmony_ci 87e41f4b71Sopenharmony_ci### When to Use 88e41f4b71Sopenharmony_ci 89e41f4b71Sopenharmony_ciThe Face_auth driver provides basic facial authentication capabilities for the User_auth and Face_auth service to ensure successful facial authentication. 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci### Available APIs 92e41f4b71Sopenharmony_ci 93e41f4b71Sopenharmony_ciThe following table describes the C++ APIs generated from the Interface Definition Language (IDL) interface description. For details about the interface declaration, see the .idl file in **/drivers/interface/face_auth/**. 94e41f4b71Sopenharmony_ci 95e41f4b71Sopenharmony_ci**Table 1** describes the HDI APIs for face credential enrollment, authentication, recognition, and deletion. **Table 2** describes the callbacks used to return the executor operation result to the framework or return the authentication tip information to upper-layer applications. 96e41f4b71Sopenharmony_ci 97e41f4b71Sopenharmony_ci**Table 1** Available APIs 98e41f4b71Sopenharmony_ci 99e41f4b71Sopenharmony_ci| API | Description | 100e41f4b71Sopenharmony_ci| ----------------------------------- | ---------------------------------- | 101e41f4b71Sopenharmony_ci| GetExecutorList(std::vector\<sptr\<IAllInOneExecutor>>& allInOneExecutors) | Obtains the executor list of V2_0. | 102e41f4b71Sopenharmony_ci| GetExecutorInfo(ExecutorInfo& info) | Obtains the executor information, including the executor type, executor role, authentication type, security level, and executor public key. | 103e41f4b71Sopenharmony_ci| OnRegisterFinish(const std::vector\<uint64_t>& templateIdList,<br> const std::vector\<uint8_t>& frameworkPublicKey, const std::vector\<uint8_t>& extraInfo) | Obtains the public key and template ID list from User_auth after the executor is registered successfully. | 104e41f4b71Sopenharmony_ci| Enroll(uint64_t scheduleId, const std::vector\<uint8_t>& extraInfo,<br> const sptr\<IExecutorCallback>& callbackObj) | Enrolls a face image template. | 105e41f4b71Sopenharmony_ci| Authenticate(uint64_t scheduleId, const std::vector\<uint64_t>& templateIdList,<br> const std::vector\<uint8_t>& extraInfo, const sptr\<IExecutorCallback>& callbackObj) | Performs facial authentication. | 106e41f4b71Sopenharmony_ci| Identify(uint64_t scheduleId, const std::vector\<uint8_t>& extraInfo,<br> const sptr\<IExecutorCallback>& callbackObj) | Performs facial identification. | 107e41f4b71Sopenharmony_ci| Delete(const std::vector\<uint64_t>& templateIdList) | Deletes a face image template. | 108e41f4b71Sopenharmony_ci| Cancel(uint64_t scheduleId) | Cancels a face enrollment, authentication, or identification operation based on the **scheduleId**. | 109e41f4b71Sopenharmony_ci| SendCommand(int32_t commandId, const std::vector\<uint8_t>& extraInfo,<br> const sptr\<IExecutorCallback>& callbackObj) | Sends commands to the Face_auth service. | 110e41f4b71Sopenharmony_ci| SetBufferProducer(const sptr\<BufferProducerSequenceable> &bufferProducer) | Sets the preview stream buffer. | 111e41f4b71Sopenharmony_ci| GetProperty(const std::vector\<uint64_t>& templateIdList,<br>const std::vector\<int32_t>& propertyTypes, Property& property) | Obtains executor property information. | 112e41f4b71Sopenharmony_ci| SetCachedTemplates(const std::vector\<uint64_t> &templateIdList) | Sets a list of templates to be cached. | 113e41f4b71Sopenharmony_ci| RegisterSaCommandCallback(const sptr\<ISaCommandCallback> &callbackObj) | Registers a callback to be invoked when an SA command is executed. | 114e41f4b71Sopenharmony_ci 115e41f4b71Sopenharmony_ci**Table 2** Callbacks 116e41f4b71Sopenharmony_ci 117e41f4b71Sopenharmony_ci| API | Description | 118e41f4b71Sopenharmony_ci| ------------------------------------------------------------ | ------------------------ | 119e41f4b71Sopenharmony_ci| ExecutorCallbackService::OnResult(int32_t result, const std::vector\<uint8_t>& extraInfo) | Called to return the operation result. | 120e41f4b71Sopenharmony_ci| ExecutorCallbackService::OnTip(int32_t tip, const std::vector\<uint8_t>& extraInfo) | Called to return the interaction information about the operation process. | 121e41f4b71Sopenharmony_ci| SaCommandCallbackService::OnSaCommands(const std::vector\<SaCommand>& commands) | Called to send the command list. | 122e41f4b71Sopenharmony_ci 123e41f4b71Sopenharmony_ci### How to Develop 124e41f4b71Sopenharmony_ci 125e41f4b71Sopenharmony_ciThe following uses the Hi3516D V300 development board as an example to demonstrate how to develop the Face_auth driver. <br/>The directory structure is as follows: 126e41f4b71Sopenharmony_ci 127e41f4b71Sopenharmony_ci```undefined 128e41f4b71Sopenharmony_ci// drivers/peripheral/face_auth 129e41f4b71Sopenharmony_ci├── BUILD.gn # Build script 130e41f4b71Sopenharmony_ci├── bundle.json # Component description file 131e41f4b71Sopenharmony_ci└── hdi_service # Face_auth driver implementation 132e41f4b71Sopenharmony_ci ├── BUILD.gn # Build script 133e41f4b71Sopenharmony_ci ├── include # Header files 134e41f4b71Sopenharmony_ci └── src # Source files 135e41f4b71Sopenharmony_ci ├── executor_impl.cpp # Implementation of authentication and enrollment APIs 136e41f4b71Sopenharmony_ci ├── face_auth_interface_driver.cpp # Face_auth driver entry 137e41f4b71Sopenharmony_ci └── face_auth_interface_service.cpp # Implementation of the APIs for obtaining the executor list 138e41f4b71Sopenharmony_ci``` 139e41f4b71Sopenharmony_ci 140e41f4b71Sopenharmony_ciThe development procedure is as follows: 141e41f4b71Sopenharmony_ci 142e41f4b71Sopenharmony_ci1. Develop the Face_auth driver based on the HDF. The **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions are used. For details about the code, see [face_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/face_auth_interface_driver.cpp). 143e41f4b71Sopenharmony_ci 144e41f4b71Sopenharmony_ci ```c++ 145e41f4b71Sopenharmony_ci // Create an IRemoteObject object by using the custom HdfFaceAuthInterfaceHost object, which consists of the IoService object and HDI service. 146e41f4b71Sopenharmony_ci struct HdfFaceAuthInterfaceHost { 147e41f4b71Sopenharmony_ci struct IDeviceIoService ioService; 148e41f4b71Sopenharmony_ci OHOS::sptr<OHOS::IRemoteObject> stub; 149e41f4b71Sopenharmony_ci }; 150e41f4b71Sopenharmony_ci 151e41f4b71Sopenharmony_ci // Enable the IPC service to call the response API. 152e41f4b71Sopenharmony_ci int32_t FaceAuthInterfaceDriverDispatch( 153e41f4b71Sopenharmony_ci struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) 154e41f4b71Sopenharmony_ci { 155e41f4b71Sopenharmony_ci IAM_LOGI("start"); 156e41f4b71Sopenharmony_ci if (client == nullptr || data == nullptr || reply == nullptr || client->device == nullptr || 157e41f4b71Sopenharmony_ci client->device->service == nullptr) { 158e41f4b71Sopenharmony_ci IAM_LOGE("invalid param"); 159e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 160e41f4b71Sopenharmony_ci } 161e41f4b71Sopenharmony_ci 162e41f4b71Sopenharmony_ci auto *hdfFaceAuthInterfaceHost = CONTAINER_OF(client->device->service, struct HdfFaceAuthInterfaceHost, ioService); 163e41f4b71Sopenharmony_ci if (hdfFaceAuthInterfaceHost == nullptr || hdfFaceAuthInterfaceHost->stub == nullptr) { 164e41f4b71Sopenharmony_ci IAM_LOGE("hdfFaceAuthInterfaceHost is invalid"); 165e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 166e41f4b71Sopenharmony_ci } 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci OHOS::MessageParcel *dataParcel = nullptr; 169e41f4b71Sopenharmony_ci OHOS::MessageParcel *replyParcel = nullptr; 170e41f4b71Sopenharmony_ci OHOS::MessageOption option; 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ci if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { 173e41f4b71Sopenharmony_ci IAM_LOGE("invalid data sbuf object to dispatch"); 174e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 175e41f4b71Sopenharmony_ci } 176e41f4b71Sopenharmony_ci if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { 177e41f4b71Sopenharmony_ci IAM_LOGE("invalid reply sbuf object to dispatch"); 178e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 179e41f4b71Sopenharmony_ci } 180e41f4b71Sopenharmony_ci 181e41f4b71Sopenharmony_ci return hdfFaceAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); 182e41f4b71Sopenharmony_ci } 183e41f4b71Sopenharmony_ci 184e41f4b71Sopenharmony_ci // Initialize the HdfFaceAuthInterfaceDriver object. 185e41f4b71Sopenharmony_ci int HdfFaceAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject) 186e41f4b71Sopenharmony_ci { 187e41f4b71Sopenharmony_ci IAM_LOGI("start"); 188e41f4b71Sopenharmony_ci if (deviceObject == nullptr) { 189e41f4b71Sopenharmony_ci IAM_LOGE("deviceObject is nullptr"); 190e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 191e41f4b71Sopenharmony_ci } 192e41f4b71Sopenharmony_ci if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_USERAUTH)) { 193e41f4b71Sopenharmony_ci IAM_LOGE("set face auth hdf class failed"); 194e41f4b71Sopenharmony_ci return HDF_FAILURE; 195e41f4b71Sopenharmony_ci } 196e41f4b71Sopenharmony_ci return HDF_SUCCESS; 197e41f4b71Sopenharmony_ci } 198e41f4b71Sopenharmony_ci 199e41f4b71Sopenharmony_ci // Bind the service provided by the Face_auth driver to the HDF. 200e41f4b71Sopenharmony_ci int HdfFaceAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject) 201e41f4b71Sopenharmony_ci { 202e41f4b71Sopenharmony_ci IAM_LOGI("start"); 203e41f4b71Sopenharmony_ci if (deviceObject == nullptr) { 204e41f4b71Sopenharmony_ci IAM_LOGE("deviceObject is nullptr"); 205e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 206e41f4b71Sopenharmony_ci } 207e41f4b71Sopenharmony_ci auto *hdfFaceAuthInterfaceHost = new (std::nothrow) HdfFaceAuthInterfaceHost; 208e41f4b71Sopenharmony_ci if (hdfFaceAuthInterfaceHost == nullptr) { 209e41f4b71Sopenharmony_ci IAM_LOGE("failed to create HdfFaceAuthInterfaceHost object"); 210e41f4b71Sopenharmony_ci return HDF_FAILURE; 211e41f4b71Sopenharmony_ci } 212e41f4b71Sopenharmony_ci 213e41f4b71Sopenharmony_ci hdfFaceAuthInterfaceHost->ioService.Dispatch = FaceAuthInterfaceDriverDispatch; 214e41f4b71Sopenharmony_ci hdfFaceAuthInterfaceHost->ioService.Open = NULL; 215e41f4b71Sopenharmony_ci hdfFaceAuthInterfaceHost->ioService.Release = NULL; 216e41f4b71Sopenharmony_ci 217e41f4b71Sopenharmony_ci auto serviceImpl = IFaceAuthInterface::Get(true); 218e41f4b71Sopenharmony_ci if (serviceImpl == nullptr) { 219e41f4b71Sopenharmony_ci IAM_LOGE("failed to get of implement service"); 220e41f4b71Sopenharmony_ci delete hdfFaceAuthInterfaceHost; 221e41f4b71Sopenharmony_ci return HDF_FAILURE; 222e41f4b71Sopenharmony_ci } 223e41f4b71Sopenharmony_ci 224e41f4b71Sopenharmony_ci hdfFaceAuthInterfaceHost->stub = 225e41f4b71Sopenharmony_ci OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, IFaceAuthInterface::GetDescriptor()); 226e41f4b71Sopenharmony_ci if (hdfFaceAuthInterfaceHost->stub == nullptr) { 227e41f4b71Sopenharmony_ci IAM_LOGE("failed to get stub object"); 228e41f4b71Sopenharmony_ci delete hdfFaceAuthInterfaceHost; 229e41f4b71Sopenharmony_ci return HDF_FAILURE; 230e41f4b71Sopenharmony_ci } 231e41f4b71Sopenharmony_ci 232e41f4b71Sopenharmony_ci deviceObject->service = &hdfFaceAuthInterfaceHost->ioService; 233e41f4b71Sopenharmony_ci IAM_LOGI("success"); 234e41f4b71Sopenharmony_ci return HDF_SUCCESS; 235e41f4b71Sopenharmony_ci } 236e41f4b71Sopenharmony_ci 237e41f4b71Sopenharmony_ci // Release resources of the Face_auth driver. 238e41f4b71Sopenharmony_ci void HdfFaceAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject) 239e41f4b71Sopenharmony_ci { 240e41f4b71Sopenharmony_ci IAM_LOGI("start"); 241e41f4b71Sopenharmony_ci if (deviceObject == nullptr || deviceObject->service == nullptr) { 242e41f4b71Sopenharmony_ci IAM_LOGE("deviceObject is invalid"); 243e41f4b71Sopenharmony_ci return; 244e41f4b71Sopenharmony_ci } 245e41f4b71Sopenharmony_ci auto *hdfFaceAuthInterfaceHost = CONTAINER_OF(deviceObject->service, struct HdfFaceAuthInterfaceHost, ioService); 246e41f4b71Sopenharmony_ci if (hdfFaceAuthInterfaceHost == nullptr) { 247e41f4b71Sopenharmony_ci IAM_LOGE("hdfFaceAuthInterfaceHost is nullptr"); 248e41f4b71Sopenharmony_ci return; 249e41f4b71Sopenharmony_ci } 250e41f4b71Sopenharmony_ci delete hdfFaceAuthInterfaceHost; 251e41f4b71Sopenharmony_ci IAM_LOGI("success"); 252e41f4b71Sopenharmony_ci } 253e41f4b71Sopenharmony_ci 254e41f4b71Sopenharmony_ci // Register the entry data structure object of the Face_auth driver. 255e41f4b71Sopenharmony_ci struct HdfDriverEntry g_faceAuthInterfaceDriverEntry = { 256e41f4b71Sopenharmony_ci .moduleVersion = 1, 257e41f4b71Sopenharmony_ci .moduleName = "drivers_peripheral_face_auth", 258e41f4b71Sopenharmony_ci .Bind = HdfFaceAuthInterfaceDriverBind, 259e41f4b71Sopenharmony_ci .Init = HdfFaceAuthInterfaceDriverInit, 260e41f4b71Sopenharmony_ci .Release = HdfFaceAuthInterfaceDriverRelease, 261e41f4b71Sopenharmony_ci }; 262e41f4b71Sopenharmony_ci 263e41f4b71Sopenharmony_ci // Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind() function and then the Init() function. If the Init() function fails to be called, the HDF will call Release() to release driver resources and exit the driver model. 264e41f4b71Sopenharmony_ci HDF_INIT(g_faceAuthInterfaceDriverEntry); 265e41f4b71Sopenharmony_ci ``` 266e41f4b71Sopenharmony_ci 267e41f4b71Sopenharmony_ci2. Implement the APIs for obtaining the executor list. For details about the code, see [face_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/face_auth_interface_service.cpp). 268e41f4b71Sopenharmony_ci 269e41f4b71Sopenharmony_ci ```c++ 270e41f4b71Sopenharmony_ci // Executor implementation class 271e41f4b71Sopenharmony_ci class AllInOneExecutorImpl : public IAllInOneExecutor { 272e41f4b71Sopenharmony_ci public: 273e41f4b71Sopenharmony_ci AllInOneExecutorImpl(struct ExecutorInfo executorInfo); 274e41f4b71Sopenharmony_ci virtual ~AllInOneExecutorImpl() {} 275e41f4b71Sopenharmony_ci 276e41f4b71Sopenharmony_ci private: 277e41f4b71Sopenharmony_ci struct ExecutorInfo executorInfo_; // Executor information 278e41f4b71Sopenharmony_ci }; 279e41f4b71Sopenharmony_ci 280e41f4b71Sopenharmony_ci static constexpr uint16_t SENSOR_ID = 123; // Executor sensor ID 281e41f4b71Sopenharmony_ci static constexpr uint32_t EXECUTOR_TYPE = 123; // Executor type 282e41f4b71Sopenharmony_ci static constexpr size_t PUBLIC_KEY_LEN = 32; //32-byte public key of the executor 283e41f4b71Sopenharmony_ci 284e41f4b71Sopenharmony_ci // Create an HDI service object. 285e41f4b71Sopenharmony_ci extern "C" IFaceAuthInterface *FaceAuthInterfaceImplGetInstance(void) 286e41f4b71Sopenharmony_ci { 287e41f4b71Sopenharmony_ci auto faceAuthInterfaceService = new (std::nothrow) FaceAuthInterfaceService(); 288e41f4b71Sopenharmony_ci if (faceAuthInterfaceService == nullptr) { 289e41f4b71Sopenharmony_ci IAM_LOGE("faceAuthInterfaceService is nullptr"); 290e41f4b71Sopenharmony_ci return nullptr; 291e41f4b71Sopenharmony_ci } 292e41f4b71Sopenharmony_ci return faceAuthInterfaceService; 293e41f4b71Sopenharmony_ci } 294e41f4b71Sopenharmony_ci 295e41f4b71Sopenharmony_ci // Obtain the executor list of V2_0. 296e41f4b71Sopenharmony_ci int32_t GetExecutorList(std::vector<sptr<IAllInOneExecutor>> &executorList) 297e41f4b71Sopenharmony_ci { 298e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 299e41f4b71Sopenharmony_ci for (auto executor : executorList_) { 300e41f4b71Sopenharmony_ci executorList.push_back(executor); 301e41f4b71Sopenharmony_ci } 302e41f4b71Sopenharmony_ci IAM_LOGI("interface mock success"); 303e41f4b71Sopenharmony_ci return HDF_SUCCESS; 304e41f4b71Sopenharmony_ci } 305e41f4b71Sopenharmony_ci ``` 306e41f4b71Sopenharmony_ci 307e41f4b71Sopenharmony_ci3. Implement each function of the executor. For details about the code, see [all_in_one_executor_impl.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/face_auth/hdi_service/src/all_in_one_executor_impl.cpp). 308e41f4b71Sopenharmony_ci 309e41f4b71Sopenharmony_ci ```c++ 310e41f4b71Sopenharmony_ci // Obtain the executor information. 311e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::GetExecutorInfo(ExecutorInfo &executorInfo) 312e41f4b71Sopenharmony_ci { 313e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 314e41f4b71Sopenharmony_ci executorInfo = executorInfo_; 315e41f4b71Sopenharmony_ci IAM_LOGI("get executor information success"); 316e41f4b71Sopenharmony_ci return HDF_SUCCESS; 317e41f4b71Sopenharmony_ci } 318e41f4b71Sopenharmony_ci 319e41f4b71Sopenharmony_ci // After the executor is successfully registered, obtain the public key and template ID list from User_auth and save the public key. The executor compares its template ID list with the template ID list obtained and updates its template ID list. 320e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::OnRegisterFinish(const std::vector<uint64_t> &templateIdList, 321e41f4b71Sopenharmony_ci const std::vector<uint8_t> &frameworkPublicKey, const std::vector<uint8_t> &extraInfo) 322e41f4b71Sopenharmony_ci { 323e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 324e41f4b71Sopenharmony_ci static_cast<void>(templateIdList); 325e41f4b71Sopenharmony_ci static_cast<void>(extraInfo); 326e41f4b71Sopenharmony_ci static_cast<void>(frameworkPublicKey); 327e41f4b71Sopenharmony_ci IAM_LOGI("register finish"); 328e41f4b71Sopenharmony_ci return HDF_SUCCESS; 329e41f4b71Sopenharmony_ci } 330e41f4b71Sopenharmony_ci 331e41f4b71Sopenharmony_ci // Enroll a face image. 332e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::Enroll( 333e41f4b71Sopenharmony_ci uint64_t scheduleId, const std::vector<uint8_t> &extraInfo, const sptr<IExecutorCallback> &callbackObj) 334e41f4b71Sopenharmony_ci { 335e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 336e41f4b71Sopenharmony_ci static_cast<void>(scheduleId); 337e41f4b71Sopenharmony_ci static_cast<void>(extraInfo); 338e41f4b71Sopenharmony_ci if (callbackObj == nullptr) { 339e41f4b71Sopenharmony_ci IAM_LOGE("callbackObj is nullptr"); 340e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 341e41f4b71Sopenharmony_ci } 342e41f4b71Sopenharmony_ci IAM_LOGI("enroll, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT); 343e41f4b71Sopenharmony_ci int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {}); 344e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 345e41f4b71Sopenharmony_ci IAM_LOGE("callback result is %{public}d", ret); 346e41f4b71Sopenharmony_ci return HDF_FAILURE; 347e41f4b71Sopenharmony_ci } 348e41f4b71Sopenharmony_ci return HDF_SUCCESS; 349e41f4b71Sopenharmony_ci } 350e41f4b71Sopenharmony_ci 351e41f4b71Sopenharmony_ci // Start facial authentication. 352e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::Authenticate(uint64_t scheduleId, const std::vector<uint64_t> &templateIdList, 353e41f4b71Sopenharmony_ci const std::vector<uint8_t> &extraInfo, const sptr<IExecutorCallback> &callbackObj) 354e41f4b71Sopenharmony_ci { 355e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 356e41f4b71Sopenharmony_ci static_cast<void>(scheduleId); 357e41f4b71Sopenharmony_ci static_cast<void>(templateIdList); 358e41f4b71Sopenharmony_ci static_cast<void>(extraInfo); 359e41f4b71Sopenharmony_ci if (callbackObj == nullptr) { 360e41f4b71Sopenharmony_ci IAM_LOGE("callbackObj is nullptr"); 361e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 362e41f4b71Sopenharmony_ci } 363e41f4b71Sopenharmony_ci IAM_LOGI("authenticate, result is %{public}d", ResultCode::NOT_ENROLLED); 364e41f4b71Sopenharmony_ci int32_t ret = callbackObj->OnResult(ResultCode::NOT_ENROLLED, {}); 365e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 366e41f4b71Sopenharmony_ci IAM_LOGE("callback result is %{public}d", ret); 367e41f4b71Sopenharmony_ci return HDF_FAILURE; 368e41f4b71Sopenharmony_ci } 369e41f4b71Sopenharmony_ci return HDF_SUCCESS; 370e41f4b71Sopenharmony_ci } 371e41f4b71Sopenharmony_ci 372e41f4b71Sopenharmony_ci // Perform facial recognition. 373e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::Identify( 374e41f4b71Sopenharmony_ci uint64_t scheduleId, const std::vector<uint8_t> &extraInfo, const sptr<IExecutorCallback> &callbackObj) 375e41f4b71Sopenharmony_ci { 376e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 377e41f4b71Sopenharmony_ci static_cast<void>(scheduleId); 378e41f4b71Sopenharmony_ci static_cast<void>(extraInfo); 379e41f4b71Sopenharmony_ci if (callbackObj == nullptr) { 380e41f4b71Sopenharmony_ci IAM_LOGE("callbackObj is nullptr"); 381e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 382e41f4b71Sopenharmony_ci } 383e41f4b71Sopenharmony_ci IAM_LOGI("identify, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT); 384e41f4b71Sopenharmony_ci int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {}); 385e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 386e41f4b71Sopenharmony_ci IAM_LOGE("callback result is %{public}d", ret); 387e41f4b71Sopenharmony_ci return HDF_FAILURE; 388e41f4b71Sopenharmony_ci } 389e41f4b71Sopenharmony_ci return HDF_SUCCESS; 390e41f4b71Sopenharmony_ci } 391e41f4b71Sopenharmony_ci 392e41f4b71Sopenharmony_ci // Delete the face image template. 393e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::Delete(const std::vector<uint64_t> &templateIdList) 394e41f4b71Sopenharmony_ci { 395e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 396e41f4b71Sopenharmony_ci static_cast<void>(templateIdList); 397e41f4b71Sopenharmony_ci IAM_LOGI("delete success"); 398e41f4b71Sopenharmony_ci return HDF_SUCCESS; 399e41f4b71Sopenharmony_ci } 400e41f4b71Sopenharmony_ci 401e41f4b71Sopenharmony_ci // Cancel the operation based on the specified scheduleId. 402e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::Cancel(uint64_t scheduleId) 403e41f4b71Sopenharmony_ci { 404e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 405e41f4b71Sopenharmony_ci static_cast<void>(scheduleId); 406e41f4b71Sopenharmony_ci IAM_LOGI("cancel success"); 407e41f4b71Sopenharmony_ci return HDF_SUCCESS; 408e41f4b71Sopenharmony_ci } 409e41f4b71Sopenharmony_ci 410e41f4b71Sopenharmony_ci // Send template locking or unlocking command from the Face_auth service to the Face_auth driver. 411e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::SendCommand( 412e41f4b71Sopenharmony_ci int32_t commandId, const std::vector<uint8_t> &extraInfo, const sptr<IExecutorCallback> &callbackObj) 413e41f4b71Sopenharmony_ci { 414e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 415e41f4b71Sopenharmony_ci static_cast<void>(extraInfo); 416e41f4b71Sopenharmony_ci if (callbackObj == nullptr) { 417e41f4b71Sopenharmony_ci IAM_LOGE("callbackObj is nullptr"); 418e41f4b71Sopenharmony_ci return HDF_ERR_INVALID_PARAM; 419e41f4b71Sopenharmony_ci } 420e41f4b71Sopenharmony_ci int32_t ret; 421e41f4b71Sopenharmony_ci switch (commandId) { 422e41f4b71Sopenharmony_ci case DriverCommandId::LOCK_TEMPLATE: 423e41f4b71Sopenharmony_ci IAM_LOGI("lock template, result is %{public}d", ResultCode::SUCCESS); 424e41f4b71Sopenharmony_ci ret = callbackObj->OnResult(ResultCode::SUCCESS, {}); 425e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 426e41f4b71Sopenharmony_ci IAM_LOGE("callback result is %{public}d", ret); 427e41f4b71Sopenharmony_ci return HDF_FAILURE; 428e41f4b71Sopenharmony_ci } 429e41f4b71Sopenharmony_ci break; 430e41f4b71Sopenharmony_ci case DriverCommandId::UNLOCK_TEMPLATE: 431e41f4b71Sopenharmony_ci IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS); 432e41f4b71Sopenharmony_ci ret = callbackObj->OnResult(ResultCode::SUCCESS, {}); 433e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 434e41f4b71Sopenharmony_ci IAM_LOGE("callback result is %{public}d", ret); 435e41f4b71Sopenharmony_ci return HDF_FAILURE; 436e41f4b71Sopenharmony_ci } 437e41f4b71Sopenharmony_ci break; 438e41f4b71Sopenharmony_ci case DriverCommandId::INIT_ALGORITHM: 439e41f4b71Sopenharmony_ci IAM_LOGI("init algorithm, result is %{public}d", ResultCode::SUCCESS); 440e41f4b71Sopenharmony_ci ret = callbackObj->OnResult(ResultCode::SUCCESS, {}); 441e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 442e41f4b71Sopenharmony_ci IAM_LOGE("callback result is %{public}d", ret); 443e41f4b71Sopenharmony_ci return HDF_FAILURE; 444e41f4b71Sopenharmony_ci } 445e41f4b71Sopenharmony_ci break; 446e41f4b71Sopenharmony_ci default: 447e41f4b71Sopenharmony_ci IAM_LOGD("not support DriverCommandId : %{public}d", commandId); 448e41f4b71Sopenharmony_ci ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {}); 449e41f4b71Sopenharmony_ci if (ret != HDF_SUCCESS) { 450e41f4b71Sopenharmony_ci IAM_LOGE("callback result is %{public}d", ret); 451e41f4b71Sopenharmony_ci return HDF_FAILURE; 452e41f4b71Sopenharmony_ci } 453e41f4b71Sopenharmony_ci } 454e41f4b71Sopenharmony_ci return HDF_SUCCESS; 455e41f4b71Sopenharmony_ci } 456e41f4b71Sopenharmony_ci 457e41f4b71Sopenharmony_ci // Set the preview stream buffer. 458e41f4b71Sopenharmony_ci int32_t FaceAuthInterfaceService::SetBufferProducer(const sptr<BufferProducerSequenceable> &bufferProducer) 459e41f4b71Sopenharmony_ci { 460e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start set buffer producer %{public}s", 461e41f4b71Sopenharmony_ci UserIam::Common::GetPointerNullStateString(bufferProducer.GetRefPtr()).c_str()); 462e41f4b71Sopenharmony_ci return HDF_SUCCESS; 463e41f4b71Sopenharmony_ci } 464e41f4b71Sopenharmony_ci 465e41f4b71Sopenharmony_ci // Obtaining executor properties. 466e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::GetProperty( 467e41f4b71Sopenharmony_ci const std::vector<uint64_t> &templateIdList, const std::vector<int32_t> &propertyTypes, Property &property) 468e41f4b71Sopenharmony_ci { 469e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 470e41f4b71Sopenharmony_ci property = {}; 471e41f4b71Sopenharmony_ci IAM_LOGI("get property success"); 472e41f4b71Sopenharmony_ci return HDF_SUCCESS; 473e41f4b71Sopenharmony_ci } 474e41f4b71Sopenharmony_ci 475e41f4b71Sopenharmony_ci // Set a list of templates to be cached. 476e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::SetCachedTemplates(const std::vector<uint64_t> &templateIdList) 477e41f4b71Sopenharmony_ci { 478e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 479e41f4b71Sopenharmony_ci IAM_LOGI("set cached templates success"); 480e41f4b71Sopenharmony_ci return HDF_SUCCESS; 481e41f4b71Sopenharmony_ci } 482e41f4b71Sopenharmony_ci 483e41f4b71Sopenharmony_ci // Register the callback to be invoked when the SA command is executed. 484e41f4b71Sopenharmony_ci int32_t AllInOneExecutorImpl::RegisterSaCommandCallback(const sptr<ISaCommandCallback> &callbackObj) 485e41f4b71Sopenharmony_ci { 486e41f4b71Sopenharmony_ci IAM_LOGI("interface mock start"); 487e41f4b71Sopenharmony_ci IAM_LOGI("register sa command callback success"); 488e41f4b71Sopenharmony_ci return HDF_SUCCESS; 489e41f4b71Sopenharmony_ci } 490e41f4b71Sopenharmony_ci ``` 491e41f4b71Sopenharmony_ci 492e41f4b71Sopenharmony_ci4. Modify **serviceName2Config** in the **face_auth_service.cpp** file if you need to add a driver or modify driver information. 493e41f4b71Sopenharmony_ci 494e41f4b71Sopenharmony_ci ```c++ 495e41f4b71Sopenharmony_ci // base/user_iam/face_auth/services/src/face_auth_service.cpp 496e41f4b71Sopenharmony_ci void FaceAuthService::StartDriverManager() 497e41f4b71Sopenharmony_ci { 498e41f4b71Sopenharmony_ci IAM_LOGI("start"); 499e41f4b71Sopenharmony_ci int32_t ret = UserAuth::IDriverManager::Start(HDI_NAME_2_CONFIG); 500e41f4b71Sopenharmony_ci if (ret != FACE_AUTH_SUCCESS) { 501e41f4b71Sopenharmony_ci IAM_LOGE("start driver manager failed"); 502e41f4b71Sopenharmony_ci } 503e41f4b71Sopenharmony_ci } 504e41f4b71Sopenharmony_ci ``` 505e41f4b71Sopenharmony_ci 506e41f4b71Sopenharmony_ci### Verification 507e41f4b71Sopenharmony_ci 508e41f4b71Sopenharmony_ciUse the [User Authentication APIs](../../application-dev/reference/apis-user-authentication-kit/js-apis-useriam-userauth.md) to develop a HAP and verify the application on the RK3568 platform. The sample code for starting and canceling an authentication is as follows: 509e41f4b71Sopenharmony_ci 510e41f4b71Sopenharmony_ci1. Initiate a request for user authentication and obtain the authentication result. 511e41f4b71Sopenharmony_ci 512e41f4b71Sopenharmony_ci```ts 513e41f4b71Sopenharmony_ci // API version 10 514e41f4b71Sopenharmony_ci import type {BusinessError} from '@ohos.base'; 515e41f4b71Sopenharmony_ci import userIAM_userAuth from '@ohos.userIAM.userAuth'; 516e41f4b71Sopenharmony_ci 517e41f4b71Sopenharmony_ci // Set authentication parameters. 518e41f4b71Sopenharmony_ci const authParam: userIAM_userAuth.AuthParam = { 519e41f4b71Sopenharmony_ci challenge: new Uint8Array([49, 49, 49, 49, 49, 49]), 520e41f4b71Sopenharmony_ci authType: [userIAM_userAuth.UserAuthType.PIN, userIAM_userAuth.UserAuthType.FACE], 521e41f4b71Sopenharmony_ci authTrustLevel: userIAM_userAuth.AuthTrustLevel.ATL3, 522e41f4b71Sopenharmony_ci }; 523e41f4b71Sopenharmony_ci 524e41f4b71Sopenharmony_ci // Set the authentication page. 525e41f4b71Sopenharmony_ci const widgetParam: userIAM_userAuth.WidgetParam = { 526e41f4b71Sopenharmony_ci title: 'Verify identity', 527e41f4b71Sopenharmony_ci }; 528e41f4b71Sopenharmony_ci 529e41f4b71Sopenharmony_ci try { 530e41f4b71Sopenharmony_ci // Obtain an authentication object. 531e41f4b71Sopenharmony_ci let userAuthInstance = userIAM_userAuth.getUserAuthInstance(authParam, widgetParam); 532e41f4b71Sopenharmony_ci console.info('get userAuth instance success'); 533e41f4b71Sopenharmony_ci // Subscribe to the authentication result. 534e41f4b71Sopenharmony_ci userAuthInstance.on('result', { 535e41f4b71Sopenharmony_ci onResult(result) { 536e41f4b71Sopenharmony_ci console.info(`userAuthInstance callback result: ${JSON.stringify(result)}`); 537e41f4b71Sopenharmony_ci // Unsubscribe from the authentication result if required. 538e41f4b71Sopenharmony_ci userAuthInstance.off('result'); 539e41f4b71Sopenharmony_ci } 540e41f4b71Sopenharmony_ci }); 541e41f4b71Sopenharmony_ci console.info('auth on success'); 542e41f4b71Sopenharmony_ci userAuthInstance.start(); 543e41f4b71Sopenharmony_ci console.info('auth start success'); 544e41f4b71Sopenharmony_ci } catch (error) { 545e41f4b71Sopenharmony_ci const err: BusinessError = error as BusinessError; 546e41f4b71Sopenharmony_ci console.error(`auth catch error. Code is ${err?.code}, message is ${err?.message}`); 547e41f4b71Sopenharmony_ci } 548e41f4b71Sopenharmony_ci``` 549e41f4b71Sopenharmony_ci 550e41f4b71Sopenharmony_ci2. Cancel an authentication. 551e41f4b71Sopenharmony_ci```ts 552e41f4b71Sopenharmony_ci // API version 10 553e41f4b71Sopenharmony_ci import type {BusinessError} from '@ohos.base'; 554e41f4b71Sopenharmony_ci import userIAM_userAuth from '@ohos.userIAM.userAuth'; 555e41f4b71Sopenharmony_ci 556e41f4b71Sopenharmony_ci const authParam: userIAM_userAuth.AuthParam = { 557e41f4b71Sopenharmony_ci challenge: new Uint8Array([49, 49, 49, 49, 49, 49]), 558e41f4b71Sopenharmony_ci authType: [userIAM_userAuth.UserAuthType.PIN, userIAM_userAuth.UserAuthType.FACE], 559e41f4b71Sopenharmony_ci authTrustLevel: userIAM_userAuth.AuthTrustLevel.ATL3, 560e41f4b71Sopenharmony_ci }; 561e41f4b71Sopenharmony_ci 562e41f4b71Sopenharmony_ci const widgetParam: userIAM_userAuth.WidgetParam = { 563e41f4b71Sopenharmony_ci title: 'Verify identity', 564e41f4b71Sopenharmony_ci }; 565e41f4b71Sopenharmony_ci 566e41f4b71Sopenharmony_ci try { 567e41f4b71Sopenharmony_ci // Obtain an authentication object. 568e41f4b71Sopenharmony_ci let userAuthInstance = userIAM_userAuth.getUserAuthInstance(authParam, widgetParam); 569e41f4b71Sopenharmony_ci console.info('get userAuth instance success'); 570e41f4b71Sopenharmony_ci // Start user authentication. 571e41f4b71Sopenharmony_ci userAuthInstance.start(); 572e41f4b71Sopenharmony_ci console.info('auth start success'); 573e41f4b71Sopenharmony_ci // Cancel the authentication. 574e41f4b71Sopenharmony_ci userAuthInstance.cancel(); 575e41f4b71Sopenharmony_ci console.info('auth cancel success'); 576e41f4b71Sopenharmony_ci } catch (error) { 577e41f4b71Sopenharmony_ci const err: BusinessError = error as BusinessError; 578e41f4b71Sopenharmony_ci console.error(`auth catch error. Code is ${err?.code}, message is ${err?.message}`); 579e41f4b71Sopenharmony_ci } 580e41f4b71Sopenharmony_ci``` 581