> ## Documentation Index
> Fetch the complete documentation index at: https://o.doubao.com/SAEP_Protocol/llms.txt
> Use this file to discover all available pages before exploring further.

---
tree:false
---

## 1. 引言与目标 {#1.-引言与目标}

本文档是**屏幕自动化操作声明协议**（SAEP，Screen Automation Execution Protocol）的官方接入指南，旨在帮助 Android 应用开发者理解并接入屏幕自动化操作声明功能。开发者可通过本指南完成策略声明、能力检测、Agent 信息查询和操作日志审计，在支持自动化协作的同时保护应用数据、业务资源与用户权益。

## 2. 屏幕自动化操作协议介绍 {#2.-屏幕自动化操作协议介绍}

SAEP 是面向 GUI Agent 操作第三方应用的声明协议。它将应用保护要求转换为机器可解析的策略，由系统在操作前完成 Agent 身份校验和策略决策，在关键能力路径实施约束，并记录可审计的决策与执行结果。

协议解决的问题：

* **让应用表达可操作边界**：三方应用可声明哪些页面和操作允许 Agent 访问，哪些页面或能力需要禁止 GUI Agent 代理操作。
* **让策略管理统一裁决**：策略管理模块综合 Agent 身份、系统安全基线、应用声明策略和用户授权状态，得到本次操作的最终决策。
* **让约束不可轻易绕过**：限制由系统关键能力入口执行，不仅依赖 Agent 自律。
* **让行为可以追溯**：记录谁在什么时间、对哪个应用页面、请求了什么操作、命中了什么策略以及实际结果。

### 2.1 系统架构 {#2.1-系统架构}



