1# DRM解决方案开发指导 2 3DRM 解决方案插件实现 DRM HDI 接口(链接),DRM Kit的DRM框架将通过HDI接口加载DRM解决方案插件。 4 5插件由DRM解决方案集成方开发,放置在设备的 /vendor 分区中。 6 7OpenHarmony HDI 插件驱动服务开发流程参考[HDF驱动开发流程](../../../device-dev/driver/driver-hdf-manage.md),DRM HDI API 的 IDL 在 ohos/drivers/interface/drm/v1_0 目录中定义,其中 v1_0 对应不同版本的 HDI API 版本号,需根据实际调用的 HDI API 版本进行修改。 8 9DRM HDI API 的 IDL 构建完成后,可以在`//ohos/out/产品型号/gen/drivers/interface/drm/v1_0/`中找到生成的相应版本的 .h 和 .cpp文件。 10实现 DRM 解决方案插件的步骤如下(以clearplay为例): 11 121. [开发插件](#开发插件) 13 - 模块添加 14 - 驱动入口实现 15 - HDI接口实现 16 - 编译配置 17 - 部件配置 18 - 部件编译入口配置 19 - 服务代码编译 20 212. [DRM解决方案插件服务配置](#drm解决方案插件服务配置) 22 - hcs配置 23 - host用户与组配置 24 - 动态加载 25 263. [添加SELinux权限](#添加selinux权限) 27 28## 开发插件 29 30### 模块添加 31 32创建插件目录,参考如下: 33``` 34//drivers/peripheral/clearplay 35. 36├── BUILD.gn # 模块编译BUILD.gn。 37├── bundle.json # 部件配置。 38├── hdi_service # DRM解决方案HDI服务代码。 39│ ├── BUILD.gn # DRM解决方案HDI服务代码编译BUILD.gn。 40│ ├── common # DRM解决方案HDI服务依赖的工具类代码,包含json解析、base64编解码。 41│ ├── include # RM解决方案HDI服务实现头文件。 42│ └── src # DRM解决方案HDI服务实现代码。 43├── interfaces # DRM解决方案HDI服务能力接口。 44│ ├── BUILD.gn # DRM解决方案HDI服务能力接口编译BUILD.gn。 45│ ├── include # DRM解决方案HDI服务能力接口文件。 46│ └── src # DRM解决方案HDI服务能力接口实现。 47└── README_zh.md # DRM解决方案HDI服务组件说明。 48``` 49 50### 驱动入口实现 51 52驱动入口实现可以参考`//ohos/out/产品型号/gen/drivers/interface/drm/v1_0/media_key_system_factory_driver.cpp`,需要驱动入口实现中修改以下几点,并手动配置编译: 53 54``` 55using namespace OHOS::HDI::Drm::V1_0; // 1. 本文中 V1_0 为 HDI API 版本号,需根据不同版本进行变更。 56 57struct HdfMediaKeySystemFactoryHost { 58 struct IDeviceIoService ioService; 59 OHOS::sptr<OHOS::IRemoteObject> stub; 60}; 61static int HdfMediaKeySystemFactoryDriverBind(struct HdfDeviceObject *deviceObject) 62{ 63 auto *hdfMediaKeySystemFactoryHost = new (std::nothrow) HdfMediaKeySystemFactoryHost; 64 if (hdfMediaKeySystemFactoryHost == nullptr) { 65 HDF_LOGE("%{public}s: failed to create create HdfMediaKeySystemFactoryHost object", __func__); 66 return HDF_FAILURE; 67 } 68 int ret = HdfDeviceObjectSetInterfaceDesc(deviceObject, "ohos.hdi.drm.v1_0.IMediaKeySystemFactory"); // 2. 服务绑定接口描述符,便于DRM框架服务通过接口描述符获取到DRM解决方案HDI服务,根据不同的HDI API版本号调整。 69 if (ret != HDF_SUCCESS) { 70 HDF_LOGE("%{public}s: failed to HdfDeviceObjectSetInterfaceDesc", __func__); 71 } 72 73 hdfMediaKeySystemFactoryHost->ioService.Dispatch = MediaKeySystemFactoryDriverDispatch; 74 hdfMediaKeySystemFactoryHost->ioService.Open = NULL; 75 hdfMediaKeySystemFactoryHost->ioService.Release = NULL; 76 77 auto serviceImpl = OHOS::HDI::Drm::V1_0::IMediaKeySystemFactory::Get("clearplay_service", true); // 3. 获取DRM解决方案HDI服务实例。 78 if (serviceImpl == nullptr) { 79 HDF_LOGE("%{public}s: failed to get of implement service", __func__); 80 delete hdfMediaKeySystemFactoryHost; 81 return HDF_FAILURE; 82 } 83 84 hdfMediaKeySystemFactoryHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 85 OHOS::HDI::Drm::V1_0::IMediaKeySystemFactory::GetDescriptor()); // 4. 获取DRM解决方案HDI服务实现对应的Stub对象。 86 if (hdfMediaKeySystemFactoryHost->stub == nullptr) { 87 HDF_LOGE("%{public}s: failed to get stub object", __func__); 88 delete hdfMediaKeySystemFactoryHost; 89 return HDF_FAILURE; 90 } 91 92 deviceObject->service = &hdfMediaKeySystemFactoryHost->ioService; 93 return HDF_SUCCESS; 94} 95 96static int32_t MediaKeySystemFactoryDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, 97 struct HdfSBuf *reply) 98{ 99 auto *hdfMediaKeySystemFactoryHost = 100 CONTAINER_OF(client->device->service, struct HdfMediaKeySystemFactoryHost, ioService); 101 102 OHOS::MessageParcel *dataParcel = nullptr; 103 OHOS::MessageParcel *replyParcel = nullptr; 104 OHOS::MessageOption option; 105 106 if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) { 107 HDF_LOGE("%{public}s: invalid data sbuf object to dispatch", __func__); 108 return HDF_ERR_INVALID_PARAM; 109 } 110 if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) { 111 HDF_LOGE("%{public}s: invalid reply sbuf object to dispatch", __func__); 112 return HDF_ERR_INVALID_PARAM; 113 } 114 115 return hdfMediaKeySystemFactoryHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option); 116} 117``` 118 119### HDI接口实现 120 121实现可以参考`//ohos/out/产品型号/gen/drivers/interface/drm/v1_0/`中自动生成的.cpp文件,可以按照业务需要进行定制化修改或新增文件,如`media_key_system_factory_service.cpp`: 122 123``` 124extern "C" IMediaKeySystemFactory *MediaKeySystemFactoryImplGetInstance(void) 125{ 126 // 请新增实现。 127 return new (std::nothrow) MediaKeySystemFactoryService(); 128} 129 130int32_t MediaKeySystemFactoryService::IsMediaKeySystemSupported(const std::string& name, const std::string& mimeType, 131 OHOS::HDI::Drm::V1_0::ContentProtectionLevel level, bool& isSupported) 132{ 133 // 请新增实现。 134 return HDF_SUCCESS; 135} 136 137int32_t MediaKeySystemFactoryService::CreateMediaKeySystem(sptr<OHOS::HDI::Drm::V1_0::IMediaKeySystem>& mediaKeySystem) 138{ 139 // 请新增实现。 140 return HDF_SUCCESS; 141} 142 143int32_t MediaKeySystemFactoryService::GetMediaKeySystemDescription(std::string& name, std::string& uuid) 144{ 145 // 请新增实现。 146 return HDF_SUCCESS; 147} 148 149``` 150 151### 编译配置 152//drivers/peripheral/clearplay/BUILD.gn 153 154``` 155if (defined(ohos_lite)) { 156 group("clearplay_entry") { 157 deps = [] 158 } 159} else { 160 group("clearplay_entry") { 161 deps = [ 162 "./hdi_service:hdf_clearplay_service", 163 "./interfaces:hdf_clearplay_interfaces", 164 ] 165 } 166} 167``` 168 169//drivers/peripheral/clearplay/hdi_service/BUILD.gn 170``` 171import("//build/ohos.gni") 172 173ohos_shared_library("libmedia_key_system_factory_clearplay_service_1.0") { 174 include_dirs = [ 175 "./include", 176 "./include/drm/v1_0", 177 "./include/drm", 178 "./../interfaces/include", 179 "./../interfaces/include/drm/v1_0", 180 "./../interfaces/include/drm", 181 "./common", 182 ] 183 sources = [ 184 "./common/base64_utils.cpp", 185 "./src/media_decrypt_module_service.cpp", 186 "./src/media_key_session_callback_service.cpp", 187 "./src/media_key_session_service.cpp", 188 "./src/media_key_system_callback_service.cpp", 189 "./src/media_key_system_factory_service.cpp", 190 "./src/media_key_system_service.cpp", 191 "./src/oem_certificate_service.cpp", 192 ] 193 194 deps = [ ] 195 196 cflags = [ 197 "-Wall", 198 "-Wextra", 199 "-Werror", 200 "-fsigned-char", 201 "-fno-common", 202 "-fno-strict-aliasing", 203 ] 204 205 external_deps = [ 206 "c_utils:utils", 207 "hdf_core:libhdf_utils", 208 "hilog:libhilog", 209 "ipc:ipc_single", 210 ] 211 212 install_images = [ chipset_base_dir ] 213 subsystem_name = "hdf" 214 part_name = "drivers_peripheral_clearplay" 215} 216 217group("hdf_clearplay_service") { 218 deps = [ ":libmedia_key_system_factory_clearplay_service_1.0" ] 219} 220``` 221 222//drivers/peripheral/clearplay/interfaces/BUILD.gn 223 224``` 225import("//build/ohos.gni") 226 227ohos_shared_library("libclearplay_driver") { 228 include_dirs = [ 229 "./include", 230 "./include/drm", 231 ] 232 233 public_configs = [ ":clearplay_imp_external_library_config" ] 234 sources = [ "./src/media_key_system_factory_driver.cpp" ] 235 236 external_deps = [ 237 "c_utils:utils", 238 "drivers_interface_drm:libdrm_stub_1.0", 239 "hdf_core:libhdf_host", 240 "hdf_core:libhdf_ipc_adapter", 241 "hdf_core:libhdf_utils", 242 "hdf_core:libhdi", 243 "hilog:libhilog", 244 "ipc:ipc_single", 245 ] 246 cflags = [ 247 "-Wall", 248 "-Wextra", 249 "-Werror", 250 "-fsigned-char", 251 "-fno-common", 252 "-fno-strict-aliasing", 253 ] 254 shlib_type = "hdi" 255 install_images = [ chipset_base_dir ] 256 subsystem_name = "hdf" 257 part_name = "drivers_peripheral_clearplay" 258} 259 260config("clearplay_imp_external_library_config") { 261 include_dirs = 262 [ "//drivers/peripheral/clearplay/interfaces/include/drm/v1_0" ] 263} 264group("hdf_clearplay_interfaces") { 265 deps = [ ":libclearplay_driver" ] 266} 267``` 268 269### 部件配置 270 271新建drivers/peripheral/clearplay/build.json用于定义新增的drivers_peripheral_clearplay部件: 272 273``` 274{ 275 "name": "@ohos/drivers_peripheral_clearplay", 276 "description": "clearplay drm device driver", 277 "version": "4.0", 278 "license": "Apache License 2.0", 279 "publishAs": "code-segment", 280 "segment": { 281 "destPath": "drivers/peripheral/clearplay" 282 }, 283 "dirs": {}, 284 "scripts": {}, 285 "component": { 286 "name": "drivers_peripheral_clearplay", 287 "subsystem": "hdf", 288 "syscap": [], 289 "adapted_system_type": ["standard"], 290 "rom": "", 291 "ram": "", 292 "deps": { 293 "components": [ 294 "bounds_checking_function", 295 "drivers_interface_drm", 296 "c_utils", 297 "hdf_core", 298 "hilog", 299 "ipc" 300 ], 301 "third_party": [] 302 }, 303 "build": { 304 "sub_component": [ 305 "//drivers/peripheral/clearplay:clearplay_entry" 306 ], 307 "inner_kits": [ 308 { 309 "type":"so", 310 "name": "//drivers/peripheral/clearplay/hdi_service:libmedia_key_system_factory_clearplay_service_1.0", 311 "header": { 312 "header_files": [ 313 "imedia_decrypt_module.h", 314 "imedia_key_session_callback.h", 315 "imedia_key_session.h", 316 "imedia_key_system_callback.h", 317 "imedia_key_system_factory.h", 318 "imedia_key_system.h", 319 "ioem_certificate.h", 320 "media_decrypt_module_proxy.h", 321 "media_decrypt_module_stub.h", 322 "media_key_session_callback_proxy.h", 323 "media_key_session_callback_stub.h", 324 "media_key_session_proxy.h", 325 "media_key_session_stub.h", 326 "media_key_system_callback_proxy.h", 327 "media_key_system_callback_stub.h", 328 "media_key_system_factory_proxy.h", 329 "media_key_system_factory_stub.h", 330 "media_key_system_proxy.h", 331 "media_key_system_stub.h", 332 "media_key_system_types.h", 333 "oem_certificate_proxy.h", 334 "oem_certificate_stub.h" 335 ], 336 "header_base": "//drivers/peripheral/clearplay/interfaces/include/drm/v1_0" 337 } 338 }, 339 { 340 "type":"so", 341 "name": "//drivers/peripheral/clearplay/interfaces:libclearplay_driver", 342 "header": { 343 "header_files": [], 344 "header_base": "//drivers/peripheral/clearplay/interfaces/include/drm/v1_0" 345 } 346 } 347 ] 348 } 349 } 350} 351``` 352### 部件编译入口配置 353 354以rk3568产品为例:`//productdefine/common/inherit/chipset_common.json` 355 356``` 357{ 358 "component": "drivers_peripheral_clearplay", 359 "features": [] 360} 361``` 362 363### 服务代码编译 364 365与编译系统部件编译类似: 366`./build.sh --product-name rk3568 --ccache --build-target drivers_peripheral_clearplay` 367编译生成的二进制文件如下: 368//ohos/out/rk3568/hdf/drivers_peripheral_clearplay/libclearplay_driver.z.so 369//ohos/out/rk3568/hdf/drivers_peripheral_clearplay/libmedia_key_system_factory_clearplay_service_1.0.z.so 370 371## DRM解决方案插件服务配置 372 373### hcs配置 374 375以rk3568产品为例,在`vendor/hihope/rk3568/hdf_config/uhdf/device_info.hcs`添加驱动服务配置 376 377``` 378clearplay :: host { 379 hostName = "clearplay_host"; // 进程名。 380 priority = 50; 381 uid = ""; // 用户态进程uid,缺省为空,会被配置为hostName的定义值,即普通用户。 382 gid = ""; // 用户态进程gid,缺省为空,会被配置为hostName的定义值,即普通用户组。 383 caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"]; // 用户态进程Linux capabilities配置,缺省为空,需要业务模块按照业务需要进行配置。 384 clearplay_device :: device { 385 device0 :: deviceNode { 386 policy = 2; 387 priority = 100; 388 moduleName = "libclearplay_driver.z.so"; // 驱动加载入口。 389 serviceName = "clearplay_service"; // 服务名称。 390 } 391 } 392} 393``` 394 395### host用户与组配置 396 397对于在hcs中新增加的host节点,需要新增配置对应进程的uid(用户ID)和gid(组ID) 398passwd文件为系统用户配置文件,存储了系统中所有用户的基本信息,这里以此为例: 399 400``` 401//base/startup/init/services/etc/passwd 402clearplay_host:x:1089:1089:::/bin/false 403``` 404 405`//base/startup/init/services/etc/passwd`中每行用户信息使用“:”作为分隔符,划分为7个字段,每个字段所表示的含义如下: 406用户名:密码:UID(用户ID):GID(组ID):描述信息:主目录:默认shell 407 408group为用户组配置文件,存储了所有用户组的信息,以下为例: 409 410``` 411base/startup/init/services/etc/group 412clearplay_host:x:1089: 413``` 414 415base/startup/init/services/etc/group中每行代表一个用户组,用户组中以“:”作为分隔符,分为4个字段,每个字段的含义如下: 416组名:密码:GID(组ID):该用户组中的用户列表 417注意: 418- passwd中clearplay_host对应device_info.hcs中的uid,若device_info.hcs中uid缺省,则默认为hostName 419- group中clearplay_host对应device_info.hcs中的gid,若device_info.hcs中gid缺省,则默认为hostName 420 421### 动态加载 422 423为节约 RAM 内存占用,DRM 框架服务支持动态加载 DRM 解决方案插件,DRM 框架服务调用完解决方案插件后,及时卸载 DRM 解决方案插件,释放 RAM 内存占用,插件需通过修改服务启动属性将自身服务配置成懒加载,并加入到设备上的 DRM 框架服务懒加载列表配置文件中;HDI服务提供动态加载能力,系统启动过程中默认不加载,支持动态加载,以下为示例: 424`device_info.hcs`配置preload为2 425``` 426clearplay :: host { 427 hostName = "clearplay_host"; 428 priority = 50; 429 clearplay_device :: device { 430 device0 :: deviceNode { 431 policy = 2; 432 priority = 100; 433 preload = 2; // 设置preload为2,则系统启动过程中默认不加载,后续可手动加载。 434 moduleName = "libclearplay_driver.z.so"; 435 serviceName = "clearplay_service"; 436 } 437 } 438} 439``` 440设备上`/etc/drm/drm_plugin_lazyloding.cfg`为 DRM 框架服务懒加载列表配置文件,键值对形式,DRM 解决方案插件解决方案名为键,DRM解决方案服务名为值: 441``` 442{ 443 "plugin_services": { 444 "lazy_load_service": [ 445 "com.clearplay.drm:clearplay_service" 446 ] 447 } 448} 449``` 450 451## 添加SELinux权限 452 453selinux用于限制服务进程可访问的资源,以下给定基础的selinux配置,在此基础上按业务添加所需规则。 454 455注意:以下示例中,clearplay_host表示hcs中的hostName值,clearplay_service表示服务名称 456//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/adapter/public/hdf_service_contexts 457`clearplay_service u:object_r:hdf_clearplay_service:s0` 458 459//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/adapter/public/hdf_service.te 460`type hdf_clearplay_service, hdf_service_attr;` 461 462//base/security/selinux_adapter/sepolicy/ohos_policy/startup/init/public/chipset_init.te 463`allow init clearplay_host:process { rlimitinh siginh transition };` 464 465//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/peripheral/clearplay/vendor/hdf_devmgr.te 466``` 467allow hdf_devmgr clearplay_host:binder { call transfer }; 468allow hdf_devmgr clearplay_host:dir { search }; 469allow hdf_devmgr clearplay_host:file { open read }; 470allow hdf_devmgr clearplay_host:process { getattr }; 471``` 472 473//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/adapter/public/type.te 474`type clearplay_host, hdfdomain, domain;` 475 476//base/security/selinux_adapter/sepolicy/ohos_policy/drivers/peripheral/clearplay/vendor/clearplay_host.te(新建此目录) 477``` 478allow clearplay_host chip_prod_file:dir { search }; 479allow clearplay_host dev_console_file:chr_file { read write }; 480allow clearplay_host dev_hdf_kevent:chr_file { open read write ioctl getattr }; 481allow clearplay_host dev_unix_socket:dir { search }; 482allow clearplay_host hdf_device_manager:hdf_devmgr_class { get }; 483allow clearplay_host hdf_devmgr:binder { call transfer }; 484allow clearplay_host hdf_clearplay_service:hdf_devmgr_class { add }; 485allow clearplay_host hilog_param:file { open read map }; 486allow clearplay_host musl_param:file { open read map }; 487allow clearplay_host sa_device_service_manager:samgr_class { get }; 488allow clearplay_host samgr:binder { call }; 489allow clearplay_host sh:binder { call }; 490allow clearplay_host vendor_etc_file:dir { open read getattr search }; 491allow clearplay_host vendor_etc_file:file { open read getattr }; 492allowxperm clearplay_host dev_hdf_kevent:chr_file ioctl { 0x6202 0x6203 }; 493```