直接回答
先看产品需求,而不是先找 Direct Boot API。对大多数端侧 AI 工作流,设备重启后的正确状态是“等待当前用户解锁”。此前保存的 ready 标记、上一次成功加载模型或关机前设置的闹钟,都不能证明首次解锁前可以访问模型文件、用户历史或推理任务。如果没有面向用户或系统的关键动作必须在这段时间执行,就不要启用 Direct Boot 感知组件;把普通数据留在默认的凭据加密(CE)存储中,并在解锁后初始化本地推理。 Android 文件级加密为应用提供两种可用时间不同的存储上下文。CE 是默认存储;本次启动后,只有当前用户成功首次解锁,CE 才可用。首次解锁后,即使屏幕再次锁定,CE 仍持续可用;普通重新锁屏不是又一次首次解锁边界。设备加密(DE)存储在首次解锁前后都可访问,但它同样经过加密。不能仅因 DE 更早可读,就把它当作私密数据的通用存储。Android 建议尽可能将文件放在 CE 中,并把 DE 限制在 Direct Boot 阶段确实需要的信息。 默认情况下,应用不会在 Direct Boot 阶段运行。只有确实承担解锁前职责的组件才应显式声明 android:directBootAware,并通过受保护设备存储上下文访问它所需的数据。这个决定只作用于具体组件和存储,不会自动让整个应用或模型流水线就绪。例如,通知调度可能只需要一条小型计划标记;这并不构成把完整模型、提示历史、转写、照片、健康笔记或其他用户内容移入 DE 的理由。解锁前元数据应最少、非私密、有版本,并且即使不读取模型输入也能独立使用。 组件启动时,先用当前用户上下文调用 UserManager.isUserUnlocked()。如果结果已是 true,就立即走已解锁路径,不要等待可能在组件启动前已经发出的 ACTION_USER_UNLOCKED 广播。如果仍为锁定状态且运行中的功能需要解锁通知,应由运行中的组件动态注册 BroadcastReceiver 来接收 ACTION_USER_UNLOCKED,然后再次检查状态,以覆盖注册过程中的解锁竞态,并对状态转换幂等处理。不能假定静态 Manifest 声明的接收器会收到 ACTION_USER_UNLOCKED。相对地,ACTION_LOCKED_BOOT_COMPLETED 由符合条件且在 Manifest 注册的 android:directBootAware 组件接收,并需要 RECEIVE_BOOT_COMPLETED 权限和相应注册。两种事件不能和普通屏幕亮起或屏幕解锁回调混为一谈。如果设备有工作资料或单独的用户凭据挑战,应检查相应用户/资料上下文的解锁状态,不能借用主用户状态;每个存储边界都属于对应用户。 因此,模型就绪应由多个状态组成,而不是一个持久化 Boolean:首次解锁前、可选的最小 DE 动作已完成、等待用户解锁、CE 可访问、模型资源已核实、运行时已初始化、任务可执行。首次解锁前不能读取 CE 中的模型;DE 元数据里写着“已下载”也不能证明资源当前已挂载、完整或可加载。收到 USER_UNLOCKED 后,应重新解析资源位置和身份,执行应用实际支持的校验,初始化运行时,再向用户提供新的任务。如果需要的模型缺失且此时没有网络,就保持未就绪并解释下一步;不要静默启动大体积修复下载,不要把开机事件当作用户同意,也不要搬运 CE/DE 数据来伪造自动成功。 应使用设置了锁屏凭据的专用测试设备或测试资料来验证这个边界。重启后停留在锁屏,检查是否只有明确指定的组件运行、是否只读取了预期的 DE 元数据。然后解锁当前用户,观察解锁转换,再测试 CE 模型资源和新的本地任务。之后重新锁屏但不重启,确认没有错误地重新判成首次解锁前。再重启一次重复测试;只有产品支持工作资料时,才单独测试工作资料的凭据挑战。记录系统版本、用户/资料、存储上下文、事件、文件身份、网络状态和结果。本方法不证明 Cove 已有 Direct Boot 接收器、解锁前推理或任何特定就绪行为。 关键区别不是“加密与未加密”:CE 与 DE 都是加密存储。真正的区别是当前启动周期中,当前用户凭据保护的密钥是否已可用,以及功能是否确实需要在此之前动作。默认将私密模型任务数据留在 CE。只有经过隐私和恢复审查、且有明确解锁前需求时,才把最少的合理元数据放入 DE。能等待的任务就等到解锁。这样可以缩小解锁前的暴露面,避免声称本地存储的模型会自动在首次解锁前运行。
重启后在首次解锁前请求模型任务
Android 设备刚重启,当前用户仍停留在锁屏,还没有输入凭据。应用之前记住了模型选择和任务偏好,但模型与私密历史存放在普通应用存储中。产品提案建议将两者都移入 DE,以便自动开始工作。
决策
先确认首次解锁前是否确有面向用户的功能必须执行。没有就等待当前用户解锁,并将模型与任务数据留在 CE;确有狭窄需求时,只通过明确声明 Direct-Boot-aware 的组件暴露最少非私密元数据。
预期结果
应用如实呈现锁定/等待状态,不提前读取 CE 或搬运用户内容,并在解锁事件后重新检查模型,才接受新任务。
需要收集的证据
只有将以下证据与同一模型文件和测试运行关联起来,结论才可复核:
- 当前用户首次解锁与存储上下文
- 解锁前最小化元数据清单
- 首次解锁后的模型就绪和断网结果
只有记录了模型身份、构建配置、实际后端、任务样例和失败情况,运行时比较才可复核。
实施流程
- 写明首次解锁前的实际需求. 指出要执行的准确动作、服务的用户或系统对象,以及为何不能等到首次解锁。如果理由只是加快启动或恢复一个 ready 标记,就延后执行,不要只为方便启用 Direct Boot。
- 按敏感性分类每份文件和状态. 盘点模型资源、提示、任务输入、历史、健康或媒体记录、偏好设置及小型调度元数据。私密数据和解锁前不必使用的内容留在 CE;不要为了避免等待状态就搬动完整模型或用户任务。
- 仅在必要时设计最小 DE 契约. 有真实解锁前需求时,明确所需的小型非私密字段、保留时间和使用组件。只让该组件 Direct-Boot-aware,并显式取得 DE 上下文;普通界面和推理初始化仍走解锁后的路径。
- 按当前用户状态门控行为. 使用当前用户上下文的 UserManager.isUserUnlocked()。将 LOCKED_BOOT_COMPLETED 作为锁定阶段,将 USER_UNLOCKED 作为 CE 可用转换;不把屏幕重新锁定视为重新进入锁定启动,也不复用其他资料的状态。
- 解锁后重新验证模型资源. 收到解锁信号后重新解析模型路径,检查准确制品身份和应用已配置的完整性证据,再初始化运行时。DE 中保存的标记或重启前的 ready 状态,不能证明当前文件可访问或运行时已经成功加载。
- 分别测试锁定启动、首次解锁和之后重锁. 在有锁屏凭据的临时设备或资料中重启并检查锁定阶段,解锁后测试新任务,再不重启地重新锁屏。记录当前用户状态、存储读取、事件、网络条件和失败;不要声称 Cove 已实现接收器。
让每个阶段的状态都可观察。失败信息应指出阶段、模型、运行时和恢复动作,同时避免记录用户私密内容。
验收标准
- 功能有书面记录的首次解锁前需求;没有该需求时,不启用 Direct-Boot-aware 组件,模型任务等待解锁。
- 私密输入、提示、历史和模型任务状态默认保留在 CE;任何 DE 字段都最少、非私密、有明确理由,并由显式感知加密状态的组件拥有。
- 测试区分锁定启动、当前用户首次解锁、普通屏幕重锁和独立资料挑战;解锁后才启动的组件会先查状态而不等待错过的广播,并重新建立模型就绪状态。
决策对照表
| 维度 | 选择或证据 | 解读方式 |
|---|---|---|
| 等待首次解锁 | 本地 AI 默认流程 | 私密模型和任务数据留在 CE;没有真实早期需求时不增加解锁前组件。 |
| 使用最少 DE 元数据 | 窄范围 Direct Boot 行为 | 可支持有理由的解锁前动作,但只用于明确限定的非私密状态和感知加密的组件。 |
| 把模型和任务历史移入 DE | 广泛解锁前存储 | 增加数据暴露和迁移复杂度,却不能证明模型就绪或推理应在解锁前启动。 |
| 把屏幕重锁视为 CE 不可用 | 反复锁定的解释 | 用户在本次启动已经解锁后,这种解释不正确;CE 会持续可用到设备重启。 |
需要避免的失败模式
- 把私密内容移入设备加密存储
- 把历史 ready 标记当成当前模型可访问证据
- 把屏幕重新锁定当成重新进入解锁前状态
还要避免静默回退、版本未固定、缺少取消处理,以及把不同配置的结果混在一起下结论。失败运行也应与成功记录一并保存。
最小复现记录
| 层级 | 记录内容 |
|---|---|
| 设备 | 厂商、型号、芯片、内存档位、操作系统版本 |
| 软件 | 应用版本和 Git 提交号 |
| 模型 | 系列、变体、版本、格式、文件长度、摘要、量化方式 |
| 运行时 | 名称、版本、请求后端及实际后端证据 |
| 工作负载 | 样例版本、输入摘要、提示词摘要、输出策略 |
| 结果 | 完成、失败、取消、回退及保护隐私的诊断信息 |
发布检查表
- ☐ 主要搜索问题已回答,且没有未经支持的数字。
- ☐ 所有模型文件和运行时版本均已固定。
- ☐ 代表性任务和失败处理策略均有说明。
- ☐ 生命周期、取消、清理和回退均已测试。
- ☐ 用户内容与网络边界均有说明。
- ☐ 结论只适用于被记录的配置。
- ☐ 新增测试结果时链接到原始方法或证据。
来源与相关证据
- Android privacy and security
- Android Developers — Direct Boot 模式
- Android 开源项目 — 文件级加密
- Android API — UserManager.isUserUnlocked
中文部署与排错专题见。奇连 AI 端侧专题。
常见问题
屏幕锁定时,凭据加密存储会变得不可访问吗?
不会。当前启动后,当前用户首次解锁时 CE 变为可用,即使之后屏幕重新锁定也仍可访问。新的设备重启才会开始下一次首次解锁边界;应与普通屏幕锁定分别测试。
为了加快启动,应把本地模型或提示历史移到 DE 吗?
默认不应如此。Android 建议将私密或解锁前不需要的数据留在 CE,并尽量把文件放在 CE。DE 只应存放经证明必须用于解锁前功能的最少非私密信息。
应用应怎样处理当前用户解锁通知?
组件启动时先检查当前用户上下文的 UserManager.isUserUnlocked();已解锁就立即继续。如果仍锁定,运行中的组件应动态注册 BroadcastReceiver 监听 ACTION_USER_UNLOCKED 并复查状态;不要假定静态 Manifest 接收器会收到它。LOCKED_BOOT_COMPLETED 则要求符合条件、在 Manifest 注册且具备 RECEIVE_BOOT_COMPLETED 权限的 android:directBootAware 组件。
收到 ACTION_LOCKED_BOOT_COMPLETED 就可以开始模型推理吗?
不可以。该事件通知符合条件的 Direct-Boot-aware 组件进入锁定启动阶段并可访问 DE;它不会开放 CE、证明模型资源可读、初始化运行时,也不能说明首次解锁前适合开始推理。
主用户的解锁状态能代表工作资料吗?
不能。应检查相关当前用户或资料,特别是工作资料有单独凭据挑战时。不能用一个用户的解锁事件证明另一个资料的凭据保护文件已可用。