支持直接启动模式

设备开机但用户尚未解锁设备时,Android 7.0 会在安全的直接启动模式下运行。为了支持此模式,系统提供了两种数据存储位置

  • 凭据加密存储空间,这是默认存储位置,仅在用户解锁设备后可用。
  • 设备加密存储空间,此存储位置在直接启动模式期间和用户解锁设备后均可用。

默认情况下,应用在直接启动模式期间不运行。如果您的应用需要在直接启动模式期间执行操作,您可以注册应用组件以便在此模式下运行。应用需要在直接启动模式期间运行的一些常见用例包括

  • 有计划通知的应用,例如闹钟应用。
  • 提供重要用户通知的应用,例如短信应用。
  • 提供无障碍服务的应用,例如 Talkback。

如果您的应用需要在直接启动模式下运行时访问数据,请使用设备加密存储空间。设备加密存储空间包含使用只有在设备成功执行验证启动后才可用的密钥进行加密的数据。

对于必须使用与用户凭据(例如 PIN 或密码)关联的密钥进行加密的数据,请使用凭据加密存储空间。凭据加密存储空间在用户成功解锁设备后直到用户重新启动设备之前均可用。如果用户在解锁设备后启用锁定屏幕,则凭据加密存储空间仍然可用。

请求在直接启动期间运行的访问权限

应用必须先向系统注册其组件,然后才能在直接启动模式期间运行或访问设备加密存储空间。应用通过将组件标记为支持加密来向系统注册。要将您的组件标记为支持加密,请在清单中将 android:directBootAware 属性设置为 true。

支持加密的组件可以注册以在设备重启时接收来自系统的 ACTION_LOCKED_BOOT_COMPLETED 广播消息。此时设备加密存储空间可用,您的组件可以执行在直接启动模式期间需要运行的任务,例如触发计划的闹钟。

以下代码片段是演示如何在应用清单中将 BroadcastReceiver 注册为支持加密并为 ACTION_LOCKED_BOOT_COMPLETED 添加 intent 过滤器的示例

<receiver
  android:directBootAware="true" >
  ...
  <intent-filter>
    <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
  </intent-filter>
</receiver>

用户解锁设备后,所有组件都可以访问设备加密存储空间和凭据加密存储空间。

访问设备加密存储空间

要访问设备加密存储空间,请通过调用 Context.createDeviceProtectedStorageContext() 创建第二个 Context 实例。使用此上下文进行的任何存储 API 调用都将访问设备加密存储空间。以下示例访问设备加密存储空间并打开现有的应用数据文件

Kotlin

val directBootContext: Context = appContext.createDeviceProtectedStorageContext()
// Access appDataFilename that lives in device encrypted storage
val inStream: InputStream = directBootContext.openFileInput(appDataFilename)
// Use inStream to read content...

Java

Context directBootContext = appContext.createDeviceProtectedStorageContext();
// Access appDataFilename that lives in device encrypted storage
FileInputStream inStream = directBootContext.openFileInput(appDataFilename);
// Use inStream to read content...

仅将设备加密存储空间用于在直接启动模式期间必须可访问的信息。不要将设备加密存储空间用作通用的加密存储。对于私人用户信息或在直接启动模式期间不需要的加密数据,请使用凭据加密存储空间。

获取用户解锁通知

用户在重启后解锁设备时,您的应用可以切换到访问凭据加密存储空间,并使用依赖于用户凭据的常规系统服务。

要在用户重启后解锁设备时收到通知,请从运行的组件中注册一个 BroadcastReceiver 以监听解锁通知消息。用户在启动后解锁设备时

如果用户已解锁设备,您可以通过调用 UserManager.isUserUnlocked() 来得知。

迁移现有数据

如果用户更新设备以使用直接启动模式,您可能有一些现有数据需要迁移到设备加密存储空间。请使用 Context.moveSharedPreferencesFrom()Context.moveDatabaseFrom()(其中目标上下文是方法调用者,源上下文是参数)来在凭据加密存储空间和设备加密存储空间之间迁移偏好设置和数据库数据。

不要将私人用户信息(例如密码或授权令牌)从凭据加密存储空间迁移到设备加密存储空间。在决定将哪些其他数据迁移到设备加密存储空间时,请自行判断。在某些情况下,您可能需要在两个加密存储空间中管理不同的数据集。

测试支持加密的应用

在启用直接启动模式的情况下测试支持加密的应用。

大多数运行最新版本 Android 的设备会在设置锁定屏幕凭据(PIN、图案或密码)后启用直接启动模式。具体而言,所有使用基于文件的加密的设备都是如此。要检查设备是否使用基于文件的加密,请运行以下 shell 命令

adb shell getprop ro.crypto.type

如果输出为 file,则表示设备已启用基于文件的加密。

在默认情况下不使用基于文件的加密的设备上,可能有其他选项可用于测试直接启动模式

  • 某些使用全盘加密 (ro.crypto.type=block) 并运行 Android 7.0 到 Android 12 的设备可以转换为基于文件的加密。有两种方法可以实现此转换

      警告:无论是哪种转换为基于文件的加密的方法,都会清除设备上的所有用户数据。

    • 在设备上,如果尚未启用开发者选项,请前往设置 > 关于手机并点按版本号七次以启用。然后前往设置 > 开发者选项并选择转换为文件加密
    • 或者,运行以下 shell 命令
      adb reboot-bootloader
      fastboot --wipe-and-use-fbe
      
  • 运行 Android 13 或更低版本的设备支持“模拟”直接启动模式,该模式使用文件权限来模拟加密文件被锁定和解锁的效果。仅在开发期间使用模拟模式;它可能导致数据丢失。要启用模拟直接启动模式,请在设备上设置锁定图案,在设置锁定图案时如果提示安全启动屏幕则选择“不用了”,然后运行以下 shell 命令

    adb shell sm set-emulate-fbe true
    

    要关闭模拟直接启动模式,请运行以下 shell 命令

    adb shell sm set-emulate-fbe false
    

    运行这些命令中的任何一个都会导致设备重启。

检查设备政策加密状态

设备管理应用可以使用 DevicePolicyManager.getStorageEncryptionStatus() 来检查设备的当前加密状态。

如果您的应用面向低于 Android 7.0 (API 24) 的 API 级别,并且设备正在使用全盘加密或基于文件的直接启动加密,则 getStorageEncryptionStatus() 将返回 ENCRYPTION_STATUS_ACTIVE。在这两种情况下,静态数据始终是加密存储的。

如果您的应用面向 Android 7.0 (API 24) 或更高版本,并且设备正在使用全盘加密,则 getStorageEncryptionStatus() 将返回 ENCRYPTION_STATUS_ACTIVE。如果设备正在使用基于文件的直接启动加密,则返回 ENCRYPTION_STATUS_ACTIVE_PER_USER

如果您构建的应用面向 Android 7.0,请务必同时检查 ENCRYPTION_STATUS_ACTIVEENCRYPTION_STATUS_ACTIVE_PER_USER 以确定设备是否已加密。

其他代码示例

通过 DirectBoot 示例,您可以进一步了解如何使用本页介绍的 API。