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