![Image=2560x1430](https://p9-arcosite.byteimg.com/tos-cn-i-goo7wpa0wc/2dc01e68934c4a939c30e09039c94665~tplv-goo7wpa0wc-topic.webp)



### 2.2 核心角色与概念 {#2.2-核心角色与概念}

<!-- @cols-width: 266,126,1000 -->
| 逻辑组件  | 所属层面  | 核心职责  |
| --- | --- | --- |
| Target App（三方应用）  | 应用生态  | 声明应用、Activity 和 Intent 级操作边界；查询已注册 Agent 及本应用审计日志。  |
| Agent 策略管理  | 应用生态  | 以静态 Manifest 资源或动态更新方式表达限制规则，包含 `default_policy` 与 `scope`。  |
| Agent 身份查询  | 应用生态  | 对系统侧 Agent 身份信息进行查询和管理。  |
| GUI Agent  | Agent 生态  | 完成任务规划、页面理解和意图识别；执行前提交目标、动作和上下文，请求系统决策。  |
| Agent 身份认证  | 系统控制面  | 管理 Agent 注册信息，校验包名、签名、UUID、可信等级和设备证明，并向声明应用提供查询。  |
| 策略管理模块  | 系统执行面  | 将决策落实到屏幕/虚拟显示、无障碍读取、点击、输入和注入等系统控制点。  |
| Agent 动作执行  | 系统执行面  | 承载屏幕与虚拟显示、无障碍与页面读取、点击、输入和注入等实际能力；只接受策略管理模块放行后的请求。  |
| TEE 服务  | 可信基础设施  | 保护可信身份和证明材料，关联 Agent 应用、实例身份与设备可信状态。  |
| 日志管理服务  | 审计基础设施  | 汇聚策略决策和 Agent 动作执行结果，补充系统可信字段，并按调用应用实施查询隔离。  |
| 安全存储  | 审计基础设施  | 保存策略、Agent 注册信息和审计记录，实施访问控制、完整性保护和生命周期管理。  |

### 2.3 系统基线 {#2.3-系统基线}

系统基线是 SAEP 的最低边界，由系统统一维护，优先于应用声明和 Agent 自身判断。它用于防止三方应用未声明策略、策略填写错误或 Agent 试图绕过时出现能力意外放开。

* **身份基线**：未注册、签名不匹配、可信证明失败或设备状态不满足要求的 Agent，应被拒绝进入受控执行链路。
* **能力基线**：截图、无障碍访问、点击与输入注入等高权限能力必须经过系统控制点。
* **行为基线**：涉及支付转账、账号认证、内容发布、删除、权限变更等高风险动作，可由系统要求用户二次确认、用户接管或拒绝执行。
* **不可放宽**：应用策略不得把系统基线的 `BLOCK` 或 `CALL_USER` 降级为 `ALLOW`。
* **可审计**：系统基线命中、执行阻断、降级和用户接管均应产生原因码与审计记录。

### 2.4 Agent 操作策略 {#2.4-agent-操作策略}

Agent 操作策略描述“某个 Agent 在当前上下文中能否对目标应用执行某项 GUI 操作”。最终结果至少由以下四类输入共同决定：

1. **Agent 身份与可信状态**：Agent UUID、包名、签名摘要、Agent 类型、可信等级和设备健康证明。
2. **系统基线**：系统对红线行为和高风险能力的统一限制。
3. **应用声明策略**：应用静态或动态提供的 `default_policy` 与 `scope`。
4. **用户授权与任务上下文**：用户是否对当前任务和具体高风险步骤作出有效确认。

应用策略可在三个作用域表达：

<!-- @cols-width: 112,126,483 -->
| 作用域  | 匹配对象  | 示例  |
| --- | --- | --- |
| App  | 整个应用  | Agent 在本应用可在任意页面执行该操作。  |
| Activity  | 指定页面  | 登录页禁止截图和输入，支付确认页完全禁止操作。  |
| Intent  | 指定业务意图  | 限制内容修改、最终发布、删除或激励权益领取。  |

策略合并遵循三个稳定原则：系统基线不可放宽、多个命中结果取更严格值、解析失败回退到可用的默认策略。由于方案材料对 App、Activity、Intent 的简单顺序表述存在差异，开发者不应依赖“后写覆盖前写”；应让敏感页面显式声明限制，并通过目标镜像的验收用例确认最终 Effective Policy。

### 2.5 决策、强制执行与用户接管 {#2.5-决策、强制执行与用户接管}

<!-- @cols-width: 126,553,546 -->
| 决策  | 系统行为  | 应用与 Agent 预期  |
| --- | --- | --- |
| `ALLOW`  | 允许调用对应系统能力，并记录正常执行结果。  | 仍需继续通过应用业务鉴权；不代表免除用户授权。  |
| `BLOCK`  | 在 PEP 阻断操作，返回明确拒绝且不应回退到旁路能力。  | 停止自动操作，向用户说明限制，不尝试换通道绕过。  |
| `CALL_USER`  | 暂停自动化并展示系统级确认或接管界面。  | 等待用户亲自确认或操作，确认只覆盖所展示的具体步骤。  |
| `CLARIFY`  | 当前材料中用于表达澄清或软性约束。  | 具体语义和是否对外开放必须以目标 SDK/API 包为准。  |

强制执行应位于系统控制的关键路径。例如：应用级禁用可阻止目标应用进入 Agent 虚拟屏；页面禁止截图可增加安全图层；输入限制可在 InputManager 等路径阻断模拟注入。意图级约束是否已具备完整系统强制能力取决于目标版本，不能仅凭 Agent 返回“已遵守”完成验收。

### 2.6 审计闭环 {#2.6-审计闭环}

策略决策和实际执行必须同时进入审计链路，才能识别“决策允许但执行失败”“决策拒绝但 Agent 尝试绕过”等差异。审计事件至少应关联 Agent 身份、会话与步骤、目标包和 Activity、操作意图、能力类型、策略版本、决策结果、执行结果及原因码。

* **系统侧记录**：由系统服务和关键执行点补充调用方 UID、时间戳、执行结果等可信字段。
* **最小披露**：不记录原始截图、用户输入敏感个人信息或完整控件树等隐私原文。
* **应用隔离**：三方应用只能查询与自身应用相关的日志。
* **版本边界**：日志查询、导出和保留阈值以目标系统版本实际能力为准。

## 3. 接入准备 {#3.-接入准备}

### 3.1 支持系统版本 {#3.1-支持系统版本}

<!-- @cols-width: 126,273 -->
| 项目  | 当前状态  |
| --- | --- |
| 支持系统版本  | ObricUI 2.2 版本及以上  |

### 3.2 API 总览 {#3.2-api-总览}

三方应用可通过以下系统接口和配置入口接入 SAEP。调用前应先检测协议状态；接口不存在、调用异常或返回不可用时，应按 SAEP 不可用处理，并继续执行应用自身的控制。

<!-- @cols-width: 742,1000,728 -->
| 所属类  | API 签名  | API 描述  |
| --- | --- | --- |
| `android.security.obric.robots.RobotsHelperStub`  | `public static RobotsHelperStub getInstance()`  | 获取 SAEP 状态查询接口的单例对象。  |
| `android.security.obric.robots.RobotsHelperStub`  | `public boolean isRobotsEnabled(android.content.Context context)`  | 通过应用 Context 查询 SAEP 是否启用；`true` 表示启用。  |
| `android.security.obric.robots.RobotsHelperStub`  | `public boolean isRobotsEnabled()`  | 不传入 Context 查询 SAEP 是否启用；由系统实现侧获取上下文。  |
| `android.content.ContentResolver`  | `public int update(android.net.Uri uri, android.content.ContentValues values, java.lang.String where, java.lang.String[] selectionArgs)`  | 向 SAEP Policy Provider 提交动态策略；返回成功更新的记录数。  |
| `android.security.obric.agentmanager.AgentManagerStub`  | `public static AgentManagerStub getInstance()`  | 获取可信 Agent 查询接口的单例对象。  |
| `android.security.obric.agentmanager.AgentManagerStub`  | `public java.util.List<java.lang.String> listRegisteredAgents()`  | 查询设备中已注册 Agent 的 UUID 列表。  |
| `android.security.obric.agentmanager.AgentManagerStub`  | `public java.lang.String getAgentInfo(java.lang.String agentUuid)`  | 根据 Agent UUID 查询对应的注册身份信息，结果为 JSON 字符串。  |
| `android.security.obric.audit.SecurityAuditManagerStub`  | `public static SecurityAuditManagerStub getInstance()`  | 获取安全审计日志查询接口的单例对象。  |
| `android.security.obric.audit.SecurityAuditManagerStub`  | `public java.util.List<java.lang.String> queryLogs(long startTimeMs, long endTimeMs, java.lang.String targetIntent, java.lang.String targetActivity)`  | 按时间、操作意图和目标 Activity 查询与调用应用自身相关的审计日志。  |

## 4. 接入流程 {#4.-接入流程}

### 4.1 SAEP 协议的工作逻辑 {#4.1-saep-协议的工作逻辑}



![Image=2560x712](https://p9-arcosite.byteimg.com/tos-cn-i-goo7wpa0wc/31aae8dd4c1e41228be9e1bd9e095f60~tplv-goo7wpa0wc-topic.webp)



### 4.2 第一步：检测 SAEP 是否可用 {#4.2-第一步：检测-saep-是否可用}

应用应在进入依赖 SAEP 的功能前查询协议状态。返回 `true` 表示当前系统侧功能生效；返回 `false` 表示功能被云端关闭、系统版本不支持或暂不可用。检测失败时按“不支持”处理，并继续依赖应用自身安全控制。

```java
// 判断 SAEP 协议功能当前是否生效（通过 Context 版本）
// 返回 true 表示生效，false 表示已被云端关闭或不可用
public static boolean isRobotsEnabled(Context context)
```

**SAEP 状态查询（当前材料中的反射方式）**

```java
try {
    Class<?> clazz =
        Class.forName("android.security.obric.robots.RobotsHelperStub");
    Method getInstance = clazz.getDeclaredMethod("getInstance");
    getInstance.setAccessible(true);
    Object instance = getInstance.invoke(null);

    // 方式一：带 Context 参数版本
    Method methodWithCtx = clazz.getDeclaredMethod("isRobotsEnabled",
        Context.class);
    methodWithCtx.setAccessible(true);
    boolean enabled = (Boolean) methodWithCtx.invoke(instance, context);
    Log.d(TAG, "SAEP protocol enabled: " + enabled);
} catch (Exception e) {
    Log.e(TAG, "isRobotsEnabled failed: " + e.getMessage());
}
```

### 4.3 第二步：设定策略 {#4.3-第二步：设定策略}

#### 4.3.1 策略结构 {#4.3.1-策略结构}

<!-- @cols-width: 196,100,100,1000 -->
| 字段  | 类型  | 必填  | 说明  |
| --- | --- | --- | --- |
| `schema`  | string  | 是  | 固定格式：`AGRP-Policy/1.0`。Android GUI Robots 协议（AGRP，Android GUI Robots Policy）。  |
| `policy_version`  | int  | 是  | 策略版本号由应用自增；动态更新不得回滚。  |
| `package`  | string  | 否  | 设置管控规则的应用包名。  |
| `updated_at`  | string  | 是  | Unix 毫秒级时间戳字符串，用于记录 Policy 更新时间。  |
| `default_policy`  | object  | 是  | 解析失败时的回落策略，必须可用。  |
| `scope`  | object  | 否  | 应用级、Activity 页面级和 Agent 意图级细化规则。  |

顶层字段表只声明到 `default_policy` 和 `scope`。以下按当前策略示例及现有联调代码补齐 `app`、`activities` 两个维度的嵌套字段；未由正式 Schema 定义的必填、缺省与覆盖语义继续标为“未定义”。

**app 维度字段**

<!-- @cols-width: 518,100,812 -->
| 字段路径  | 类型  | 说明  |
| --- | --- | --- |
| `default_policy.app`  | object  | 当前示例中的应用级默认回落策略容器；目前仅确认顶层 `default_policy` 必填。  |
| `default_policy.app.global_disable`  | boolean  | `true` 表示禁止全部 Agent 操作。  |
| `default_policy.app.screenshot_disable`  | boolean  | `true` 表示禁止截图或屏幕帧。  |
| `default_policy.app.input_disable`  | boolean  | `true` 表示禁止点击、文本输入等模拟输入。  |
| `scope.app`  | object  | 应用级细化策略容器；随非必填的 `scope` 整体省略。  |
| `scope.app.global_disable`  | boolean  | 当前策略示例已使用；语义同上。  |
| `scope.app.screenshot_disable`  | boolean  | 现有联调代码支持，主策略示例未展示；正式支持范围以 Schema 为准。  |
| `scope.app.input_disable`  | boolean  | 现有联调代码支持，主策略示例未展示；正式支持范围以 Schema 为准。  |

**activities 维度字段**

<!-- @cols-width: 798,168,791 -->
| 字段路径  | 类型  | 说明  |
| --- | --- | --- |
| `scope.activities`  | object / map  | Activity 页面级规则集合；使用完整 Activity 类名作为动态键，不是数组。  |
| `scope.activities.<完整 Activity 类名>`  | object  | 单个页面的规则条目，例如 `com.example.bank.LoginActivity`。  |
| `scope.activities.<Activity>.name`  | string  | 面向用户展示的页面中文名称。  |
| `scope.activities.<Activity>.page_scope`  | object  | Activity 页面级限制项容器。  |
| `scope.activities.<Activity>.page_scope.global_disable`  | boolean  | `true` 表示禁止该页面全部 Agent 操作。  |
| `scope.activities.<Activity>.page_scope.screenshot_disable`  | boolean  | `true` 表示禁止该页面截图或屏幕帧。  |
| `scope.activities.<Activity>.page_scope.input_disable`  | boolean  | `true` 表示禁止该页面点击、文本输入等模拟输入。  |

**agent_intents 维度字段**

<!-- @cols-width: 266,100,630 -->
| 字段路径  | 类型  | 说明  |
| --- | --- | --- |
| `scope.agent_intents`  | object  | Agent 意图级别；针对声明的意图场景，会在整个应用全局生效。  |

#### 4.3.2 支持的限制项 {#4.3.2-支持的限制项}

<!-- @cols-width: 252,294,420 -->
| 字段  | true 的含义  | 典型用途  |
| --- | --- | --- |
| `global_disable`  | 禁止全部 Agent 操作  | 整个应用不允许 GUI Agent 操作。  |
| `screenshot_disable`  | 禁止截图/屏幕帧  | 登录、支付确认、隐私展示等敏感页面。  |
| `input_disable`  | 禁止点击、文本输入等模拟输入  | 密码、验证码、权限变更等页面。  |
| `modify_content`  | 限制修改内容或设置  | 昵称、通讯录、权限、设备与支付开关等。  |
| `post_content`  | 限制最终发送/发布  | 可辅助编辑，但不能代替用户完成最终发布。  |
| `delete_content`  | 限制最终删除  | 可帮助定位或选择对象，但不能执行删除。  |
| `account_incentive`  | 限制激励权益操作  | 签到、抽奖、秒杀、任务、积分或奖励领取。  |

统一语义：上述字段均以 `true` 表示“限制/禁止”，以 `false` 表示“不由该字段限制”，若未设定对应字段时将按照 `false` 进行处置。`false` 不代表系统最终一定允许，系统安全基线和其他更严格规则仍可拒绝操作，如支付场景。

#### 4.3.3 优先级与失败回退 {#4.3.3-优先级与失败回退}

* **系统基线不可放宽**：应用策略不能把系统基线的拒绝或用户确认结果降级为允许。
* **最严格结果生效**：多个命中规则冲突时，从严处置。
* **全局禁用优先**：`global_disable=true` 时，不再依赖截图或输入子项来放开能力。
* **解析失败安全回退**：Schema 不支持、JSON 解析失败或结构异常时，使用 `default_policy`，并记录回退原因。
* **版本单调递增**：低于当前系统缓存版本的动态策略不得覆盖高版本。

#### 4.3.4 策略示例 {#4.3.4-策略示例}

文件：`res/raw/agent_saep_policy.json`

```json
{
  "schema": "AGRP-Policy/1.0",
  "policy_version": 1,
  "package": "com.example.bank",
  "updated_at": "1772191606000",
  "default_policy": {
    "app": {
      "global_disable": true,
      "screenshot_disable": false,
      "input_disable": true
    }
  },
  "scope": {
    "app": {
      "global_disable": false
    },
    "activities": {
      "com.example.bank.LoginActivity": {
        "name": "登录界面",
        "page_scope": {
          "global_disable": true,
          "screenshot_disable": true,
          "input_disable": true
        }
      },
      "com.example.bank.PayConfirmActivity": {
        "name": "支付确认界面",
        "page_scope": {
          "screenshot_disable": true
        }
      }
    },
    "agent_intents": {
      "modify_content": false,
      "delete_content": false,
      "account_incentive": true,
      "post_content": false
    }
  }
}
```

### 4.4 第三步：接入静态策略（推荐） {#4.4-第三步：接入静态策略（推荐）}

静态声明是当前材料推荐的基础接入方式。系统在应用安装或更新时读取并缓存策略，不依赖应用进程已启动。

文件：`AndroidManifest.xml`

```xml
<application
    ... >

    <meta-data
        android:name="com.obric.agentrobots.POLICY_JSON"
        android:resource="@raw/agent_saep_policy" />

    ...
</application>
```

本节按当前接口材料使用 `@raw/agent_saep_policy.json`。开发者可根据自身代码规范对资源名称进行自定义命名。

### 4.5 第四步：动态更新策略（可选） {#4.5-第四步：动态更新策略（可选）}

当策略需要随用户状态、云控或业务条件变化时，可通过系统 Provider 更新。当前初稿示例 URI 为：

```text
content://com.obric.agentrobots.provider/policy
```

请求参数：

* `policy`：完整策略 JSON 字符串。
* `version`：整数版本号，必须高于当前已生效版本。

**动态策略更新**

```java
private static final Uri POLICY_UPDATE_URI =
    Uri.parse("content://com.obric.agentrobots.provider/policy");

/**
 * 通过 ContentProvider 更新策略
 *
 * @param context 上下文
 * @param policy 策略 JSON 字符串
 * @param version 版本号
 * @return 更新影响的行数，负数表示失败
 */
public static int updatePolicy(Context context, String policy, int version) {
    ContentValues values = new ContentValues();
    values.put("policy", policy);
    values.put("version", version);
    return context.getContentResolver().update(
        POLICY_UPDATE_URI, values, null, null);
}
```

应用必须在本地完成 JSON Schema 校验后再提交。更新失败时保留上一有效版本，不得先清空旧策略；失败结果要进入应用自身监控。

<!-- @cols-width: 588,987 -->
| 错误码  | 处理建议  |
| --- | --- |
| `E_ACCESS_DENIED`  | 检查调用包名、签名和权限。  |
| `E_INVALID_ARGUMENT`  | 检查参数、JSON 与版本类型。  |
| `E_POLICY_PARSE_ERROR` / `E_POLICY_VALIDATION`  | 检查字段名、Schema、枚举值和 JSON 合法性；注意原材料中的 `POLICTY` 拼写可能是实现兼容项。  |
| `E_POLICY_VERSION_ROLLBACK`  | 生成更高版本号后重试，禁止复用旧版本。  |
| `E_POLICY_NOT_MORE_RESTRICTIVE`  | 策略包含无法收敛的放宽项；保持原策略并按镜像规则调整。  |
| `E_SIGNATURE_INVALID`  | 检查包签名与登记信息。  |
| `E_RATE_LIMITED`  | 建议合并更新，避免频繁调用。  |
| `E_STORAGE_UNAVAILABLE` / `E_INTERNAL_ERROR`  | 保留上一有效策略，记录告警并稍后重试。  |

> 开发者可以根据自身应用工程情况选择静态策略声明或动态更新，两种方案保证至少有一个接入即可。推荐开发者使用静态策略声明进行更新，系统会在应用包安装和更新时自动捕获最新的策略文件。

### 4.6 第五步：查询可信 Agent {#4.6-第五步：查询可信-agent}

系统提供端侧已注册 Agent 列表和指定 Agent 信息查询。

#### 4.6.1 接口定义 {#4.6.1-接口定义}

```java
package android.security.obric.agentmanager;

public class RobotsHelperStub {
    /**
     * 获取指定Agent的信息
     *
     * @param agentUuid Agent的 UUID
     * @return Agent信息的 JSON 字符串
     */
    public String getAgentInfo(String agentUuid) {
    }

    /**
     * 获取已注册的Agent列表
     *
     * @return 已注册Agent的 UUID 列表
     */
    public List<String> listRegisteredAgents() {
    }
}
```

系统提供在端侧已经注册的可信 Agent 进行查询。查询结果可能包含 Agent 名称、UUID、应用包名、签名摘要、Agent 类型、可信等级和版本等信息。应用应将该信息用于展示和审计关联，不应自行把“已注册”推导为对任意业务动作已获授权。

#### 4.6.2 查询流程 {#4.6.2-查询流程}



![Image=2560x1718](https://p9-arcosite.byteimg.com/tos-cn-i-goo7wpa0wc/86d188e13bda4c86a5816b1ac02a4181~tplv-goo7wpa0wc-topic.webp)

#### 4.6.3 调用示例 {#4.6.3-调用示例}

以下代码保留原文的异常处理和反射调用方式。正式 SDK 可用后应优先改用稳定的编译期接口。

**1. 获取已注册的 UUID**

```java
try {
    Class<?> stubClazz =
        Class.forName("android.security.obric.agentmanager.AgentManagerStub");
    Method getInstanceMethod = stubClazz.getDeclaredMethod("getInstance");
    getInstanceMethod.setAccessible(true);
    Object stub = getInstanceMethod.invoke(null);

    Method listMethod = stubClazz.getDeclaredMethod("listRegisteredAgents");
    listMethod.setAccessible(true);

    List<String> uuids = (List<String>) listMethod.invoke(stub);
    // uuids 即已注册的AgentUUID 列表
} catch (Exception e) {
    e.printStackTrace();
}
```

**2. 通过 UUID 获取对应 Agent 应用信息**

```java
try {
    Class<?> stubClazz =
        Class.forName("android.security.obric.agentmanager.AgentManagerStub");
    Method getInstanceMethod = stubClazz.getDeclaredMethod("getInstance");
    getInstanceMethod.setAccessible(true);
    Object stub = getInstanceMethod.invoke(null);

    Method getInfoMethod = stubClazz.getDeclaredMethod("getAgentInfo",
        String.class);
    getInfoMethod.setAccessible(true);

    String uuid = "<YOUR_AGENT_UUID>";
    String info = (String) getInfoMethod.invoke(stub, uuid);
    // info 即该Agent的详情信息（JSON 字符串）
} catch (Exception e) {
    e.printStackTrace();
}
```

### 4.7 第六步：查询本应用审计日志 {#4.7-第六步：查询本应用审计日志}

系统与 Agent 会统一记录所有 Agent 的操作日志。作为被操作方，你的应用也将被赋予查询相关日志的权限。应用只能查询与自身包名相关的记录。建议在后台线程异步查询，按时间窗口分页或分批处理，避免阻塞主线程。

系统将提供一个标准接口，允许你查询与你的应用相关的 Agent 操作记录。支持查询范围如下：

1. 时间维度
2. 页面维度
3. 意图维度

#### 4.7.1 日志查询流程 {#4.7.1-日志查询流程}



![Image=2560x1048](https://p9-arcosite.byteimg.com/tos-cn-i-goo7wpa0wc/c99970ce378445768338d7746b026b67~tplv-goo7wpa0wc-topic.webp)



* 建议使用后台线程异步查询，避免阻塞应用主进程。
* 仅允许应用查询自身包名相关日志。
* 失败返回空列表的语义需与正式 SDK 区分“无数据”和“查询失败”。

#### 4.7.2 接口定义 {#4.7.2-接口定义}

```java
package android.security.obric.audit;

public class SecurityAuditManagerStub {
    /**
     * 查询调用方自己的审计日志。
     *
     * @param startTimeMs 日志开始时间戳（毫秒）；0 表示不限制
     * @param endTimeMs 日志结束时间戳（毫秒）；0 表示不限制
     * @param targetIntent 查询意图；为空则不按意图过滤
     * @param targetActivity 查询目标 Activity；为空则不按 Activity 过滤
     * @return 原始 JSON 日志字符串列表；失败返回空列表
     */
    public List<String> queryLogs(long startTimeMs, long endTimeMs,
        String targetIntent, String targetActivity) {
    }
}
```

#### 4.7.3 日志字段 {#4.7.3-日志字段}

<!-- @cols-width: 427,322,100,100,1000 -->
| 分类  | 字段名  | 类型  | 是否可空  | 说明  |
| --- | --- | --- | --- | --- |
| `agent_identify`（Agent 身份）  | `agent_name`  | String  | 否  | Agent 名称。  |
| `agent_identify`（Agent 身份）  | `agent_uuid`  | String  | 否  | Agent 实例的唯一标识，来自其身份声明。  |
| `agent_identify`（Agent 身份）  | `pkg_sha256`  | String  | 否  | Agent 应用签名的 SHA256。  |
| `agent_identify`（Agent 身份）  | `agent_type`  | Enum  | 否  | Agent 类型（如 `ASSISTIVE_EXECUTION`、`AUTONOMOUS`）。  |
| `agent_identify`（Agent 身份）  | `trust_level`  | Enum  | 否  | Agent 的可信等级（如 `TRUSTED_TEE`、`UNTRUSTED`），由系统层 TEE 决定并填充。  |
| `agent_identify`（Agent 身份）  | `package_name`  | String  | 否  | 发起调用的进程 UID 及其包名，由系统填充。  |
| `agent_identify`（Agent 身份）  | `agent_version`  | String  | 是  | Agent app 的版本号。  |
| `agent_identify`（Agent 身份）  | `agent_md5`  | String  | 是  | Agent app 的 apk 文件哈希。  |
| `agent_identify`（Agent 身份）  | `proof_signature`  | String  | 否  | 由 TEE 产出，针对 Agent 注册的可信身份证明签名。  |
| `agent_decision`（操作记录与决策记录）  | `log_source`  | String  | 否  | 日志来源：`agent`：Agent 决策日志；`framework`：InputManagerService 和 WindowsManager 插桩日志。  |
| `agent_decision`（操作记录与决策记录）  | `timestamp`  | String  | 否  | 日志的时间戳。  |
| `agent_decision`（操作记录与决策记录）  | `event_id`  | String  | 否  | 单次事件的全局唯一标识符。  |
| `agent_decision`（操作记录与决策记录）  | `session_id`  | String  | 否  | Agent 的会话 ID，用于关联一个任务流程中的所有事件。  |
| `agent_decision`（操作记录与决策记录）  | `step_id`  | String  | 否  | Agent 操作的步骤 id。  |
| `agent_decision`（操作记录与决策记录）  | `target_package`  | String  | 否  | 操作目标应用的包名。  |
| `agent_decision`（操作记录与决策记录）  | `target_activity`  | String  | 是  | 操作目标应用的 Activity 名称。  |
| `agent_decision`（操作记录与决策记录）  | `intent_type`  | String  | 是  | Agent 的操作意图分类（如 `ACCOUNT_AUTH`、`ASSET_TRANSACTION`）。若未进行意图判断，该字段为空。  |
| `agent_decision`（操作记录与决策记录）  | `decision_outcome`  | Enum  | 否  | 云侧返回决策结果：`BLOCK`、`CALL_USER`、`CLARIFY`、`ALLOW`。  |
| `agent_decision`（操作记录与决策记录）  | `user_authorization_type`  | Enum  | 是  | 用户授权类型：`CALL_USER`、`EXPLICIT_AGREEMENT`、`AUTO_EXECUTION`。  |
| `agent_decision`（操作记录与决策记录）  | `action_type`  | String  | 否  | 本次操作使用的核心能力（如 `SCREENSHOT`、`CLICK`）。  |
| `agent_decision`（操作记录与决策记录）  | `action_args`  | List  | 否  | 本次操作的参数；截图场景传入 activity。  |
| `agent_decision`（操作记录与决策记录）  | `policy`  | String  | 是  | 原始策略管理 json 原文。若目标应用不存在管控策略，此处为空。  |
| `agent_decision`（操作记录与决策记录）  | `reason_code`  | String  | 是  | Agent 决策原因，如 `APP_POLICY_GLOBAL`、`SYSTEM_BASELINE`、`APP_POLICY_ACTIVITY`、`APP_POLICY_INTENT`、`NULL`。策略更新：如 `MANIFEST`、`CONTENT_PROVIDER`。  |
| `agent_decision`（操作记录与决策记录）  | `duration_ms`  | Long  | 是  | 操作执行耗时（毫秒）。操作被拒绝/用户接管场景下，默认值为 0。  |

#### 4.7.4 调用示例 {#4.7.4-调用示例}

```java
List<String> logs = new ArrayList<>();
try {
    Class<?> clazz =
        Class.forName("android.security.obric.audit.SecurityAuditManagerStub");
    Method method = clazz.getDeclaredMethod("queryLogs",
        long.class, long.class, String.class, String.class);
    method.setAccessible(true);
    Object ret = method.invoke(null, startMs, endMs, intentParam,
        activityParam);
    if (ret instanceof List) {
        logs.addAll((List<String>) ret);
        //TO DO: 实现业务逻辑
    }
} catch (Exception e) {
    Log.e(TAG, "queryLogs error: " + e.getMessage());
}
```

#### 4.7.5 日志留存 {#4.7.5-日志留存}

日志存储在端侧安全区域，日志存储规则满足以下任意一个条件将会进行滚动删除。

* 存储时长：默认 60 天。
* 存储大小：数据库超过 100 MB。
* 存储总量：数据总量超过 10 万条。

## 5. 常见问题 {#5.-常见问题}

### 配置策略未生效 {#配置策略未生效}

* 确认目标设备确实启用 SAEP，参考 4.1 检测 SAEP 是否可用。
* 确认 Manifest 中 meta 声明与要求一致，资源已打包进 APK。
* 检查 JSON 合法性、字段拼写、`schema` 与 `policy_version`。

### 动态策略更新失败 {#动态策略更新失败}


* 确认 URI、调用权限、包名/签名和策略版本号。
* 版本号必须单调递增；不要用时间戳截断后充当 int。
* 对频控错误退避重试；对解析和校验错误不要无条件重试。

### Agent 查询或日志查询反射失败 {#agent-查询或日志查询反射失败}


* 确认当前系统镜像包含对应 Framework API。
* 对照交付 API 包确认类名、静态/实例方法和参数签名。

### 声明允许后 Agent 仍被拒绝 {#声明允许后-agent-仍被拒绝}

应用声明只表达应用侧边界，不能覆盖系统安全基线、Agent 身份校验、用户授权或业务风控。请结合日志中的 `decision_outcome` 与 `reason_code` 定位。

## 6. Demo 示例 {#6.-demo-示例}

为便于开发者理解并验证 SAEP 接入流程，我们提供开源示例工程 SAEP Demo，包含以下功能：

- **协议状态查询**：查询当前设备是否启用 SAEP。
- **静态策略声明**：展示 Manifest 配置方式及随 APK 打包的策略文件。
- **动态策略更新**：构建并提交本应用的策略配置。
- **可信 Agent 查询**：获取已注册的 Agent UUID 列表及对应身份信息。
- **本地审计日志查询**：按时间、Activity 和意图等条件查询与本应用相关的操作记录。

### 源码地址

| 平台 | 仓库地址 |
| --- | --- |
| GitHub | [bytedance/SAEP-demo](https://github.com/bytedance/SAEP-demo) |
| Gitee | [ByteDance/SAEP-demo](https://gitee.com/ByteDance/SAEP-demo) |