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