细化任务执行结果与超时处理

This commit is contained in:
QiuSW
2026-09-04 16:02:22 +08:00
parent 6458419730
commit a6622b775a
17 changed files with 259 additions and 102 deletions
+23
View File
@@ -20,6 +20,29 @@
当前代码中的动作只有 `WAIT`、`CLICK`、`INPUT`、`BACK` 和 `EXTRACT_TEXT`。
## 结果码总表
结果码在这里统一定义,动作文档只引用不重复定义。事实来源是 [`ResultCode`](../../../android/app/src/main/java/cn/auto/agent/core/model/TaskModels.kt)。
**是否成功只看 `successful`;成功时 `code` 恒为 `OK`。** 不使用 `CLICKED`、`INPUT_SENT`、`OPEN_SENT`、`ALREADY_SELECTED` 这类“成功但不是 OK”的码——否则调用方无法用 `code` 判断成败。需要区分成功的细节时,用独立的 `detail` 字段,不占用 `code`。
| code | 状态 | 含义 |
|---|---|---|
| `OK` | **[已实现]** | 步骤或任务成功 |
| `PACKAGE_MISMATCH` | **[已实现]** | 超时内前台包始终与 `packageName` 不符 |
| `ACTIVITY_MISMATCH` | **[已实现]** | 超时内前台 Activity 始终与 `activityName` 不符 |
| `TARGET_NOT_FOUND` | **[已实现]** | 超时内 selector 没有匹配到节点 |
| `TARGET_AMBIGUOUS` | **[已实现]** | selector 匹配多个节点,立即失败 |
| `ACTION_FAILED` | **[已实现]** | 目标已找到,但动作在超时内始终未成功 |
| `TARGET_NOT_INTERACTABLE` | **[提案]** | 目标不可见、禁用或不可编辑 |
| `VERIFICATION_FAILED` | **[提案]** | 动作已分发,但 `after` 或回读验证未通过 |
| `TASK_INVALID` | **[提案]** | 任务解析失败 |
| `UNSUPPORTED_ON_DEVICE` | **[提案]** | 当前系统版本或服务配置不支持该动作 |
超时不单独设码:超时体现为“超时内没能成功”的那个具体原因(`TARGET_NOT_FOUND`、`ACTION_FAILED` 等),不再为每个动作定义 `WAIT_TIMEOUT`、`SCROLL_TIMEOUT` 这类同义码。
新增动作时,先在 `ResultCode` 与本表中登记,再在动作文档引用。
## 统一规则
每个 UI 动作遵循同一条简单流程:
+3 -5
View File
@@ -60,11 +60,9 @@ after 超时不会自动再次返回。连续返回需要编写多个 BACK 步
## 4. 结果码
- `BACK_SENT`:系统接受返回请求,未声明 after。
- `OK`:返回后 after 满足。
- `PRECONDITION_FAILED`
- `ACTION_FAILED`
- `VERIFICATION_FAILED`
见[结果码总表](README.md#结果码总表)。BACK 使用 `OK`、`ACTION_FAILED` 和 `VERIFICATION_FAILED`。
未声明 after 时,成功只表示系统接受了返回请求。before 不满足按 `ACTION_FAILED` 之外的上下文码处理(`PACKAGE_MISMATCH` 或 `TARGET_NOT_FOUND`)。
## 5. 测试
+3 -7
View File
@@ -75,13 +75,9 @@
## 4. 结果码
- `CLICKED`:点击已分发,未声明 after。
- `OK`:点击已分发且 after 满足。
- `TARGET_NOT_FOUND`
- `TARGET_AMBIGUOUS`
- `TARGET_NOT_INTERACTABLE`
- `ACTION_FAILED`
- `VERIFICATION_FAILED`
见[结果码总表](README.md#结果码总表)。CLICK 使用 `OK`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS`、`TARGET_NOT_INTERACTABLE`、`ACTION_FAILED` 和 `VERIFICATION_FAILED`。
未声明 after 时,成功只表示点击已分发,不表示页面已变化。
## 5. 测试
+3 -7
View File
@@ -79,13 +79,9 @@ EXTRACT 不点击、不滚动、不读取未声明字段,也不保存完整控
## 4. 结果码
- `OK`
- `TARGET_NOT_FOUND`
- `TARGET_AMBIGUOUS`
- `FIELD_NOT_AVAILABLE`
- `CONVERSION_FAILED`
- `OUTPUT_EMPTY`
- `EXTRACT_TIMEOUT`
见[结果码总表](README.md#结果码总表)。EXTRACT 使用 `OK`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS` 和 `ACTION_FAILED`(文本为空、字段缺失或类型转换失败)。
字段缺失与类型转换失败是否需要独立码,等 EXTRACT 实现时按实际排查需要决定,不提前登记。
## 5. 兼容方式
+3 -8
View File
@@ -75,14 +75,9 @@
## 4. 结果码
- `INPUT_SENT`:输入已分发但未回读验证。
- `OK`:输入验证通过。
- `INPUT_VALUE_INVALID`
- `TARGET_NOT_FOUND`
- `TARGET_AMBIGUOUS`
- `TARGET_NOT_EDITABLE`
- `ACTION_FAILED`
- `VERIFICATION_FAILED`
见[结果码总表](README.md#结果码总表)。INPUT 使用 `OK`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS`、`TARGET_NOT_INTERACTABLE`(含不可编辑)、`ACTION_FAILED` 和 `VERIFICATION_FAILED`。
`verify` 为 `NONE` 时,成功只表示系统接受了输入请求,不表示文本已正确写入。
## 5. 测试
+3 -8
View File
@@ -63,14 +63,9 @@ OPEN 不写入任何具体 App 的页面文案、深链或恢复流程;这些
## 4. 结果码
- `OPEN_ALREADY_FOREGROUND`
- `OPEN_SENT`:目标包已进入前台,未声明 after。
- `OK`:目标包和 after 都满足。
- `TARGET_NOT_INSTALLED`
- `NO_HANDLER`
- `ACTION_FAILED`
- `PACKAGE_MISMATCH`
- `VERIFICATION_FAILED`
见[结果码总表](README.md#结果码总表)。OPEN 使用 `OK`、`PACKAGE_MISMATCH`、`ACTION_FAILED`(未安装、无处理程序或 Intent 分发失败)和 `VERIFICATION_FAILED`。
“已在前台”“已进入前台但未验证”属于成功的细节,放在 `detail` 而不是 `code`。未安装与无处理程序是否需要独立码,等实现时按排查需要决定。
## 5. 测试
+3 -8
View File
@@ -68,14 +68,9 @@ Android 无障碍截图从 API 30 开始可用;服务配置还需要声明对
## 4. 结果码
- `OK`
- `UNSUPPORTED_ON_DEVICE`
- `TARGET_NOT_FOUND`
- `TARGET_AMBIGUOUS`
- `CAPTURE_FAILED`
- `CROP_INVALID`
- `IMAGE_TOO_LARGE`
- `STORE_FAILED`
见[结果码总表](README.md#结果码总表)。SCREENSHOT 使用 `OK`、`UNSUPPORTED_ON_DEVICE`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS` 和 `ACTION_FAILED`(截图、裁剪、超限或保存失败)。
截图各阶段的失败是否需要拆成独立码,等实现时按排查需要决定。
## 5. 测试
+3 -8
View File
@@ -64,14 +64,9 @@ SCROLL 是统一滚动动作。当前代码尚未实现。
## 4. 结果码
- `OK`
- `SCROLL_SENT`:方向滚动成功。
- `TARGET_NOT_FOUND`
- `CONTAINER_NOT_FOUND`
- `CONTAINER_AMBIGUOUS`
- `EDGE_REACHED`
- `ACTION_FAILED`
- `SCROLL_TIMEOUT`
见[结果码总表](README.md#结果码总表)。SCROLL 使用 `OK`、`TARGET_NOT_FOUND`(含容器未找到)、`TARGET_AMBIGUOUS`(容器不唯一)和 `ACTION_FAILED`。
“到达边缘仍未找到目标”属于 `TARGET_NOT_FOUND` 的一种原因,写在 `message` 里即可,不单独设码。
## 5. 测试
+3 -8
View File
@@ -49,14 +49,9 @@ SELECT_OPTION 是“查找选项、必要时滚动、点击并验证选中”的
## 3. 结果码
- `ALREADY_SELECTED`
- `OK`
- `OPTION_NOT_FOUND`
- `OPTION_AMBIGUOUS`
- `CONTAINER_NOT_FOUND`
- `ACTION_FAILED`
- `VERIFICATION_FAILED`
- `SELECT_TIMEOUT`
见[结果码总表](README.md#结果码总表)。SELECT_OPTION 使用 `OK`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS`、`ACTION_FAILED` 和 `VERIFICATION_FAILED`。
“已经处于选中状态”属于成功的细节,放在 `detail` 而不是 `code`。
## 4. 测试
+4 -7
View File
@@ -22,8 +22,8 @@
- 约每 100 毫秒查询一次。
- selector 匹配一个节点时成功。
- 没有匹配时等待到超时。
- 多个匹配时立即返回 `TASK_AMBIGUOUS`。
- 超时返回 `TASK_NOT_MATCHED`;optional=true 时继续下一步。
- 多个匹配时立即返回 `TARGET_AMBIGUOUS`。
- 超时返回 `TARGET_NOT_FOUND`;optional=true 时跳过并继续下一步。
## 2. Condition 扩展 **[提案]**
@@ -68,12 +68,9 @@
## 4. 结果码
- `OK`:条件满足。
- `WAIT_TIMEOUT`:超时未满足。
- `TARGET_AMBIGUOUS`:要求 ONE 但匹配多个。
- `CONDITION_ERROR`:条件无法正常求值。
见[结果码总表](README.md#结果码总表)。WAIT 使用 `OK`、`TARGET_NOT_FOUND`(超时未满足)、`TARGET_AMBIGUOUS`(要求 ONE 但匹配多个)以及上下文码 `PACKAGE_MISMATCH`、`ACTIVITY_MISMATCH`。
v1 对外仍可映射为现有 `OK`、`TASK_AMBIGUOUS` 和 `TASK_NOT_MATCHED`。
Condition 无法求值时需要一个独立码,等 Condition 实现时再登记。
## 5. 测试
+7 -18
View File
@@ -10,8 +10,10 @@
2. 等待 `packageName` 和可选 `activityName` 匹配。
3. BACK 直接调用全局返回;其他动作查询 selector。
4. 没有目标时继续等待,多个目标立即失败。
5. 执行动作;成功后进入下一步。
6. 到达超时时,optional 步骤跳过,其他步骤停止任务。
5. 执行动作;成功后立即结束本步并进入下一步。
6. 每次尝试结束后判定截止时间:到达超时时 optional 步骤跳过,其他步骤停止任务。
超时判定在每轮尝试之后进行,因此轮询唤醒晚于截止时间不会让失败的步骤被记为成功。多目标(`TARGET_AMBIGUOUS`)立即停止任务,不受 `optional` 影响。
当前结果:
@@ -26,13 +28,9 @@
}
~~~
当前结果码只有:
结果码见[结果码总表](actions/README.md#结果码总表)。当前执行器会产生 `OK`、`PACKAGE_MISMATCH`、`ACTIVITY_MISMATCH`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS` 和 `ACTION_FAILED`。
| code | 含义 |
|---|---|
| `OK` | 任务执行完成 |
| `TASK_AMBIGUOUS` | selector 匹配多个节点 |
| `TASK_NOT_MATCHED` | 包名、Activity、目标或动作在超时内未成功 |
是否成功只看 `successful`,成功时 `code` 恒为 `OK`;`message` 只用于排障,不参与流程判断。
## 2. 简单步骤结果 **[提案]**
@@ -60,16 +58,7 @@
暂不引入 phase、effect、transition 和独立结果协议版本。以后确实需要断点恢复或复杂流程审计时再扩展。
建议逐步细分以下 code:
- `TASK_INVALID`
- `PACKAGE_MISMATCH`
- `ACTIVITY_MISMATCH`
- `TARGET_NOT_FOUND`
- `TARGET_AMBIGUOUS`
- `ACTION_FAILED`
- `VERIFICATION_FAILED`
- `UNSUPPORTED_ON_DEVICE`
结果码的取值与新增规则统一见[结果码总表](actions/README.md#结果码总表)。
## 3. 动作执行规则
+5 -3
View File
@@ -66,9 +66,10 @@
- 步骤线性执行。
- 包名、Activity 或目标控件不匹配时,在 `timeoutMs` 内继续等待。
- 默认要求 selector 只匹配一个节点;多个节点立即返回 `TASK_AMBIGUOUS`。
- 普通失败当前统一返回 `TASK_NOT_MATCHED`。
- 非 optional 步骤失败后停止任务;optional 步骤超时后继续。
- 默认要求 selector 只匹配一个节点;多个节点立即返回 `TARGET_AMBIGUOUS`。
- 失败返回具体原因码:`PACKAGE_MISMATCH`、`ACTIVITY_MISMATCH`、`TARGET_NOT_FOUND`、`TARGET_AMBIGUOUS` 或 `ACTION_FAILED`。
- 步骤在 `timeoutMs` 内没有成功时给出确定结果:非 optional 步骤停止任务并返回对应的原因码,optional 步骤跳过并继续。
- `optional` 只跳过“超时类失败”(上下文不匹配、目标未出现、动作未成功);`TARGET_AMBIGUOUS` 立即停止任务,不受 `optional` 影响。
- 当前只搜索 `rootInActiveWindow`。
已知差距:
@@ -86,6 +87,7 @@
- 默认唯一匹配,不自动选择第一个。
- 所有等待、滚动和重试都有总超时或最大次数。
- 动作结果使用结构化 code,不依赖 message 文本判断流程。
- 是否成功只看 `successful`,成功时 `code` 恒为 `OK`。成功的细节(点击已分发但未验证、App 已在前台等)放在独立的 `detail` 字段,不占用 `code`。
- 页面文字、资源 ID 和成功条件保留在任务或目标 App 适配层。
## 5. 后续扩展
+9 -3
View File
@@ -16,10 +16,11 @@
### 1. 修正现有 v1
- 未知或不适用字段明确报错,不再静默忽略。
- ~~将失败原因从单一 `TASK_NOT_MATCHED` 细分~~ 已完成,见[结果码总表](actions/README.md#结果码总表)。
- 未知或不适用字段明确报错,不再静默忽略。**但这一项与“设备上报能力”是一对,必须一起做或都先不做**:严格校验一旦上线,下发端就必须知道设备支持哪些字段,否则新服务端发给旧设备的任务会整体解析失败,且事先无法预判。设备数量可控、能统一升级时,两件都可以推迟。
- 将“等待目标”和“执行动作”分开;`CLICK`、`INPUT`、`BACK` 不因驱动返回 `false` 而重复分发。
- 将 `TASK_NOT_MATCHED` 逐步细分为包名不符、Activity 不符、目标未找到和动作失败。
- 明确 `optional` 只跳过哪些失败。
- ~~步骤超时必须给出确定结果,不能因轮询唤醒晚于截止时间被记为成功。~~ 已修正,回归测试见 `TaskExecutorTimeoutTest`。
- ~~明确 `optional` 只跳过哪些失败。~~ 已在[任务协议](protocol.md#3-当前执行语义)写明:只跳过超时类失败。
- 查询控件时补充可见、启用和有效边界判断,并正确释放节点。
- 让任务保存返回“新增、重复或失败”,同步统计不再混淆。
@@ -58,6 +59,11 @@
- 真机测试:只覆盖本次涉及的 Android 版本、目标 App 页面和输入法。
- 文档测试:相对链接有效,JSON 示例能解析。
## 已知会推迟的设计
- **设备能力上报**(`schemaVersion`、支持的动作与选择器字段):只在“多台设备版本不一致 + 服务端自动生成任务”时才有价值。与上面的未知字段严格校验绑定。
- **意外弹窗处理**:权限弹窗、更新提示和插屏是真实失败的主因,但当前 `BRANCH`/`GOTO` 只许向前、`onFailure` 不提供重试,缺少全局处理位置。等第一个真实目标 App 跑起来、拿到实际弹窗形态后再设计(预期形态:任务级 `interrupts`,一组“条件 → 一个消除动作”,带单条与全任务触发次数上限,且不重置步骤 `timeoutMs`)。在那之前若用大量 `optional` 步骤穷举兜底,这些任务将来需要重写;成规模出现时就是该做这件事的信号。
## 等外部信息明确后再设计
- 服务端任务接口与结果提交格式。