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