1# Neural Network Runtime Device Access
2
3## Overview
4
5### Function Introduction
6
7Neural Network Runtime (NNRt) functions as a bridge to connect the upper-layer AI inference framework and underlying acceleration chips, implementing cross-chip inference computing of AI models.
8
9NNRt opens HDIs for chip vendors to connect dedicated acceleration chips to NNRt to interconnect with the OpenHarmony ecosystem.
10
11### Basic Concepts
12Before you get started, it would be helpful for you to have a basic understanding of the following concepts:
13
14- Hardware Device Interface (HDI): defines APIs for cross-process communication between services in OpenHarmony.
15- Interface Description Language (IDL): defines the HDI language format.
16
17### Constraints
18- System version: OpenHarmony trunk version.
19- Development environment: Ubuntu 18.04 or later.
20- Access device: a chip with AI computing capabilities.
21
22### Working Principles
23NNRt connects to device chips through HDIs, which implement cross-process communication between services.
24
25**Figure 1** NNRt architecture
26
27![NNRt architecture](./figures/nnrt_arch_diagram.png)
28
29The NNRt architecture consists of three layers: AI applications at the application layer, AI inference framework and NNRt at the system layer, and device services at the chip layer. To use a dedicated acceleration chip model for inference, an AI application needs to call the underlying dedicated AI acceleration chip through the AI inference framework and NNRt. NNRt is responsible for adapting to various underlying dedicated acceleration chips. It opens standard and unified HDIs for various AI acceleration chips to access the OpenHarmony ecosystem. In addition, NNRt opens standard and unified APIs to connect to various upper-layer AI inference frameworks.
30
31During program running, the AI application, AI inference framework, and NNRt reside in the user process, and the underlying AI chip device services reside in the HDI service process. NNRt implements the HDI client and the service side implements HDI Service to fulfill cross-process communication through the Hardware Driver Foundation (HDF) subsystem.
32
33## How to Develop
34
35### Application Scenario
36Suppose you are connecting an AI acceleration chip, for example, RK3568, to NNRt. The following exemplifies how to connect the RK3568 chip to NNRt through HDI V2.0 to implement AI model inference. The process is similar for HDI V1.0.
37> **NOTE**<br>In this tutorial, the purpose of connecting the RK3568 chip to NNRt is to utilize the runtime and CPU operators of MindSpore Lite, instead of implementing the CPU driver. Therefore, the RK3568 chip depends on the dynamic libraries and header files of MindSpore Lite. In practice, the RK3568 chip does not depend on any library or header file of MindSpore Lite.
38
39### Development Flowchart
40The following figure shows the process of connecting a dedicated AI acceleration chip to NNRt.
41
42**Figure 2** Process of connecting a dedicated AI acceleration chip to NNRt
43
44![Process of connecting a dedicated AI acceleration chip to NNRt](./figures/nnrt_dev_flow.png)
45
46### Development Procedure
47The following uses the RK3568 chip as an example to describe the development procedure.
48#### Generating the HDI Header File
49Download the OpenHarmony source code from the open source community, build the `drivers_interface` component, and generate the HDI header file.
50
511. [Download the source code](../get-code/sourcecode-acquire.md).
52
532. Go to the root directory of OpenHarmony source code, and compile the IDL API file of NNRt.
54    ```shell
55    ./build.sh --product-name rk3568 –ccache --build-target drivers_interface_nnrt
56    ```
57
58    After the compilation is complete, an HDI header file of the C++ language is generated in the `out/rk3568/gen/drivers/interface/nnrt/v2_0` directory. To generate a header file of the C language, run the following command to set the language field in the `drivers/interface/nnrt/v2_0/BUILD.gn` file before starting compilation:
59
60    ```shell
61    language = "c"
62    ```
63
64    The directory of the generated header file is as follows:
65    ```text
66    out/rk3568/gen/drivers/interface/nnrt
67    └── v2_0
68        ├── drivers_interface_nnrt__libnnrt_proxy_2.0_external_deps_temp.json
69        ├── drivers_interface_nnrt__libnnrt_stub_2.0_external_deps_temp.json
70        ├── innrt_device.h                        # Header file of the HDI
71        ├── iprepared_model.h                     # Header file of the AI model
72        ├── libnnrt_proxy_2.0__notice.d
73        ├── libnnrt_stub_2.0__notice.d
74        ├── model_types.cpp                       # Implementation file for AI model structure definition
75        ├── model_types.h                         # Header file for AI model structure definition
76        ├── nnrt_device_driver.cpp                # Device driver implementation example
77        ├── nnrt_device_proxy.cpp
78        ├── nnrt_device_proxy.h
79        ├── nnrt_device_service.cpp               # Implementation file for device services
80        ├── nnrt_device_service.h                 # Header file for device services
81        ├── nnrt_device_stub.cpp
82        ├── nnrt_device_stub.h
83        ├── nnrt_types.cpp                        # Implementation file for data type definition
84        ├── nnrt_types.h                          # Header file for data type definitions
85        ├── node_attr_types.cpp                   # Implementation file for AI model operator attribute definition
86        ├── node_attr_types.h                     # Header file for AI model operator attribute definition
87        ├── prepared_model_proxy.cpp
88        ├── prepared_model_proxy.h
89        ├── prepared_model_service.cpp            # Implementation file for AI model services
90        ├── prepared_model_service.h              # Header file for AI model services
91        ├── prepared_model_stub.cpp
92        └── prepared_model_stub.h
93    ```
94
95#### Implementing the HDI Service
96
971. Go to the root directory of OpenHarmony source code, and create the `nnrt` folder in the `drivers/peripheral` directory for HDI service development. The directory structure is as follows:
98    ```text
99    drivers/peripheral/nnrt
100    ├── bundle.json
101    ├── v2_0
102        ├── BUILD.gn                                  # Code build script
103        └── hdi_cpu_service                           # Customized directory
104            ├── BUILD.gn                              # Code build script
105            ├── include
106            │   ├── nnrt_device_service.h             # Header file for device services
107            │   ├── node_functions.h                  # Optional, depending on the actual implementation
108            │   ├── node_registry.h                   # Optional, depending on the actual implementation
109            │   └── prepared_model_service.h          # Header file for AI model services
110            └── src
111                ├── nnrt_device_driver.cpp            # Implementation file for the device driver
112                ├── nnrt_device_service.cpp           # Implementation file for device services
113                ├── nnrt_device_stub.cpp              # Optional, depending on the actual implementation
114                ├── node_attr_types.cpp               # Optional, depending on the actual implementation
115                ├── node_functions.cpp                # Optional, depending on the actual implementation
116                ├── node_registry.cpp                 # Optional, depending on the actual implementation
117                └── prepared_model_service.cpp        # Implementation file for AI model services
118    ```
119
1202. Implement the device driver. Unless otherwise required, you can directly use the `nnrt_device_driver.cpp` file generated through IDL file compilation.
121
1223. Implement service APIs by referring to the `nnrt_device_service.cpp` and `prepared_model_service.cpp` files. For details about the API definitions, see [NNRt HDI Definitions](https://gitee.com/openharmony/drivers_interface/tree/master/nnrt).
123
1244. Compile the implementation files for device drivers and services as shared libraries.
125
126    Create the `BUILD.gn` file with the following content in the `drivers/peripheral/nnrt/v2_0/hdi_cpu_service/` directory. For details about how to set related parameters, see [Compilation and Building](https://gitee.com/openharmony/build).
127
128    ```shell
129    import("//build/ohos.gni")
130    import("//drivers/hdf_core/adapter/uhdf2/uhdf.gni")
131
132    ohos_shared_library("libnnrt_service_2.0") {
133      include_dirs = []
134      sources = [
135        "src/nnrt_device_service.cpp",
136        "src/node_functions.cpp",
137        "src/node_registry.cpp",
138        "src/prepared_model_service.cpp",
139        "src/shared_buffer_parser.cpp",
140        "src/validation.cpp",
141      ]
142
143      external_deps = [
144        "c_utils:utils",
145        "drivers_interface_nnrt:libnnrt_stub_2.0",
146        "hdf_core:libhdf_utils",
147        "hilog_native:libhilog",
148        "ipc:ipc_core",
149      ]
150
151      install_images = [ chipset_base_dir ]
152      subsystem_name = "hdf"
153      part_name = "drivers_peripheral_nnrt"
154    }
155
156    ohos_shared_library("libnnrt_driver") {
157      include_dirs = []
158      sources = [ "src/nnr_device_driver.cpp" ]
159      deps = [ ":libnnrt_service_2.0" ]
160
161      external_deps = [
162        "c_utils:utils",
163        "drivers_interface_nnrt:libnnrt_stub_2.0",
164        "hdf_core:libhdf_host",
165        "hdf_core:libhdf_ipc_adapter",
166        "hdf_core:libhdf_utils",
167        "hdf_core:libhdi",
168        "hilog_native:libhilog",
169        "ipc:ipc_core",
170      ]
171
172      install_images = [ chipset_base_dir ]
173      subsystem_name = "hdf"
174      part_name = "drivers_peripheral_nnrt"
175    }
176
177    group("hdf_nnrt_service") {
178      deps = [
179        ":libnnrt_driver",
180        ":libnnrt_service_2.0",
181      ]
182    }
183    ```
184
185    Add `group("hdf_nnrt_service")` to the `drivers/peripheral/nnrt/v2_0/BUILD.gn` file so that it can be referenced at a higher directory level.
186    ```shell
187    if (defined(ohos_lite)) {
188      group("nnrt_entry") {
189        deps = []
190      }
191    } else {
192      group("nnrt_entry") {
193        deps = [ "./hdi_cpu_service:hdf_nnrt_service" ]
194      }
195    }
196    ```
197
198    Create the `drivers/peripheral/nnrt/bundle.json` file to define the new `drivers_peripheral_nnrt` component.
199    ```json
200    {
201      "name": "drivers_peripheral_nnrt",
202      "description": "Neural network runtime device driver",
203      "version": "4.0",
204      "license": "Apache License 2.0",
205      "component": {
206        "name": "drivers_peripheral_nnrt",
207        "subsystem": "hdf",
208        "syscap": [""],
209        "adapter_system_type": ["standard"],
210        "rom": "1024KB",
211        "ram": "2048KB",
212        "deps": {
213          "components": [
214            "c_utils",
215            "hdf_core",
216            "hilog_native",
217            "ipc"
218          ],
219          "third_part": [
220            "bounds_checking_function"
221          ]
222        },
223        "build": {
224          "sub_component": [
225            "//drivers/peripheral/nnrt/v2_0:nnrt_entry"
226          ],
227          "test": [
228          ],
229          "inner_kits": [
230          ]
231        }
232      }
233    }
234    ```
235
236#### Declaring the HDI Service
237
238  In the `uhdf` directory, declare the user-mode driver and services in the `.hcs` file of the corresponding product. For example, for the RK3568 chip, add the following configuration to the `vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs` file:
239  ```text
240  nnrt :: host {
241      hostName = "nnrt_host";
242      priority = 50;
243      uid = "";
244      gid = "";
245      caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"];
246      nnrt_device :: device {
247          device0 :: deviceNode {
248              policy = 2;
249              priority = 100;
250              moduleName = "libnnrt_driver.z.so";
251              serviceName = "nnrt_device_service";
252          }
253      }
254  }
255  ```
256> **NOTE**<br>After modifying the `.hcs` file, you need to delete the `out` folder and compile the file again for the modification to take effect.
257
258#### Configuring the User ID and Group ID of the Host Process
259  In the scenario of creating an nnrt_host process, you need to configure the user ID and group ID of the corresponding process. The user ID is configured in the `base/startup/init/services/etc/passwd` file, and the group ID is configured in the `base/startup/init/services/etc/group` file.
260  ```text
261  # Add the user ID in base/startup/init/services/etc/passwd.
262  nnrt_host:x:3311:3311:::/bin/false
263
264  # Add the group ID in base/startup/init/services/etc/group.
265  nnrt_host:x:3311:
266  ```
267
268#### Configuring SELinux
269
270The SELinux feature has been enabled for the OpenHarmony. You need to configure SELinux rules for the new processes and services so that they can run the host process to access certain resources, release HDI services, etc.
271
2721. Add the following configuration to the `base/security/selinux/sepolicy/ohos_policy/drivers/adapter/public/hdf_service_contexts` file:
273    ```text
274    # Add the security context configuration.
275    nnrt_device_service        u:object_r:hdf_nnrt_device_service:s0
276    ```
277    > **NOTE**<br>`nnrt_host` indicates the process name configured in [Declaring the HDI Service](#declaring-the-hdi-service).
278
2792. Add the following configuration to the `base/security/selinux/sepolicy/ohos_policy/drivers/adapter/public/hdf_service.te` file:
280    ```text
281    # Add the security context configuration.
282    type hdf_nnrt_device_service, hdf_service_attr;
283    ```
284
2853. Add the following configuration to the `base/security/selinux/sepolicy/ohos_policy/drivers/adapter/public/hdfdomain.te` file:
286    ```text
287    # Add the security context configuration.
288    neverallow { domain -hdfdomain -sadomain } { hdfdomain -nnrt_host -allocator_host -hdf_public_domain }:binder call;
289    ```
290
2914. Add the following configuration to the `base/security/selinux/sepolicy/ohos_policy/drivers/adapter/public/type.te` file:
292    ```text
293    # Add the security context configuration.
294    type nnrt_host, hdfdomain, domain;
295    ```
296
2975. Add the following configuration to the `base/security/selinux/sepolicy/ohos_policy/drivers/adapter/vendor/hdf_devmgr.te` file:
298    ```text
299    # Add the security context configuration.
300    allow hdf_devmgr nnrt_host:binder { call transfer };
301    allow hdf_devmgr nnrt_host:dir { search };
302    allow hdf_devmgr nnrt_host:file { open read write };
303    allow hdf_devmgr nnrt_host:process { getattr };
304    ```
305
3066. Add the following configuration to the `base/security/selinux/sepolicy/ohos_policy/drivers/adapter/vendor/init.te` file:
307    ```text
308    # Add the security context configuration.
309    allow init nnrt_host:process { rlimitinh siginh transition };
310    ```
311
3127. Modify the configuration in the `base/security/selinux/sepolicy/ohos_policy/startup/init/public/chipset_init.te` file.
313
314    Find the line containing `chipset_init`.
315    ```text
316    allow chipset_init { light_host input_user_host wifi_host camera_host power_host audio_host }:process { rlimitinh siginh transition };
317    ```
318    Add `nnrt_host` to the `host` list.
319    ```text
320    allow chipset_init { light_host input_user_host wifi_host camera_host power_host audio_host nnrt_host }:process { rlimitinh siginh transition };
321    ```
322
3238. Create the `nnrt_host.te` configuration file.
324    ```shell
325    # Create the nnrt folder.
326    mkdir base/security/selinux/sepolicy/ohos_policy/drivers/peripheral/nnrt
327
328    # Create the vendor folder.
329    mkdir base/security/selinux/sepolicy/ohos_policy/drivers/peripheral/nnrt/vendor
330
331    # Create the `nnrt_host.te` file.
332    touch base/security/selinux/sepolicy/ohos_policy/drivers/peripheral/nnrt/vendor/nnrt_host.te
333    ```
334
3359. Write the following required permissions to the `nnrt_host.te` file:
336    ```text
337    allow nnrt_host dev_hdf_kevent:chr_file { ioctl };
338    allow nnrt_host hilog_param:file { read open map };
339    allow nnrt_host sh:binder { transfer };
340    allow nnrt_host samgr:binder { call };
341    allow nnrt_host dev_ashmem_file:chr_file { open };
342    allow nnrt_host dev_unix_socket:dir { search };
343    allow nnrt_host hdf_device_manager:hdf_devmgr_class { get };
344    allow nnrt_host hdf_nnrt_device_service:hdf_devmgr_class { add get };
345    allow nnrt_host dev_console_file:chr_file { read write };
346    allow nnrt_host debug_param:file { read open map };
347    allow nnrt_host sa_device_service_manager:samgr_class { get };
348    allow nnrt_host hdf_devmgr:binder { call transfer };
349    allow nnrt_host hdf_nnrt_device_service:binder { call };
350    allow nnrt_host sysfs_devices_system_cpu:file { read open getattr };
351    allow sh hdf_nnrt_device_service:hdf_devmgr_class { add get };
352    allow sh hdf_hci_interface_service:hdf_devmgr_class { get };
353    allow sh nnrt_host:dir { getattr search };
354    allow sh nnrt_host:file { open read };
355    allow sh nnrt_host:process { getattr };
356    allow sh nnrt_host:binder { call };
357    allow sh nnrt_host:fd { use };
358    ```
359
36010. Configure access permissions because SELinux uses the trustlist access permission mechanism. Upon service startup, run the `dmesg` command to view the AVC alarm,
361which provides a list of missing permissions. For details about the SELinux configuration, see [security_selinux](https://gitee.com/openharmony/security_selinux/blob/master/README-en.md).
362    ```shell
363    hdc_std shell
364    dmesg | grep nnrt
365    ```
366
367#### Configuring the Component Build Entry
368Access the `chipset_common.json` file.
369```shell
370vim //productdefine/common/inherit/chipset_common.json
371```
372Add the following configuration to `"subsystems"`, `"subsystem":"hdf"`, and `"components"`:
373```shell
374{
375  "component": "drivers_peripheral_nnrt",
376  "features": []
377}
378```
379
380#### Deleting the out Directory and Building the Entire System
381```shell
382# Delete the out directory.
383rm -rf ./out
384
385# Build the entire system.
386./build.sh --product-name rk3568 –ccache --jobs=4
387```
388
389
390### Commissioning and Verification
391On completion of service development, you can use XTS to verify its basic functions and compatibility. The operation procedure is as follows:
392
3931. Compile the **hats** test cases of NNRt in the `test/xts/hats/ai/nnrt/hdi` directory.
394    ```shell
395    # Go to the hats directory.
396    cd test/xts/hats
397
398    # Compile the `hats` test cases.
399    ./build.sh suite=hats system_size=standard product_name=rk3568
400
401    # Return to the root directory.
402    cd -
403    ```
404    The test case executable file `HatsHdfNnrtFunctionTest` is exported to the `out/rk3568/suites/hats/testcases/` directory.
405
4062. Push the test case executable file to the `/data/local/tmp/` directory of the RK3568 device.
407    ```shell
408    # Push the test case executable file to the device. In this example, the executable file is HatsHdfNnrtFunctionTest.
409    hdc_std file send out/rk3568/suites/hats/testcases/HartsHdfNnrtFunctionTest /data/local/tmp/
410
411    # Grant required permissions to the test case executable file.
412    hdc_std shell "chmod +x /data/local/tmp/HatsHdfNnrtFunctionTest"
413    ```
414
4153. Execute the test cases and view the result.
416    ```shell
417    # Execute the test cases.
418    hdc_std shell "/data/local/tmp/HatsHdfNnrtFunctionTest"
419    ```
420
421    According to the following example test report, all of the 47 test cases are successfully executed, indicating the service has passed the compatibility test.
422    ```text
423    ...
424    [----------] Global test environment tear-down
425    Gtest xml output finished
426    [==========] 47 tests from 3 test suites ran. (515 ms total)
427    [  PASSED  ] 47 tests.
428    ```
429
430### Development Example
431For the complete demo code, see [NNRt Service Implementation Example](https://gitee.com/openharmony/ai_neural_network_runtime/tree/master/example/drivers).
432
4331. Go to the root directory of OpenHarmony source code and create the `nnrt` folder in the `drivers/peripheral` directory. Then, copy the `example/driver/nnrt/v2_0` folder from the  `foundation/ai/neural_network_runtime` directory of NNRt source code to the created `nnrt` folder.
434    ```shell
435    cp -r example/drivers/nnrt/v2_0 drivers/peripheral/nnrt
436    ```
437
4382. Add the `bundle.json` file to the `drivers/peripheral/nnrt` directory. For details about how to write the `bundle.json` file, see [Implementing the HDI Service](#implementing-the-hdi-service).
439
4403. Add the dependency files of MindSpore Lite because the demo depends on the CPU operator of MindSpore Lite.
441    - Run the following command in the root directory of the OpenHarmony source code to build the MindSpore Lite dynamic library: The MindSpore source code is stored in `third_party/mindspore` in the root directory of the OpenHarmony source code.
442      ```shell
443      # Build the MindSpore Lite dynamic libraries.
444      ./build.sh --product-name rk3568 -ccaache --jobs 4 --build-target mindspore_lib
445      ```
446    - Create the `mindspore` folder in the `drivers/peripheral/nnrt/v2_0` directory to store the dynamic libraries and header files of MindSpore Lite.
447      ```shell
448      mkdir drivers/peripheral/nnrt/v2_0/mindspore
449      ```
450    - Copy the `mindspore-src/source/include` directory in the MindSpore source code to the `drivers/peripheral/nnrt/v2_0/mindspore` directory.
451      ```shell
452      cp third_party/mindspore/mindspore-src/source/include drivers/peripheral/nnrt/v2_0/mindspore
453      ```
454    - Create and copy the `schema` file of MindSpore Lite.
455      ```shell
456      # Create the mindspore_schema folder.
457      mkdir drivers/peripheral/nnrt/v2_0/hdi_cpu_service/include/mindspore_schema
458
459      # Copy the MindSpore schema file from the third_party directory.
460      cp third_party/mindspore/mindspore-src/source/mindspore/lite/schema/* drivers/peripheral/nnrt/v2_0/hdi_cpu_service/include/mindspore_schema/
461      ```
462    - Copy the MindSpore Lite dynamic library to the `mindspore` directory.
463      ```shell
464      # Create the `mindspore` folder in the `drivers/peripheral/nnrt/v2_0/mindspore` directory.
465      mkdir drivers/peripheral/nnrt/v2_0/mindspore/mindspore
466
467      # Copy the MindSpore dynamic libraries from the `out` folder to the `drivers/peripheral/nnrt/v2_0/mindspore/mindspore` directory.
468      cp out/rk3568/package/phone/system/lib/libmindspore-lite.so drivers/peripheral/nnrt/v2_0/mindspore/mindspore/
469      ```
4704. Follow the [development procedure](#development-procedure) to complete other configurations.
471