• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# DRM Solution Development
2
3DRM plugins implement the DRM HDI, and the DRM framework of DRM Kit loads the DRM plugins through the HDI.
4
5Plugins are developed by DRM solution integrators and placed in the /vendor partition of devices.
6
7For details about the development process of the OpenHarmony HDI plugin driver service, see [HDF Driver Development Process](../../../device-dev/driver/driver-hdf-manage.md). The IDL of the DRM HDI API is defined in the **ohos/drivers/interface/drm/v1_0** directory, where **v1_0** is the HDI API version number and should be changed to the actual version number.
8
9After the IDL of the DRM HDI API is built, you can find the generated .h and .cpp files of the corresponding version in **//ohos/out/*productModel*/gen/drivers/interface/drm/v1_0/**.
10
11To implement a DRM plugin (clearplay used as an example), perform the following steps:
12
131. [Plugin Development](#plugin-development)
14    - Module addition
15    - Driver entry implementation
16    - HDI API implementation
17    - Compilation configuration
18    - Component configuration
19    - Component compilation entry configuration
20    - Service code compilation
21
222. [DRM Plugin Service Configuration](#drm-plugin-service-configuration)
23    - hcs configuration
24    - Host user and group configuration
25    - Dynamic loading
26
273. [Adding SELinux Permissions](#adding-selinux-permissions)
28
29## Plugin Development
30
31### Module Addition
32
33Create a plugin directory. The following is an example:
34```
35//drivers/peripheral/clearplay
36.
37├── BUILD.gn     # Module compilation file.
38├── bundle.json  # Component configuration file.
39├── hdi_service  # HDI service code of the DRM solution.
40│   ├── BUILD.gn # Configuration file for the HDI service code of the DRM solution.
41│   ├── common   # Utility code for the HDI service of the DRM solution, including JSON parsing and Base64 encoding/decoding.
42│   ├── include  # Header file for the HDI service of the DRM solution.
43│   └── src      # Implementation code for the HDI service of DRM solution.
44├── interfaces   # Capability interfaces for the HDI service of the DRM solution.
45│   ├── BUILD.gn # Configuration file for the capability interfaces of the HDI service code of the DRM solution.
46│   ├── include  # Capability interface file for the HDI service of the DRM solution.
47│   └── src      # Implementation of the capability interfaces of the HDI service of the DRM solution.
48└── README.md # Description of the HDI service component in the DRM solution.
49```
50
51### Driver Entry Implementation
52
53Refer to **//ohos/out/productModel/gen/drivers/interface/drm/v1_0/media_key_system_factory_driver.cpp** for the driver entry implementation. Make the following modifications in the driver entry and configure the compilation manually:
54
55```
56using namespace OHOS::HDI::Drm::V1_0; // 1. V1_0 indicates the HDI API version number. Replace it with the actual version number.
57
58struct HdfMediaKeySystemFactoryHost {
59    struct IDeviceIoService ioService;
60    OHOS::sptr<OHOS::IRemoteObject> stub;
61};
62static int HdfMediaKeySystemFactoryDriverBind(struct HdfDeviceObject *deviceObject)
63{
64    auto *hdfMediaKeySystemFactoryHost = new (std::nothrow) HdfMediaKeySystemFactoryHost;
65    if (hdfMediaKeySystemFactoryHost == nullptr) {
66        HDF_LOGE("%{public}s: failed to create create HdfMediaKeySystemFactoryHost object", __func__);
67        return HDF_FAILURE;
68    }
69    int ret = HdfDeviceObjectSetInterfaceDesc(deviceObject, "ohos.hdi.drm.v1_0.IMediaKeySystemFactory"); // 2. Bind the service interface descriptor. This allows the DRM framework to access the HDI service of the DRM solution via the descriptor. Adjust according to the specific HDI API version number.
70    if (ret != HDF_SUCCESS) {
71        HDF_LOGE("%{public}s: failed to HdfDeviceObjectSetInterfaceDesc", __func__);
72    }
73
74    hdfMediaKeySystemFactoryHost->ioService.Dispatch = MediaKeySystemFactoryDriverDispatch;
75    hdfMediaKeySystemFactoryHost->ioService.Open = NULL;
76    hdfMediaKeySystemFactoryHost->ioService.Release = NULL;
77
78    auto serviceImpl = OHOS::HDI::Drm::V1_0::IMediaKeySystemFactory::Get("clearplay_service", true); // 3. Obtain the HDI service instance of the DRM solution.
79    if (serviceImpl == nullptr) {
80        HDF_LOGE("%{public}s: failed to get of implement service", __func__);
81        delete hdfMediaKeySystemFactoryHost;
82        return HDF_FAILURE;
83    }
84
85    hdfMediaKeySystemFactoryHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
86        OHOS::HDI::Drm::V1_0::IMediaKeySystemFactory::GetDescriptor()); // 4. Obtain the stub object corresponding to the HDI service implementation of the DRM solution.
87    if (hdfMediaKeySystemFactoryHost->stub == nullptr) {
88        HDF_LOGE("%{public}s: failed to get stub object", __func__);
89        delete hdfMediaKeySystemFactoryHost;
90        return HDF_FAILURE;
91    }
92
93    deviceObject->service = &hdfMediaKeySystemFactoryHost->ioService;
94    return HDF_SUCCESS;
95}
96
97static int32_t MediaKeySystemFactoryDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
98    struct HdfSBuf *reply)
99{
100    auto *hdfMediaKeySystemFactoryHost =
101        CONTAINER_OF(client->device->service, struct HdfMediaKeySystemFactoryHost, ioService);
102
103    OHOS::MessageParcel *dataParcel = nullptr;
104    OHOS::MessageParcel *replyParcel = nullptr;
105    OHOS::MessageOption option;
106
107    if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
108        HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__);
109        return HDF_ERR_INVALID_PARAM;
110    }
111    if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
112        HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__);
113        return HDF_ERR_INVALID_PARAM;
114    }
115
116    return hdfMediaKeySystemFactoryHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
117}
118```
119
120### HDI API Implementation
121
122Refer to the .cpp file automatically generated in **//ohos/out/*productModel*/gen/drivers/interface/drm/v1_0/** for the HDI API implementation. You can modify or add files based on service requirements. The following uses **media_key_system_factory_service.cpp** as an example.
123
124```
125extern "C" IMediaKeySystemFactory *MediaKeySystemFactoryImplGetInstance(void)
126{
127    // Add implementation here.
128    return new (std::nothrow) MediaKeySystemFactoryService();
129}
130
131int32_t MediaKeySystemFactoryService::IsMediaKeySystemSupported(const std::string& name, const std::string& mimeType,
132     OHOS::HDI::Drm::V1_0::ContentProtectionLevel level, bool& isSupported)
133{
134    // Add implementation here.
135    return HDF_SUCCESS;
136}
137
138int32_t MediaKeySystemFactoryService::CreateMediaKeySystem(sptr<OHOS::HDI::Drm::V1_0::IMediaKeySystem>& mediaKeySystem)
139{
140    // Add implementation here.
141    return HDF_SUCCESS;
142}
143
144int32_t MediaKeySystemFactoryService::GetMediaKeySystemDescription(std::string& name, std::string& uuid)
145{
146    // Add implementation here.
147    return HDF_SUCCESS;
148}
149
150```
151
152### Compilation Configuration
153//drivers/peripheral/clearplay/BUILD.gn
154
155```
156if (defined(ohos_lite)) {
157  group("clearplay_entry") {
158    deps = []
159  }
160} else {
161  group("clearplay_entry") {
162    deps = [
163      "./hdi_service:hdf_clearplay_service",
164      "./interfaces:hdf_clearplay_interfaces",
165    ]
166  }
167}
168```
169
170//drivers/peripheral/clearplay/hdi_service/BUILD.gn
171```
172import("//build/ohos.gni")
173
174ohos_shared_library("libmedia_key_system_factory_clearplay_service_1.0") {
175  include_dirs = [
176    "./include",
177    "./include/drm/v1_0",
178    "./include/drm",
179    "./../interfaces/include",
180    "./../interfaces/include/drm/v1_0",
181    "./../interfaces/include/drm",
182    "./common",
183  ]
184  sources = [
185    "./common/base64_utils.cpp",
186    "./src/media_decrypt_module_service.cpp",
187    "./src/media_key_session_callback_service.cpp",
188    "./src/media_key_session_service.cpp",
189    "./src/media_key_system_callback_service.cpp",
190    "./src/media_key_system_factory_service.cpp",
191    "./src/media_key_system_service.cpp",
192    "./src/oem_certificate_service.cpp",
193  ]
194
195  deps = [ ]
196
197  cflags = [
198    "-Wall",
199    "-Wextra",
200    "-Werror",
201    "-fsigned-char",
202    "-fno-common",
203    "-fno-strict-aliasing",
204  ]
205
206  external_deps = [
207    "c_utils:utils",
208    "hdf_core:libhdf_utils",
209    "hilog:libhilog",
210    "ipc:ipc_single",
211  ]
212
213  install_images = [ chipset_base_dir ]
214  subsystem_name = "hdf"
215  part_name = "drivers_peripheral_clearplay"
216}
217
218group("hdf_clearplay_service") {
219  deps = [ ":libmedia_key_system_factory_clearplay_service_1.0" ]
220}
221```
222
223//drivers/peripheral/clearplay/interfaces/BUILD.gn
224
225```
226import("//build/ohos.gni")
227
228ohos_shared_library("libclearplay_driver") {
229  include_dirs = [
230    "./include",
231    "./include/drm",
232  ]
233
234  public_configs = [ ":clearplay_imp_external_library_config" ]
235  sources = [ "./src/media_key_system_factory_driver.cpp" ]
236
237  external_deps = [
238    "c_utils:utils",
239    "drivers_interface_drm:libdrm_stub_1.0",
240    "hdf_core:libhdf_host",
241    "hdf_core:libhdf_ipc_adapter",
242    "hdf_core:libhdf_utils",
243    "hdf_core:libhdi",
244    "hilog:libhilog",
245    "ipc:ipc_single",
246  ]
247  cflags = [
248    "-Wall",
249    "-Wextra",
250    "-Werror",
251    "-fsigned-char",
252    "-fno-common",
253    "-fno-strict-aliasing",
254  ]
255  shlib_type = "hdi"
256  install_images = [ chipset_base_dir ]
257  subsystem_name = "hdf"
258  part_name = "drivers_peripheral_clearplay"
259}
260
261config("clearplay_imp_external_library_config") {
262  include_dirs =
263      [ "//drivers/peripheral/clearplay/interfaces/include/drm/v1_0" ]
264}
265group("hdf_clearplay_interfaces") {
266  deps = [ ":libclearplay_driver" ]
267}
268```
269
270### Component Configuration
271
272Create the **drivers/peripheral/clearplay/build.json** file to define the new drivers_peripheral_clearplay component.
273
274```
275{
276  "name": "@ohos/drivers_peripheral_clearplay",
277  "description": "clearplay drm device driver",
278  "version": "4.0",
279  "license": "Apache License 2.0",
280  "publishAs": "code-segment",
281  "segment": {
282    "destPath": "drivers/peripheral/clearplay"
283  },
284  "dirs": {},
285  "scripts": {},
286  "component": {
287    "name": "drivers_peripheral_clearplay",
288    "subsystem": "hdf",
289    "syscap": [],
290    "adapted_system_type": ["standard"],
291    "rom": "",
292    "ram": "",
293    "deps": {
294      "components": [
295        "bounds_checking_function",
296        "drivers_interface_drm",
297        "c_utils",
298        "hdf_core",
299        "hilog",
300        "ipc"
301      ],
302      "third_party": []
303    },
304    "build": {
305      "sub_component": [
306        "//drivers/peripheral/clearplay:clearplay_entry"
307      ],
308      "inner_kits": [
309        {
310          "type":"so",
311          "name": "//drivers/peripheral/clearplay/hdi_service:libmedia_key_system_factory_clearplay_service_1.0",
312            "header": {
313              "header_files": [
314                "imedia_decrypt_module.h",
315                "imedia_key_session_callback.h",
316                "imedia_key_session.h",
317                "imedia_key_system_callback.h",
318                "imedia_key_system_factory.h",
319                "imedia_key_system.h",
320                "ioem_certificate.h",
321                "media_decrypt_module_proxy.h",
322                "media_decrypt_module_stub.h",
323                "media_key_session_callback_proxy.h",
324                "media_key_session_callback_stub.h",
325                "media_key_session_proxy.h",
326                "media_key_session_stub.h",
327                "media_key_system_callback_proxy.h",
328                "media_key_system_callback_stub.h",
329                "media_key_system_factory_proxy.h",
330                "media_key_system_factory_stub.h",
331                "media_key_system_proxy.h",
332                "media_key_system_stub.h",
333                "media_key_system_types.h",
334                "oem_certificate_proxy.h",
335                "oem_certificate_stub.h"
336              ],
337              "header_base": "//drivers/peripheral/clearplay/interfaces/include/drm/v1_0"
338          }
339        },
340        {
341          "type":"so",
342          "name": "//drivers/peripheral/clearplay/interfaces:libclearplay_driver",
343            "header": {
344              "header_files": [],
345              "header_base": "//drivers/peripheral/clearplay/interfaces/include/drm/v1_0"
346          }
347        }
348      ]
349    }
350  }
351}
352```
353### Component Compilation Entry Configuration
354
355The following uses RK3568 as an example. The entry configuration file is **//productdefine/common/inherit/chipset_common.json**.
356
357```
358{
359  "component": "drivers_peripheral_clearplay",
360  "features": []
361}
362```
363
364### Service Code Compilation
365
366This process is similar to the compilation of system components.
367`./build.sh --product-name rk3568 --ccache --build-target drivers_peripheral_clearplay`
368The binary files generated after compilation are as follows:
369//ohos/out/rk3568/hdf/drivers_peripheral_clearplay/libclearplay_driver.z.so
370//ohos/out/rk3568/hdf/drivers_peripheral_clearplay/libmedia_key_system_factory_clearplay_service_1.0.z.so
371
372## DRM Plugin Service Configuration
373
374### hcs Configuration
375
376The following uses RK3568 as an example. Add the driver service configuration to **vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs**.
377
378```
379clearplay :: host {
380    hostName = "clearplay_host";   // Process name.
381    priority = 50;
382    uid = ""; // uid of the user-mode process. It is left empty by default. If you do not set the value, this parameter will be set to the value of hostName, which indicates a common user.
383    gid = ""; // gid of the user-mode process. It is left empty by default. If you do not set the value, this parameter will be set to the value of hostName, which indicates a common user group.
384    caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"]; // Linux capabilities of the user-mode process. It is left empty by default. Set this parameter based on service requirements.
385    clearplay_device :: device {
386        device0 :: deviceNode {
387            policy = 2;
388            priority = 100;
389            moduleName = "libclearplay_driver.z.so";  // Driver loading entry.
390            serviceName = "clearplay_service";        // Service name.
391        }
392    }
393}
394```
395
396### Host User and Group Configuration
397
398For the new host node in hcs, you must configure the uid and gid of the corresponding process.
399
400The **passwd** file is a system user configuration file that stores basic information about all users in the system. The following is an example:
401
402```
403//base/startup/init/services/etc/passwd
404clearplay_host:x:1089:1089:::/bin/false
405```
406
407In **//base/startup/init/services/etc/passwd**, each line of user information is divided into 7 fields, separated by colons (:). The meaning of each field is as follows:
408
409Username: Password: uid: gid: Description: Home directory: Default shell
410
411The **group** file is the user group configuration file that stores information about all user groups. The following is an example:
412
413```
414base/startup/init/services/etc/group
415clearplay_host:x:1089:
416```
417
418In **base/startup/init/services/etc/group**, each line indicates a user group. The user group is divided into four fields, separated by colons (:). The meaning of each field is as follows:
419
420Group name: Password: gid: List of users in the user group
421
422**NOTE**
423
424- **clearplay_host** in **passwd** corresponds to **uid** in **device_info.hcs**. If **uid** in **device_info.hcs** is not specified, the default value **hostName** is used.
425- **clearplay_host** in **group** corresponds to **gid** in **device_info.hcs**. If **gid** in **device_info.hcs** is not specified, the default value **hostName** is used.
426
427### Dynamic Loading
428
429To reduce RAM memory usage, the DRM framework supports dynamic loading of DRM plugins. After the DRM framework calls the plugin, it should promptly unload the plugin to release the occupied RAM memory. The plugin must modify its service startup properties to configure itself as a lazy loading service and add itself to the lazy loading list configuration file for the DRM framework on the device. The HDI service provides dynamic loading capabilities, which are not loaded by default during system startup but can be loaded dynamically. Here is an example:
430
431Set **preload** to **2** in **device_info.hcs**.
432
433```
434clearplay :: host {
435    hostName = "clearplay_host";
436    priority = 50;
437    clearplay_device :: device {
438        device0 :: deviceNode {
439            policy = 2;
440            priority = 100;
441            preload = 2; // If preload is set to 2, the system does not load the file during startup by default. You can manually load the file later.
442            moduleName = "libclearplay_driver.z.so";
443            serviceName = "clearplay_service";
444        }
445    }
446}
447```
448The **/etc/drm/drm_plugin_lazyloding.cfg** file on the device is the lazy loading list configuration file of the DRM framework. The file is in the format of key-value pairs, where the solution name of the DRM plugin is the key and the service name of the DRM solution is the value.
449```
450{
451    "plugin_services": {
452        "lazy_load_service": [
453            "com.clearplay.drm:clearplay_service"
454        ]
455    }
456}
457```
458
459## Adding SELinux Permissions
460
461SELinux is used to restrict resources that can be accessed by service processes. The following provides the basic SELinux configuration. Add required rules based on services.
462
463In the following example, **clearplay_host** indicates the value of **hostName** in hcs, and **clearplay_service** indicates the service name.
464
465//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/adapter/public/hdf_service_contexts
466`clearplay_service                             u:object_r:hdf_clearplay_service:s0`
467
468//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/adapter/public/hdf_service.te
469`type hdf_clearplay_service, hdf_service_attr;`
470
471//base/security/selinux_adapter/sepolicy/ohos_policy/startup/init/public/chipset_init.te
472`allow init clearplay_host:process { rlimitinh siginh transition };`
473
474//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/peripheral/clearplay/vendor/hdf_devmgr.te
475```
476allow hdf_devmgr clearplay_host:binder { call transfer };
477allow hdf_devmgr clearplay_host:dir { search };
478allow hdf_devmgr clearplay_host:file { open read };
479allow hdf_devmgr clearplay_host:process { getattr };
480```
481
482//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/adapter/public/type.te
483`type clearplay_host, hdfdomain, domain;`
484
485//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/peripheral/clearplay/vendor/clearplay_host.te (Create this directory.)
486```
487allow clearplay_host chip_prod_file:dir { search };
488allow clearplay_host dev_console_file:chr_file { read write };
489allow clearplay_host dev_hdf_kevent:chr_file { open read write ioctl getattr };
490allow clearplay_host dev_unix_socket:dir { search };
491allow clearplay_host hdf_device_manager:hdf_devmgr_class { get };
492allow clearplay_host hdf_devmgr:binder { call transfer };
493allow clearplay_host hdf_clearplay_service:hdf_devmgr_class { add };
494allow clearplay_host hilog_param:file { open read map };
495allow clearplay_host musl_param:file { open read map };
496allow clearplay_host sa_device_service_manager:samgr_class { get };
497allow clearplay_host samgr:binder { call };
498allow clearplay_host sh:binder { call };
499allow clearplay_host vendor_etc_file:dir { open read getattr search };
500allow clearplay_host vendor_etc_file:file { open read getattr };
501allowxperm clearplay_host dev_hdf_kevent:chr_file ioctl { 0x6202 0x6203 };
502```
503