Android DRM框架分析
- 1. DRM框架
- 2.DRM架构
- 3.DRM插件
- 4. 实现
- 5.DRM插件详情
- 6.MediaDrm
- 7.MediaCrypto
- 8.参考链接
1. DRM框架
Android DRM框架全称Android数字版权管理框架, DRM插件必须实现DRM框架提供的接口。Android DRM框架有很好的扩展性,支持应用根据与受版权保护的内容关联的许可限制条件来管理这些内容。DRM框架支持多种DRM方案,设备具体支持哪些DRM方案由设备制造商决定。
DRM 框架为受保护和不受保护的内容提供了一致的操作模式。DRM 方案可以定义复杂的许可元数据使用模型。DRM 框架提供了 DRM 内容与许可之间的关联,并处理权限管理。这样可以将媒体播放器从受 DRM 保护或不受保护的内容中提取出来。
MediaDrm 提供了获取用于解密受保护的媒体流的密钥。
为保证内容的广泛覆盖面,Android 开发者和数字内容发布者需要在整个 Android 生态系统中实现受支持的一致的 DRM。为了让这类数字内容适用于 Android 设备,并确保至少有一个一致的 DRM 可用于所有设备,Google 会在兼容的 Android 设备上提供无需支付许可费用的 DRM。DRM 插件会与 Android DRM 框架集成在一起,并可使用受硬件支持的保护功能来确保付费内容和用户凭据的安全。
DRM 插件提供的内容保护功能取决于底层硬件平台的安全和内容保护功能。设备的硬件功能应包括硬件安全启动,可建立加密密钥的安全和保护功能的信任链。设备的内容保护功能应包括设备内加密帧的保护和通过可信输出保护机制实现的内容保护。并非所有硬件平台都支持上述所有的安全和内容保护功能。安全功能绝不会在堆栈的单个位置实现,而是依赖于硬件、软件和服务的集成。将硬件安全功能、可信启动机制以及用于处理安全功能的隔离安全操作系统组合使用是保障安全设备的关键。
2.DRM架构
DRM框架与实现无关,DRM插件有自己特定的实现。DRM框架包括以下可执行的简单API:处理复杂的DRM操作,获取许可,配置设备,将DRM内容与其许可相关联, 以及最终解密DRM内容。
Android DRM是在以下两个架构层中实现的:
- DRM frameowork API:通过Android应用框架提供给应用。
- 本机代码DRM框架:为DRM插件(代理)提供接口,以便处理各种DRM方案的版权管理和解密操作。
如需了解详情,请参阅MediaDrm 和MediaCrypto。
3.DRM插件
系统启动时候,DRM框架会扫描HAL实例/服务(如.rc
文件所述),并通过HIDL注册表发现插件。媒体DRM服务器(mediadrmserver
)创建CryptoHal
和DrmHal
对象。然后,CryptoHal
和DrmHal
使用供应商专用实现来调用发现的插件。
插件应实现绑定式HAL。绑定式HAL使用 HAL 接口定义语言 (HIDL), HIDL支持在不重新构建HAL的情况下替换框架。
插件有供应商或SOC制造商构建,放置在设备的/vendor
分区中。Android8.0或更高版本的设备必须支持HIDL语言编写的绑定式HAL。
4. 实现
要通过插件实现新的DRM框架API,请执行以下操作:
- 将插件服务添加到设备的构建文件中。
- 更新设备清单。
- 添加 SELinux 权限。
- 在 /vendor 下创建 .rc 文件。
- 实现插件。
新的 API 在 iDrmPlugin.hal 和 iCryptoPlugin.hal 中定义。
PLATFORM_ROOT/hardware/interfaces/drm/VERSION/
将插件服务添加到设备的构建文件中
例如,要添加接口 1.2 支持,VENDOR DEVICE/device.mk 文件必须包含 android.hardware.drm@1.2-service.* 软件包:
PRODUCT_PACKAGES += \
android.hardware.drm@1.0-impl \
android.hardware.drm@1.0-service \
android.hardware.drm@1.2-service.clearkey \
android.hardware.drm@1.2-service.widevine
更新设备清单
设备的 vendor manifest.xml 文件必须包含以下条目:
<hal format="hidl">
<name>android.hardware.drm</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>ICryptoFactory</name>
<instance>default</instance>
</interface>
<interface>
<name>IDrmFactory</name>
<instance>default</instance>
</interface>
<fqname>@1.2::ICryptoFactory/clearkey</fqname>
<fqname>@1.2::IDrmFactory/clearkey</fqname>
<fqname>@1.2::ICryptoFactory/widevine</fqname>
<fqname>@1.2::IDrmFactory/widevine</fqname>
</hal>
添加 SELinux 权限
- 添加到 VENDOR DEVICE/sepolicy/vendor/file.te
type mediadrm_vendor_data_file, file_type, data_file_type;
- 添加到 VENDOR DEVICE/sepolicy/vendor/file_contexts
/vendor/bin/hw/android\.hardware\.drm@1\.2-service\.clearkey
u:object_r:hal_drm_clearkey_exec:s0
/data/vendor/mediadrm(/.*)? u:object_r:mediadrm_vendor_data_file:s0
- 添加到 device/sepolicy/vendor/hal_drm_clearkey.te
allow hal_drm_clearkey mediadrm_vendor_data_file:dir create_dir_perms;
allow hal_drm_clearkey mediadrm_vendor_data_file:file create_file_perms;
在 /vendor 下创建 .rc
文件
.rc
文件指定服务启动时要采取的操作。
实现插件
- 在插件服务的 service.cpp 中实现 main() 入口点。
- 实现 CryptoFactory 和 DrmFactory。
- 在插件中实现新的 API。
5.DRM插件详情
DRM 插件供应商实现了 DrmFactory
、CryptoFactory
和 DRM 插件。
DrmFactory
DrmHal
类会搜索已注册的 DRM 插件服务,并通过 DrmFactory
类构建支持给定加密方案的相应插件。
Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>uuid);
确定插件工厂能否构建支持给定加密方案(由 UUID 指定)的 DRM 插件。
Return<bool> isContentTypeSupported(const hidl_string &mimeType);
确定插件工厂能否构建支持给定媒体容器格式(由 mimeType 指定)的 DRM 插件。
Return<void> createPlugin(const hidl_array<uint8_t, 16>uuid,
const hidl_string& appPackageName, createPlugin_cb _hidl_cb);
为UUID指定的加密方案构建DRM插件。
CryptoFactoryCryptoHal
类会搜索已注册的 DRM 插件服务,并通过 CryptoFactory
类构建支持给定加密方案的相应插件。
Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>uuid);
确定加密工厂能否构建支持给定加密方案(由 UUID 指定)的加密插件。
Return<void> createPlugin(const hidl_array<uint8_t, 16>uuid,
const hidl_vec<uint8_t>initData, createPlugin_cb _hidl_cb)
确定插件工厂能否构建支持给定加密方案(由 UUID 指定)的加密插件。
DRM 插件
API 在 hardware/interfaces/drm/VERSION /IDrmPlugin.hal
中定义。构建完成后,可以在 out/Soong 中找到相应的 IDrmPlugin.h
文件。
6.MediaDrm
MediaDrm可以用于获取Keys,这些Keys可以用于解密受保护的媒体流,结合MediaCrypto
。MediaDrm APIs被设计以支持ISO/IEC 23001-7:通用加密标准,同时可能也用于实现其他加密方案。
加密的内容存放在加密服务器的内容库中。加密的内容通过流化或下载的方式从内容服务器传送到客户端设备。用于查看内容的Licenses从License服务器获取。
使用key请求来从license服务器获取Keys。key response传递到客户端app,该response将发起MediaDrm API的调用。
一个Provisioning服务器可能会被需要,用于向设备分发设备唯一凭据。
强制要求依赖于同步播放内容的设备数量,这些要求可以通过密钥更新或使用安全停止方法来完成。下面的序列图展示了后台播放加密内容涉及的对象之间的交互:
app首先构造MediaExtractor
和MediaCodec
对象。它通常从内容中的元数据访问由UUID标识的DRM方案,并使用此UUID构造MediaDrm对象的实例,该实例能够支持内容所需的DRM方案。加密方案分配了16字节的UUID。isCryptoSchemeSupported(UUID)
方法能够用于查询一个给定的DRM方案是否被设备所支持。
app调用openSession()
用于生成一个会话Id,这个id将用于后续交互中的唯一会话Id。app下一步将使用MediaDrm对象来获取一个key请求的message并发送到license服务器,然后提供服务端的响应给到MediaDrm对象。
一但app有了会话Id,它就可以UUID和会话Id构造一个MediaCrypto对象。MediaCrypto对象通过MediaCodec#configure
方法完成注册,从而使codec具备解密内容的能力。
当app构造完成了MediaExtractor
、MediaCodec
和MediaCrypto
对象,它继续从extractor中提取样本并将它们放入解码对列中。对于加密的内容,extractor返回的样本保持加密状态,只有当样本被传递到解码器时,它们才被解密。
MediaDrm中的方法抛出MediaDrm.MediaDrmStateException
异常,当一个DRM插件或安全硬件中发生了不可恢复的故障时。MediaDrm.MediaDrmStateException
继承自IllegalStateException
,添加了与异常相关联的开发人员可读的诊断信息字符串。
当MediaDrm对象处于激活状态时,mediaserver处理crash或者重启事件中, MediaDrm方法可能抛出MediaDrmResetException
。为了恢复,app必须释放MediaDrm对象,然后重新创建一个新的MediaDrm对象。
由于MediaDrmResetException
和MediaDrm.MediaDrmStateException
都继承自IllegalStateException
, 它们应该在IllegalStateException
之前捕获异常代码块。注册这些事件监听是通过调用setOnEventListener(MediaDrm.OnEventListener)
完成的。
回调
应用程序应该注册信息性事件,以便在回放或流式传输期间通知密钥状态更新。为了接收与此listener关联的相应回调,应用程序需要在自己的循环线程中创建MediaDrm对象(UI线程默认情况下有一个Looper在运行)。
7.MediaCrypto
MediaCrypto类可以用于联合MediaCodec
使用用于解码加密的媒体数据。Crypto方案被分配16byte的UUIDs,isCryptoSchemeSupported(UUID)
方法可以用于查询一个给定的DRM方案是否被设备所支持。