| <html devsite><head> |
| <title>DRM</title> |
| <meta name="project_path" value="/_project.yaml"/> |
| <meta name="book_path" value="/_book.yaml"/> |
| </head> |
| <body> |
| <!-- |
| Copyright 2017 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <img style="float: right; margin: 0px 15px 15px 15px;" src="images/ape_fwk_hal_drm.png" alt="安卓 DRM HAL 图标"/> |
| |
| <p>本文档概要介绍了安卓数字版权管理 (DRM) 框架,并介绍了 DRM 插件必须实现的接口。本文档不提供可由 DRM 方案定义的稳健性规则或合规性规则的相关说明。</p> |
| |
| <h2 id="introduction">简介</h2> |
| |
| <p>安卓平台提供了一个可扩展的 DRM 框架,以便应用根据与受版权保护的内容关联的许可限制条件来管理这些内容。DRM 框架支持多种 DRM 方案;设备具体支持哪些 DRM 方案由设备制造商决定。安卓 3.0 中引入的 DRM 框架为应用开发者提供了一个统一接口,并隐藏了 DRM 操作的复杂性。DRM 框架为受保护和不受保护的内容提供了一致的操作模式。DRM 方案可以定义非常复杂的许可元数据使用模型。DRM 框架提供了 DRM 内容与许可之间的关联,并处理权限管理。这样可以将媒体播放器从受 DRM 保护或不受保护的内容中提取出来。请参阅 <a href="https://developer.android.com/reference/android/media/MediaDrm.html">MediaDrm</a>,了解如何使用该类来获取用于解密受保护的媒体流的密钥。</p> |
| |
| <img src="/devices/images/ape_fwk_drm.png" alt="安卓 DRM HAL"/> |
| |
| <p class="img-caption"><strong>图 1. </strong> DRM 硬件抽象层</p> |
| |
| <p>提供丰富数字内容的能力对于移动设备用户来说非常重要。为保证内容的广泛覆盖面,安卓开发者和数字内容发布者需要在整个安卓生态系统中支持一致的 DRM 实现。为了让这类数字内容适用于安卓设备,并确保至少有一个一致的 DRM 可用于所有设备,Google 会在兼容的安卓设备上提供无需支付许可费用的 DRM。在安卓 3.0 及更高版本的平台上,DRM 插件会与安卓 DRM 框架集成在一起,并可使用受硬件支持的保护功能来确保付费内容和用户凭据的安全。 |
| </p> |
| |
| <p> |
| DRM 插件提供的内容保护功能取决于底层硬件平台的安全性和内容保护功能。设备的硬件功能包括硬件安全启动,可建立加密密钥的安全性和保护的信任链。设备的内容保护功能包括设备内加密帧的保护和通过可信输出保护机制实现的内容保护。并非任意硬件平台都支持上述所有的安全性和内容保护功能。安全性绝不会在堆栈的单个位置实现,而是依赖于硬件、软件和服务的集成。将硬件安全性功能、可信启动机制以及用于处理安全性功能的隔离安全操作系统组合使用是交付安全设备的关键。</p> |
| |
| <h2 id="architecture">架构</h2> |
| <p>DRM 框架与实现无关,可在方案特定的 DRM 插件中提取特定 DRM 方案实现的详情。DRM 框架包括可执行以下操作的简单 API:处理复杂的 DRM 操作、向在线 DRM 服务注册用户和设备、从许可中提取限制信息、将 DRM 内容与其许可相关联,以及最终解密 DRM 内容。</p> |
| |
| <p>安卓 DRM 框架在以下两个架构层中实现:</p> |
| <ul> |
| <li>DRM framework API:通过安卓应用框架提供给应用,并通过适用于标准应用的 Dalvik VM 运行。</li> |
| <li>本机代码 DRM 管理器:用于实现 DRM 框架,并为 DRM 插件(代理)提供接口,以便处理各种 DRM 方案的版权管理和解密操作。</li> |
| </ul> |
| |
| <img src="images/ape_fwk_drm_2.png" alt="安卓 DRM 框架"/> |
| |
| <p class="img-caption"><strong>图 2. </strong> DRM 框架</p> |
| |
| <p>有关详情,请参阅<a href="http://developer.android.com/reference/android/drm/package-summary.html">安卓 DRM 文件包参考</a>。</p> |
| |
| <h2 id="plug-ins">插件</h2> |
| <p>如下图所示,DRM 框架使用插件架构来支持各种 DRM 方案。DRM 管理器服务在一个独立进程中运行,以确保隔离执行 DRM 插件。从 DrmManagerClient 到 DrmManagerService 的每个 API 调用都需要使用 binder IPC 机制来跨越进程边界。DrmManagerClient 提供了 Java 编程语言实现,作为运行时应用的通用接口;此外,它还提供了 DrmManagerClient 本机实现作为本机模块的接口。DRM 框架的调用者仅访问 DrmManagerClient,无需了解每个 DRM 方案。</p> |
| |
| <img src="images/ape_fwk_drm_plugins.png" alt="安卓 DRM 插件"/> |
| |
| <p class="img-caption"><strong>图 3. </strong> 带有插件的 DRM 框架</p> |
| |
| <p>当 DrmManagerService 启动时,插件会自动加载。如下图所示,DRM 插件管理器会加载/取消加载所有可用插件。DRM 框架会在以下目录中查找并自动加载插件:</p> |
| <pre class="devsite-click-to-copy"> |
| /system/lib/drm/plugins/native/ |
| </pre> |
| |
| <img src="images/ape_fwk_drm_plugins_life.png" alt="安卓 DRM 插件生命周期"/> |
| |
| <p class="img-caption"><strong>图 4. </strong> DRM 插件生命周期</p> |
| |
| <p>插件开发者应确保插件位于 DRM 框架插件的发现目录中。请参阅下文中的实现说明了解详细信息。</p> |
| |
| <h2 id="implementation">实现</h2> |
| |
| <h3 id="IDrmEngine">IDrmEngine</h3> |
| |
| <p>IDrmEngine 是一种接口,包含一组用于 DRM 用例的 API。插件开发者必须实现 IDrmEngine 中指定的接口和下方指定的监听器接口。源代码树在以下目录中提供了接口定义:</p><p> |
| </p><pre class="devsite-click-to-copy"> |
| <var>PLATFORM_ROOT</var>/frameworks/av/drm/libdrmframework/plugins/common/include |
| </pre> |
| |
| <h3 id="DrmInfo">DRM 信息</h3> |
| <p>DrmInfo 是一种封装容器类,可封装与 DRM 服务器通信的协议。通过处理 DrmInfo 的实例,可以实现服务器注册、注销、许可获取或任何其他服务器相关的事务。该协议应当由 XML 格式的插件进行描述。每个 DRM 插件将通过解释该协议来完成相应的事务。DRM 框架定义了一个 API 来检索名为 acquireDrmInfo() 的 DrmInfo 实例。</p> |
| |
| <pre class="devsite-click-to-copy prettyprint"> |
| DrmInfo* acquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest); |
| </pre> |
| <p>检索有关注册、注销或权限获取信息的必要信息。请参阅 <a href="http://developer.android.com/reference/android/drm/DrmInfoRequest.html">DrmInfoRequest</a> 了解更多信息。</p> |
| |
| <pre class="devsite-click-to-copy prettyprint"> |
| DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo); |
| </pre> |
| <p>processDrmInfo() 会以异步方式运行,事务的结果可通过 OnEventListener 或 OnErrorListener 检索。</p> |
| |
| <h3 id="drm-rights">DRM 权限</h3> |
| |
| <p>要播放 DRM 内容,需要将 DRM 内容与其许可相关联。建立关联后,许可将在 DRM 框架中处理,从而可将媒体播放器应用从具体的证书中提取出来。</p> |
| |
| <pre class="devsite-click-to-copy prettyprint"> |
| int checkRightsStatus(int uniqueId, const String8& path, int action); |
| </pre> |
| |
| <p>检查指定内容是否具备有效权限。输入参数是已保存内容所在的内容文件路径和查询权限的操作,例如:Action::DEFAULT、Action::PLAY。返回受保护内容的权限状态,例如:RightsStatus::RIGHTS_VALID、RightsStatus::RIGHTS_EXPIRED。</p> |
| |
| <pre class="devsite-click-to-copy prettyprint"> |
| status_t saveRights(int uniqueId, const DrmRights& drmRights, const String8& rightsPath, const String8& contentPath); |
| </pre> |
| |
| <p>将 DRM 权限保存到指定的权限路径并与内容路径相关联。输入参数是要保存的 DrmRights、权限要保存到的权限文件路径,以及已保存内容所在的内容文件路径。</p> |
| |
| <h3 id="metadata">许可元数据</h3> |
| <p>许可元数据(如许可到期时间、可重复计数等)可嵌入受保护内容的权限内。安卓 DRM 框架提供了 API 来返回与输入内容相关联的限制条件。请参阅 <a href="http://developer.android.com/reference/android/drm/DrmManagerClient.html">DrmManagerClient</a> 了解更多信息。</p> |
| |
| <pre class="devsite-click-to-copy prettyprint"> |
| DrmConstraints* getConstraints(int uniqueId, const String path, int |
| action); |
| </pre> |
| <p>getConstraint 函数调用可返回受保护内容中嵌入的限制条件的键值对。要检索这些限制条件,则需要 uniqueId(受保护内容的会话和路径的唯一标识符)。此外,还需要执行被定义为 Action::DEFAULT、Action::PLAY 等的操作。</p> |
| |
| <img src="images/ape_fwk_drm_retrieve_license.png" alt="安卓 DRM 许可元数据"/> |
| |
| <p class="img-caption"><strong>图 5. </strong> 检索许可元数据</p> |
| |
| <pre class="devsite-click-to-copy prettyprint"> |
| DrmMetadata* getMetadata(int uniqueId, const String path); |
| </pre> |
| <p>获取与受保护内容指定路径下的输入内容相关联的元数据信息,以返回元数据的键值对。</p> |
| |
| <h3 id="metadata">解密会话</h3> |
| <p>为了保持解密会话,DRM 框架的调用者必须在解密序列开始时调用 openDecryptSession()。openDecryptSession() 会询问每个 DRM 插件是否能够处理输入 DRM 内容。</p> |
| <pre class="devsite-click-to-copy prettyprint"> |
| status_t openDecryptSession( |
| int uniqueId, DecryptHandle* decryptHandle, int fd, off64_t offset, off64_t length); |
| </pre> |
| |
| <p>上述调用允许您将 DRM 权限保存到指定的权限路径并与内容路径相关联。DrmRights 参数是要保存的权限、权限的正确文件路径,以及内容应该保存到的内容文件路径。</p> |
| |
| <h3 id="listeners">DRM 插件监听器</h3> |
| |
| <p>DRM 框架中的某些 API 在 DRM 事务中异步运行。一个应用可以将三个监听器类注册到 DRM 框架。</p> |
| |
| <ul> |
| <li>OnEventListener:用于异步 API 的结果</li> |
| <li>OnErrorListener:用于接收异步 API 的错误</li> |
| <li>OnInfoListener:用于 DRM 事务期间的任何补充信息</li> |
| </ul> |
| |
| <h3 id="source">源代码</h3> |
| |
| <p>安卓 DRM 框架包括几个示例、一个 passthru 插件和一个转发锁定插件,它们的位置如下:</p> |
| <pre class="devsite-click-to-copy"> |
| <var>PLATFORM_ROOT</var>/frameworks/av/drm/libdrmframework/plugins/passthru |
| <var>PLATFORM_ROOT</var>/frameworks/av/drm/libdrmframework/plugins/forward-lock |
| </pre> |
| |
| <h3 id="build">构建和集成</h3> |
| |
| <p>将以下内容添加到插件实现的 Android.mk 中。passthruplugin 作为示例使用。</p> |
| |
| <pre class="devsite-click-to-copy"> |
| PRODUCT_COPY_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/<var>PLUGIN_LIBRARY</var>:system/lib/drm/plugins/native/<var>PLUGIN_LIBRARY</var> |
| </pre> |
| <p>例如</p> |
| <pre class="devsite-click-to-copy"> |
| PRODUCT_COPY_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libdrmpassthruplugin.so:system/lib/drm/plugins/native/libdrmpassthruplugin.so |
| </pre> |
| <p>插件开发者必须在如下目录中找到各自的插件:</p> |
| <pre class="devsite-click-to-copy"> |
| /system/lib/drm/plugins/native/libdrmpassthruplugin.so |
| </pre> |
| |
| </body></html> |