安卓 3.0 中引入的 DRM 框架为应用开发者提供了一个统一接口,并隐藏了 DRM 操作的复杂性。在安卓 3.0 及更高版本的平台上,DRM 插件会与安卓 DRM 框架集成在一起,并可使用受硬件支持的保护功能来确保付费内容和用户凭据的安全
DRM 框架与实现无关,可在方案特定的 DRM 插件中提取特定 DRM 方案实现的详情。DRM 框架包括可执行以下操作的简单 API:处理复杂的 DRM 操作、向在线 DRM 服务注册用户和设备、从许可中提取限制信息、将 DRM 内容与其许可相关联,以及最终解密 DRM 内容。
安卓 DRM 框架在以下两个架构层中实现:
•DRM framework API:通过安卓应用框架提供给应用,并通过适用于标准应用的 Dalvik VM 运行。
•本机代码 DRM 管理器:用于实现 DRM 框架,并为 DRM 插件(代理)提供接口,以便处理各种 DRM 方案的版权管理和解密操作。
如下图所示,DRM 框架使用插件架构来支持各种 DRM 方案。DRM 管理器服务在一个独立进程中运行,以确保隔离执行 DRM 插件。从 DrmManagerClient 到 DrmManagerService 的每个 API 调用都需要使用 binder IPC 机制来跨越进程边界。DrmManagerClient 提供了 Java 编程语言实现,作为运行时应用的通用接口;此外,它还提供了 DrmManagerClient 本机实现作为本机模块的接口。DRM 框架的调用者仅访问 DrmManagerClient,无需了解每个 DRM 方案。
当 DrmManagerService 启动时,插件会自动加载。如下图所示,DRM 插件管理器会加载/取消加载所有可用插件。DRM 框架会在以下目录中查找并自动加载插件:
/system/lib/drm/plugins/native/
IDrmEngine 是一种接口,包含一组用于 DRM 用例的 API。插件开发者必须实现 IDrmEngine 中指定的接口和下方指定的监听器接口。源代码树在以下目录中提供了接口定义:
PLATFORM_ROOT/frameworks/av/drm/libdrmframework/plugins/common/include
DrmInfo 是一种封装容器类,可封装与 DRM 服务器通信的协议。通过处理 DrmInfo 的实例,可以实现服务器注册、注销、许可获取或任何其他服务器相关的事务。该协议应当由 XML 格式的插件进行描述。每个 DRM 插件将通过解释该协议来完成相应的事务。DRM 框架定义了一个 API 来检索名为 acquireDrmInfo() 的 DrmInfo 实例。
DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest);
检索有关注册、注销或权限获取信息的必要信息。请参阅 DrmInfoRequest 了解更多信息。
DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
processDrmInfo() 会以异步方式运行,事务的结果可通过 OnEventListener 或 OnErrorListener 检索。
要播放 DRM 内容,需要将 DRM 内容与其许可相关联。建立关联后,许可将在 DRM 框架中处理,从而可将媒体播放器应用从具体的证书中提取出来。
int checkRightsStatus(int uniqueId, const String8& path, int action);
检查指定内容是否具备有效权限。输入参数是已保存内容所在的内容文件路径和查询权限的操作,例如:Action::DEFAULT、Action::PLAY。返回受保护内容的权限状态,例如:RightsStatus::RIGHTS_VALID、RightsStatus::RIGHTS_EXPIRED。
status_t saveRights(int uniqueId, const DrmRights& drmRights, const String8& rightsPath, const String8& contentPath);
将 DRM 权限保存到指定的权限路径并与内容路径相关联。输入参数是要保存的 DrmRights、权限要保存到的权限文件路径,以及已保存内容所在的内容文件路径。
许可元数据(如许可到期时间、可重复计数等)可嵌入受保护内容的权限内。安卓 DRM 框架提供了 API 来返回与输入内容相关联的限制条件。请参阅 DrmManagerClient 了解更多信息。
DrmConstraints* getConstraints(int uniqueId, const String path, int
action);
getConstraint 函数调用可返回受保护内容中嵌入的限制条件的键值对。要检索这些限制条件,则需要 uniqueId(受保护内容的会话和路径的唯一标识符)。此外,还需要执行被定义为 Action::DEFAULT、Action::PLAY 等的操作
DrmMetadata* getMetadata(int uniqueId, const String path);
获取与受保护内容指定路径下的输入内容相关联的元数据信息,以返回元数据的键值对。
为了保持解密会话,DRM 框架的调用者必须在解密序列开始时调用 openDecryptSession()。openDecryptSession() 会询问每个 DRM 插件是否能够处理输入 DRM 内容。
status_t openDecryptSession(
int uniqueId, DecryptHandle* decryptHandle, int fd, off64_t offset, off64_t length);
上述调用允许您将 DRM 权限保存到指定的权限路径并与内容路径相关联。DrmRights 参数是要保存的权限、权限的正确文件路径,以及内容应该保存到的内容文件路径。
DRM 框架中的某些 API 在 DRM 事务中异步运行。一个应用可以将三个监听器类注册到 DRM 框架。
•OnEventListener:用于异步 API 的结果
•OnErrorListener:用于接收异步 API 的错误
•OnInfoListener:用于 DRM 事务期间的任何补充信息
安卓 DRM 框架包括几个示例、一个 passthru 插件和一个转发锁定插件,它们的位置如下:
PLATFORM_ROOT/frameworks/av/drm/libdrmframework/plugins/passthru
PLATFORM_ROOT/frameworks/av/drm/libdrmframework/plugins/forward-lock
将以下内容添加到插件实现的 Android.mk 中。passthruplugin 作为示例使用。
PRODUCT_COPY_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/PLUGIN_LIBRARY:system/lib/drm/plugins/native/PLUGIN_LIBRARY
例如
PRODUCT_COPY_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libdrmpassthruplugin.so:system/lib/drm/plugins/native/libdrmpassthruplugin.so
插件开发者必须在如下目录中找到各自的插件:
/system/lib/drm/plugins/native/libdrmpassthruplugin.so