相关原创文章:
数字版权管理DRM
DRM在Android中
DRM-widevine 总结
DRM-Playready总结
ExoPlayer+Shaka-packager播放自制DRM视频
1. Android HIDL
HIDL 读作 hide-l,全称是 Hardware Interface Definition Language。它在 Android Project Treble 中被起草,在 Android 8.0 中被全面使用。其诞生目的是,框架可以在无需重新构建 HAL 的情况下进行替换。HAL将由供应商或SOC 制造商构建,放置在设备的 /vendor
分区中,这样一来,框架就可以在其自己的分区中通过 OTA 进行替换,而无需重新编译 HAL。
HAL(Hardware Abstract Layer)硬件抽象层。主要目的在于将硬件抽象化。硬件抽象化可以隐藏特定平台的硬件接口细节,为上面一层提供固定统一的接口,使其具有硬件无关性。HAL层位于kernel和framework层之间,各厂商在Android的硬件抽象层实现特定硬件的操作细节,并编译成so库,以库的形式提供给用户使用。
关于Android HAL的其他详细内容,有许多资料可以查阅。
- HIDL
- HAL
在AndroidO版本以前,DRM架构是直接通过dlopen调用DRM插件,而不是使用HAL的方式,相关代码在:frameworks/av/drm/libmediadrm
。在AndroidO版本后也兼容之前的非HAL的插件,除了上图的DrmManager方式外,也可以通过DrmHal调用drm hal1.0的passthrough方式来调用legacy plugins,详细代码:/hardware/interfaces/drm/1.0/default
2. DRM HAL
DRM框架在AndroidO开始后引入了HAL的概念。直至当前的AndroidQ发展到了HAL1.2版本。下面基于AndroidQ版本来讲述。详细的实现方式可以参照DRM
HAL的加载入口frameworks/av/drm/libmediadrm/DrmHal.cpp
Vector<sp<IDrmFactory>> DrmHal::makeDrmFactories() {
Vector<sp<IDrmFactory>> factories;
auto manager = hardware::defaultServiceManager1_2();
if (manager != NULL) {
manager->listManifestByInterface(drm::V1_0::IDrmFactory::descriptor,
[&factories](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
auto factory = drm::V1_0::IDrmFactory::getService(instance);
if (factory != NULL) {
factories.push_back(factory);
}
}
}
);
manager->listManifestByInterface(drm::V1_1::IDrmFactory::descriptor,
[&factories](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
auto factory = drm::V1_1::IDrmFactory::getService(instance);
if (factory != NULL) {
factories.push_back(factory);
}
}
}
);
manager->listByInterface(drm::V1_2::IDrmFactory::descriptor,
[&factories](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
auto factory = drm::V1_2::IDrmFactory::getService(instance);
if (factory != NULL) {
factories.push_back(factory);
}
}
}
);
}
if (factories.size() == 0) {
// must be in passthrough mode, load the default passthrough service
auto passthrough = IDrmFactory::getService();
if (passthrough != NULL) {
ALOGI("makeDrmFactories: using default passthrough drm instance");
factories.push_back(passthrough);
} else {
ALOGE("Failed to find any drm factories");
}
}
return factories;
}
HIDL的相关代码位于:android/hardware/interfaces/drm
2.1 passthrough
passthrough直通模式: HIDL 的一种模式,使用这种模式时,服务器是共享库,由客户端进行 dlopen
处理。在直通模式下,客户端和服务器是相同的进程,但代码库不同。此模式仅用于将旧版代码库并入 HIDL 模型。
要将运行早期版本的 Android 的设备更新为使用 Android O,可以将惯用的(和旧版)HAL 封装在一个新 HIDL 接口中,该接口将在绑定式模式和同进程(直通)模式提供 HAL。这种封装对于 HAL 和 Android 框架来说都是透明的。
详细代码,可参照/hardware/interfaces/drm/1.0/default
。
2.2 HAL 1.0
AndroidO版本开始,使用DRM HAL方式来加载DRM插件,AndroidO的DRM HAL对应的版本为HAL 1.0。对应的widevine版本是v13。
2.3 HAL 1.1
AndroidP版本的DRM HAL为HAL1.1。对应的widevine版本是v14。此版本继承了HAL1.0,同时修改了一些接口。
2.3 HAL 1.2
AndroidQ版本的DRM HAL为HAL1.2,并且增加了LAZY HAL概念,以支持低性能的Android设备。对应的widevine版本是v15。
- 1.2 HAL 继承HAL1.0, HAL1.1,修改了一些接口。
- LAZY HAL
androidP已引入lazy hal概念,但并没有在drm hal中使用,drm lazy hal在AndroidQ上开始应用。
Lazy hal可以使hal服务在使用的时候开启,而当不使用时,所有client都注销服务时,就关闭hal服务,因此,这个可以有效地提高Android设备的性能和降低功耗。
在DRM 插件对接时,需要在每个插件中编写相应的Lazy hal service。
3. DRM HAL 实现
以AndroidQ DRM HAL1.2为例说明:
相关代码:
- libmediadrm:
frameworks/av/drm/libmediadrm
- mediadrmservice:
frameworks/av/services/mediadrm
- drm hidl:
hardware/interfaces/drm/1.2
- clearkey plugin:
frameworks/av/drm/mediadrm/plugins/clearkey
- widevine plugin: …(厂商自行移植)
- …
在目录hardware/interfaces/drm/1.2
根据HIDL语法实现相关的HIDL文件,然后编译时通过hidl_gen
工具生成相关的的头文件及接口源码以供具体的插件调用。
生成路径:out/soong/.intermediates/hardware/interfaces/drm/1.2/
├── android.hardware.drm@1.2
├── android.hardware.drm@1.2_genc++
└── android.hardware.drm@1.2_genc++_headers
其中headers就是生成相应的头文件android.hardware.drm@1.2_genc++_headers/gen/android/hardware/drm/1.2
:
├── BnHwCryptoFactory.h
├── BnHwCryptoPlugin.h
├── BnHwDrmFactory.h
├── BnHwDrmPlugin.h
├── BnHwDrmPluginListener.h
├── BpHwCryptoFactory.h
├── BpHwCryptoPlugin.h
├── BpHwDrmFactory.h
├── BpHwDrmPlugin.h
├── BpHwDrmPluginListener.h
├── BsCryptoFactory.h
├── BsCryptoPlugin.h
├── BsDrmFactory.h
├── BsDrmPlugin.h
├── BsDrmPluginListener.h
├── hwtypes.h
├── ICryptoFactory.h
├── ICryptoFactory.h.d
├── ICryptoPlugin.h
├── IDrmFactory.h
├── IDrmPlugin.h
├── IDrmPluginListener.h
├── IHwCryptoFactory.h
├── IHwCryptoPlugin.h
├── IHwDrmFactory.h
├── IHwDrmPlugin.h
├── IHwDrmPluginListener.h
└── types.h
对于hidl的serviec manager调用,在system/libhidl/transport
4. 插件的实现
在系统启动时,DRM 框架会扫描 HAL 实例/服务(如 .rc
文件中所述),并通过 HIDL 注册表发现插件。媒体 DRM 服务器 (mediadrmserver
) 创建 CryptoHal
和 DrmHal
对象。 然后,CryptoHal
和 DrmHal
使用供应商专用实现来调用发现的插件。
插件应实现绑定式 HAL。绑定式 HAL 使用 HAL 接口定义语言 (HIDL),HIDL 支持在不重新构建 HAL 的情况下替换框架。
插件由供应商或 SOC 制造商构建,放置在设备的 /vendor
分区中。所有在上市时即搭载了 Android 8.0 或更高版本的设备都必须支持使用 HIDL 语言编写的绑定式 HAL。
大致步骤:
- 在插件服务的
service.cpp
中实现main()
入口点。 - 实现
CryptoFactory
和DrmFactory
。 - 实现 DRM 插件。
- 新的 API 在
IDrmPlugin.hal
和ICryptoPlugin.hal
中定义。 - 在插件中实现新的 API。
DrmHal
类会搜索已注册的 DRM 插件服务,并通过 DrmFactory
类构建支持给定加密方案的相应插件。
CryptoHal
类会搜索已注册的 DRM 插件服务,并通过 CryptoFactory
类构建支持给定加密方案的相应插件。
博文为ganqiuye原创,转载请附上原文出处链接和本声明。