From c59ea763762aacc289582f5c051884bf8942b67a Mon Sep 17 00:00:00 2001 From: wendel Date: Wed, 5 Aug 2026 16:56:02 +0800 Subject: [PATCH] dfx sdd Signed-off-by: wendel AI[0%] Human Fixed[0%] Human[100%] AI Adopted[0%] Change-Id: Ic1f23d0f0ea9880bae825ec20b8f94db0521e28a --- .../issue-15383-cli-exectool/design.md | 343 ++++++++++ .../execution-plan.md | 626 ++++++++++++++++++ .../issue-15383-cli-exectool/proposal.md | 301 +++++++++ .../changes/issue-15383-cli-exectool/spec.md | 278 ++++++++ 4 files changed, 1548 insertions(+) create mode 100644 .codespec/changes/issue-15383-cli-exectool/design.md create mode 100644 .codespec/changes/issue-15383-cli-exectool/execution-plan.md create mode 100644 .codespec/changes/issue-15383-cli-exectool/proposal.md create mode 100644 .codespec/changes/issue-15383-cli-exectool/spec.md diff --git a/.codespec/changes/issue-15383-cli-exectool/design.md b/.codespec/changes/issue-15383-cli-exectool/design.md new file mode 100644 index 0000000000..3b2c7f7a35 --- /dev/null +++ b/.codespec/changes/issue-15383-cli-exectool/design.md @@ -0,0 +1,343 @@ +# 架构设计 + +> 本设计承接 `proposal.md`(条件通过)与 `spec.md`(Draft),固化 `execTool` 的架构约束、关键设计决策与模块影响。设计 AC ⊆ spec AC,不发明新行为。 + +## 设计元数据 + +| 字段 | 内容 | +|------|-----| +| Design ID | DESIGN-CLI-001 | +| 关联需求 | `proposal.md`(REQ-010) | +| 关联 Epic | 无(独立特性) | +| 目标 Feature | FEAT-CLI-001 | +| 复杂度 | 标准 | +| 目标版本 | OpenHarmony-6.0-Release(待确认) | +| Owner | 待确认 | +| 状态 | Draft | + +## 需求基线 + +> 需求基线详见 proposal.md。以下仅列出设计阶段需额外强调的要点。 + +| 项 | 补充说明 | +|----|----------| +| 仅系统应用 + EXEC_CLI_TOOL | 安全边界由 SA 186 入口统一执行,不在 NAPI 层做权限判定 | +| HAP 沙箱前置 | 沙箱配置由调用方 Token 生成,非 HAP 直接拒绝(35700003) | +| 会话内存态不持久化 | 不涉及 RDB/Preferences,无跨版本数据兼容约束 | + +## 上下文和现状 + +### 涉及仓和模块 + +| 仓库 | 补充架构说明 | +|------|-------------| +| foundation/ability/ability_runtime | 服务层(services/)与 SDK 层(interfaces/kits/)解耦;cli_tool_framework 自成子系统,经 IDL 生成 IPC Stub/Proxy;服务侧依赖 `services/common` 的权限/日志/事件上报设施 | + +### 调用链层级分析 + +| 层 | 模块 | 职责 | 修改类型 | +|----|------|------|----------| +| NAPI | `frameworks/js/napi/cli_tool_manager` | JS↔C++ 绑定:参数解析、同步校验、Promise/异步回调派发 | 修改(既有实现,固化契约) | +| InnerAPI/IPC | `interfaces/cli_tool`(IDL 生成) | `ICliToolManager` Proxy/Stub、`ICliToolManagerScheduler` 回复回调、Parcelable 数据结构 | 修改(既有实现,固化契约) | +| 服务 | `services/climgr` | SA 186 服务端:权限校验、工具查找、参数/schema 校验、沙箱生成、子进程、会话/超时/让出、IO 监控、事件派发 | 修改(既有实现,固化契约) | +| 服务/公共 | `services/common`、`cli_tool_framework/services/common` | 权限工具、HiSysEvent 上报、HiLog 标签 | 不变(复用) | +| SA 注册 | `services/sa_profile/186.json` | SA 186 注册到 samgr(进程 aimgr,库 libclimgr.z.so,ondemand) | 不变 | + +**检查项:** +- [x] 调用链每一层都已覆盖(NAPI→InnerAPI/IPC→服务→SA 注册) +- [x] 每层职责边界清晰,无跨层违规(NAPI 不直接调 services 内部;服务不反向依赖 NAPI) +- [x] 每层修改类型明确 + +### 适用架构规则 + +| Rule ID | 适用原因 | 设计结论 | 验证方式 | +|---------|----------|----------|----------| +| OH-ARCH-LAYERING | NAPI→InnerAPI/IPC→服务 三层调用 | 调用方向自上而下;服务不反向依赖 NAPI;框架层不直接引用 services 内部头文件 | 依赖检查/代码评审 | +| OH-ARCH-SUBSYSTEM | 单子系统 ability 内闭环 | 不跨子系统调用 | 代码评审 | +| OH-ARCH-IPC-SAF | 跨进程经 SA 186 | oneway `ExecTool` + `SchedulerExecToolReplyEvent` 回复;客户端按需拉起 SA | 集成测试 | +| OH-ARCH-API-LEVEL | 新增 System API | System 级、需 `ohos.permission.EXEC_CLI_TOOL`、系统应用限定 | API 评审/XTS | +| OH-ARCH-COMPONENT-BUILD | 复用既有 component/parts | 无新增 component;BUILD.gn 无新增源文件(既有实现固化) | 构建验证 | +| OH-ARCH-ERROR-LOG | 错误码/HiSysEvent | 错误码 357000xx 区间;失败路径上报 bundleName/toolName/failureReason | 单测/hilog/hisysevent | + +## 不涉及项承接 + +| 维度 | 设计结论 | +|------|----------| +| 安全与权限 | 入口在 SA 做「系统应用 + EXEC_CLI_TOOL」双校验;沙箱由调用方 Token 生成,非 HAP 拒绝;失败经 HiSysEvent 上报。详见「安全基础检查」 | +| API/SDK | 新增 System API `execTool`;签名/d.ts/权限见「API 签名、Kit 与权限」 | +| IPC/跨进程 | oneway IPC + Scheduler 回复;客户端 Scheduler Stub 接收回复并派发到 NAPI 异步任务。详见「时序设计」「线程与并发模型」 | + +## 关键设计决策 + +| 决策 ID | 问题 | 推荐方案 | 探索过的替代方案 | 取舍理由 | 影响 | +|---------|------|----------|-----------------|------|------| +| ADR-1 | 执行承载位置 | SA 186(aimgr)集中承载 | 备选1:应用进程内 fork+exec(放弃,绕过权限/沙箱/审计);备选2:独立 SA(放弃,复用 aimgr 进程更内聚) | CLI 执行涉及权限/沙箱/超时/审计,集中到 SA 统一安全边界与并发控制 | 服务端实现集中在 climgr | +| ADR-2 | 调用回复模型 | oneway `ExecTool` + `SchedulerExecToolReplyEvent` 异步回复 | 备选1:同步 IPC 返回(放弃,子进程执行可能超 timeout,同步阻塞 Binder);备选2:客户端轮询 QuerySession(放弃,延迟与功耗差) | 子进程执行时长不定(最长 1800s),同步 IPC 不可行;oneway+回调让回复时机由服务端决定 | IPC 接口为 oneway;客户端须建 Scheduler Stub | +| ADR-3 | 前台长任务返回时机 | yieldMs 让出:定时器到点切后台并派发 reply | 备选1:进程退出才返回(放弃,长任务让调用方长时间无响应);备选2:长轮询(放弃,功耗高) | yield 让调用方在 yieldMs 处拿到 running 会话后可订阅事件,兼顾响应性与长任务 | 引入 yieldMs 参数与 yield 定时器 | +| ADR-4 | 超时实现 | ffrt 延时任务(`PostExecToolTask`) | 备选1:独立 watchdog 线程(放弃,ffrt 已提供延时能力更轻量);备选2:alarm 信号(放弃,精度与可组合性差) | 复用 ffrt 延时任务,与既有调度一致 | 超时/让出各一个延时任务 | +| ADR-5 | 并发控制 | 全局会话表 + 系统配置上限 | 备选1:按调用方限流(放弃,全局资源更需保护);备选2:无上限(放弃,易资源耗尽) | CLI 子进程消耗系统资源,需全局上限保护 | `ValidateSessionLimit` 在入口校验 | + +## 设计骨架 + +### 骨架范围 + +| 骨架项 | 目标 | 不包含 | 验证方式 | +|--------|------|--------|----------| +| API/接口骨架 | `execTool` 签名、ExecOptions/CliSessionInfo/ExecResult 数据模型 | 完整业务逻辑 | 编译 + API 快照 | +| 模块骨架 | NAPI 入口、IDL 接口、climgr 服务类 | 复杂策略调优 | 构建通过 | +| 测试骨架 | exec_tool_param/exec_options/cli_session_info/process_manager 测试 fixture | 全场景 | 最小用例通过 | + +### 骨架 Spec 拆分 + +| Task ID | 目标 | 受影响文件 | AC | +|---------|------|------------|-----| +| TASK-SKELETON-1 | 建立接口/数据结构骨架 | `interfaces/cli_tool/` | WHEN 编译 THEN IDL/Parcelable 生成通过 | + +## 后续 Task 拆分 + +| Task ID | 目标 | 受影响文件 | 依赖 | +|---------|------|------------|------| +| TASK-CLI-001 | 正常执行链路(权限→查找→校验→沙箱→子进程→会话→回复) | `services/climgr/src/cli_tool_manager_service.cpp` 等 | design + spec Approved | +| TASK-CLI-002 | 会话语义(前台/让出/后台)reply 时机 | `cli_tool_manager_service.cpp`、`session_record.cpp` | TASK-CLI-001 | +| TASK-CLI-003 | 超时/让出定时器与终态派发 | `cli_tool_manager_service.cpp`、`process_manager.cpp` | TASK-CLI-002 | +| TASK-CLI-004 | 权限/非 HAP/SA 不可用异常路径 | `cli_tool_manager_service.cpp`、`cli_tool_mgr_client.cpp` | TASK-CLI-001 | +| TASK-CLI-005 | 参数/schema/超时边界校验 | `tool_util.cpp`、`exec_options.cpp` | TASK-CLI-001 | +| TASK-CLI-006 | NAPI 参数同步校验 | `js_cli_manager.cpp` | TASK-CLI-001 | +| TASK-CLI-007 | 会话上限与并发保护 | `cli_tool_manager_service.cpp` | TASK-CLI-001 | +| TASK-CLI-008 | DFX/HiSysEvent 失败上报 | `cli_event_report` | TASK-CLI-004 | + +## API 签名、Kit 与权限 + +### 新增 API + +| API 签名 | 类型 | Kit | d.ts 位置 | 权限要求 | SysCap | +|----------|------|-----|-----------|----------|--------| +| `execTool(toolName: string, subcommand: string, args: object, challenge: string, options?: ExecOptions): Promise` | System | CliToolKit | `cli_tool_framework/interfaces/.../*.d.ts`(待确认) | `ohos.permission.EXEC_CLI_TOOL` + 系统应用 | 待确认 | + +### 变更/废弃 API + +无。 + +## 构建系统影响 + +### BUILD.gn 变更 + +``` +文件路径: cli_tool_framework/interfaces/cli_tool/BUILD.gn +变更说明: 无新增源文件;IDL 接口与 cli_tool_client 库既有,固化契约不改构建。 +``` +``` +文件路径: cli_tool_framework/services/climgr/BUILD.gn +变更说明: 无新增源文件;climgr SA 库既有,固化契约不改构建。 +``` +``` +文件路径: cli_tool_framework/frameworks/js/napi/cli_tool_manager/BUILD.gn +变更说明: 无新增源文件;NAPI 模块既有,固化契约不改构建。 +``` + +### bundle.json 变更 + +无新增 component;复用既有 `ability_runtime` part。若 `ohos.permission.EXEC_CLI_TOOL` 尚未在权限定义仓声明,需在该仓补登记(不在本仓)。 + +--- + +## 可选设计扩展 + +### 架构图 + +``` +[系统应用/NAPI execTool] → [cli_tool_client Proxy] →(IPC oneway)→ [SA 186 climgr ExecTool] + ↑ SchedulerExecToolReplyEvent 回复 ↓ + └── [NapiAsyncTask Resolve/Reject] ← [cli_tool_mgr_scheduler_recipient] [ProcessManager 创建沙箱子进程] + ↓ + [IOMonitor 监控 stdout/stderr/stdin] + ↓ + [EventDispatcher 派发 IO/Exit/Error 事件] +``` + +### 数据流/控制流 + +| 步骤 | 调用方 | 被调用方 | 数据/接口 | 说明 | +|------|--------|----------|-----------|------| +| 1 | NAPI | cli_tool_client | `ExecTool(param, callback)` | 解析参数建 ExecToolParam | +| 2 | cli_tool_client | SA 186 | `ICliToolManager::ExecTool`(oneway) | 拉起 SA(按需)并 IPC | +| 3 | SA 186 | PermissionUtil | VerifyAccessToken | 系统应用 + EXEC_CLI_TOOL | +| 4 | SA 186 | CliToolDataManager | GetToolByName | 工具查找 | +| 5 | SA 186 | ToolUtil | ValidateProperties/GenerateSandboxConfig | schema 校验 + 沙箱 | +| 6 | SA 186 | ProcessManager | CreateChildProcess | fork 沙箱子进程 | +| 7 | SA 186 | IOMonitor | RegisterSession | 监控管道 + 调度 yield/timeout 定时器 | +| 8 | SA 186 | EventDispatcher | DispatchExecToolReplyEvent | 经 Scheduler 回复 | +| 9 | cli_tool_client | NapiAsyncTask | Resolve/Reject | 派发到 JS Promise | + +### 时序设计 + +```mermaid +sequenceDiagram + participant App as 系统应用(NAPI) + participant Client as cli_tool_client + participant SA as SA 186 climgr + participant Proc as 子进程 + App->>Client: execTool(param) + Client->>SA: ExecTool(param,eventId,scheduler) [oneway] + SA->>SA: 权限+查找+校验+沙箱 + SA->>Proc: CreateChildProcess(fork) + SA->>SA: RegisterSessionWithMonitors(yield/timeout 定时器) + alt background=true + SA-->>Client: SchedulerExecToolReplyEvent(running) + else foreground yieldMs>0 + SA-->>Client: SchedulerExecToolReplyEvent(running) @yieldMs + else foreground no-yield + Proc-->>SA: 退出+输出排空 + SA-->>Client: SchedulerExecToolReplyEvent(completed/failed) + end + Client-->>App: Promise resolve(CliSessionInfo) +``` + +### 算法与状态机 + +```mermaid +stateDiagram-v2 + [*] --> SPAWNING: CreateChildProcess + SPAWNING --> RUNNING: 子进程创建成功+会话登记 + RUNNING --> CANCELLING: timeout/kill/clear + RUNNING --> COMPLETED: 进程退出+输出排空 + RUNNING --> FAILED: 非零退出/异常 + CANCELLING --> COMPLETED: 清理完成 + CANCELLING --> FAILED: 清理完成 + COMPLETED --> [*] + FAILED --> [*] +``` + +> CliSessionInfo.status 字符串映射:RUNNING→"running"、COMPLETED→"completed"、FAILED→"failed"。 + +### 测试性设计 + +| 测试层级 | 测试目标 | Mock 策略 | 验证方式 | +|----------|----------|-----------|----------| +| 单元测试 | Parcelable 编解码、参数/schema 校验、超时边界 | Mock 服务端 | `exec_tool_param_test`/`exec_options_test`/`tool_util_test` | +| 单元测试 | 客户端错误码与回复派发 | Mock `ICliToolManager`/`Scheduler` | `cli_tool_mgr_client_test`/`cli_tool_mgr_scheduler_recipient_test` | +| 集成测试 | 正常执行链路、会话语义、超时/让出 | 真实 SA + 测试工具 | `process_manager_test`/`cli_tool_mgr_service_test` | +| 集成测试 | 子进程创建与管道 | 真实 fork | `process_manager_test` | + +### 异常传播时序图 + +```mermaid +sequenceDiagram + participant App as 应用层 + participant FW as cli_tool_client + participant SA as SA 186 + App->>FW: execTool(param) + FW->>SA: ExecTool [oneway] + alt 权限/非系统/非HAP/上限/工具不存在/参数非法 + SA-->>FW: SchedulerExecToolReplyEvent(错误码) + FW-->>App: Promise reject(错误码) + else SA 不可用 + FW-->>App: Promise reject(35700000) + else 超时 + SA->>SA: HandleProcessTimeout(kill) + SA-->>FW: SchedulerExecToolReplyEvent(timeout) + SA-->>App: DispatchErrorEvent("session timed out") + end +``` + +| 异常场景 | 触发层 | 传播路径 | 最终处理 | +|----------|--------|----------|----------| +| 非系统应用/缺权限 | SA 入口 | SA→Scheduler→NAPI | reject 35700008/35700007 | +| 非 HAP | SA 沙箱生成 | SA→Scheduler→NAPI | reject 35700003 | +| 工具/子命令不存在 | SA 查找 | SA→Scheduler→NAPI | reject 35700005 | +| schema/参数非法 | SA 校验 | SA→Scheduler→NAPI | reject 35700002 | +| 会话上限 | SA 入口 | SA→Scheduler→NAPI | reject 35700001 | +| 超时 | SA 定时器 | SA kill→Scheduler→NAPI + ErrorEvent | reject/终态 + 错误事件 | +| SA 不可用 | 客户端 | cli_tool_client→NAPI | reject 35700000 | + +### 资源所有权矩阵 + +| 资源 | 创建方 | 持有方 | 销毁触发 | 实际释放 | 异常回收 | +|------|--------|--------|----------|----------|----------| +| 子进程 | ProcessManager | SessionRecord | 进程退出/超时/clear | Killpg + reap | 超时定时器 kill | +| 管道 fd(stdin/stdout/stderr) | ProcessManager | SessionRecord | 输出排空/会话清理 | close | IOMonitor 注销 + close | +| 会话记录 | SA | sessions_ 表 | 终态派发后 | RemoveSessionRecord | 超时/清理路径兜底移除 | +| Scheduler Stub | cli_tool_client | client 单例 | DeathRecipient | ClearProxy | 进程死亡清代理 | +| yield/timeout 定时器 | SA(IOMonitor 注册) | ffrt | 触发或会话清理 | ffrt 任务完成 | 会话清理时不取消(幂等检查 record 存在性) | + +### 接口参数规约 + +| 接口 | 参数 | 类型 | 合法范围 | 非法处理 | 边界说明 | +|------|------|------|----------|----------|----------| +| execTool | toolName | string | 非空 + 已注册 | 空/非串→同步抛错;未注册→reject 35700005 | — | +| execTool | subcommand | string | 可空串 + 工具子命令表内 | 非空但工具无子命令/不在表→reject 35700005 | 空串用工具顶层 inputSchema | +| execTool | args | object | 键须在 inputSchema.properties 内且类型匹配 | 含未声明键/类型不符→reject 35700002 | 空对象合法;`help` 须单独存在 | +| execTool | challenge | string | 非空 | 空/非串→同步抛错 | — | +| ExecOptions | background | boolean | true/false | — | 默认 false | +| ExecOptions | yieldMs | int64 | ≥0;非后台须 ≤ timeout*1000 | <0 或越界→reject 35700002 | 默认 0;仅前台生效 | +| ExecOptions | timeout | int64 | ∈[0,1800] 秒 | <0 或 >1800→reject 35700002 | 默认 0=不启用;timeoutMs=timeout*1000 | + +### 线程与并发模型 + +| 操作 | 发起线程 | 回调线程 | 跨进程边界 | 线程安全 | 重入约束 | +|------|----------|----------|------------|----------|----------| +| execTool(NAPI) | JS 主线程 | NapiAsyncTask(JsCliEventHandlerManager 投递) | 是(IPC) | NAPI 异步任务串行化 | 允许并发调用 | +| SA ExecTool | Binder 线程 | ffrt 定时器线程 | 是 | sessions_ 表 ffrt::mutex 保护 | 允许并发会话 | +| IOMonitor 回调 | IOMonitor 线程 | 同 | 否(进程内) | SessionRecord 原子状态 + mutex | 幂等:record 不存在即跳过 | + +**并发场景:** + +| 场景 | 竞争对象 | 保护机制 | 预期行为 | +|------|----------|----------|----------| +| 多调用方并发创建会话 | sessions_ 表 | sessionsMutex_ 互斥 + 上限校验 | 超限拒绝 35700001 | +| 超时与正常退出竞争 | SessionRecord 状态 | 原子状态 + BeginCleanup 单次进入 | 仅一方完成终态派发 | +| 回调与代理死亡竞争 | Scheduler 代理 | DeathRecipient + mutex | 代理死亡不清会话,仅清代理 | + +### 安全基础检查 + +> proposal「安全与权限」= 是,本节必填。 + +#### 信任边界交叉分析 + +| 边界类型 | 跨越的交互 | 风险 | 约束 | +|---|---|---|---| +| 用户态/内核态 | fork 子进程、pipe 读写 | 子进程越权 | 子进程运行在调用方 HAP 沙箱;SA 持 caps=KILL 可终止 | +| 沙箱内外 | 子进程 vs SA(aimgr) 进程 | 跨沙箱数据泄漏 | 沙箱配置按调用方 Token 生成;stdin/stdout/stderr 经管道受控 | +| 本地/远程 | NAPI→IPC→SA 全本地 | 无远程暴露 | 仅本机系统应用可调 | +| 不同 SELinux 域 | aimgr 域 vs 子进程域 | 域切换 | SA 域 aimgr;子进程域由沙箱配置决定 | + +#### 基础安全要求 + +| 检查项 | 结论 | 说明/措施 | +|---|---|---| +| 加密算法(OH 推荐) | N/A | execTool 不涉及加密 | +| 密钥管理 | N/A | 不涉及密钥 | +| 随机数 | sessionId 生成 | 由 ToolUtil::GenerateCliSessionId 生成,不要求密码学随机 | +| 输入验证 | 强制 | toolName/subcommand/schema/timeout/yieldMs 全链路校验,非法即拒绝 | +| 错误处理 | 错误码化 | 357000xx 区间,不泄漏内部栈 | +| 配置 | 系统配置 | 并发上限由系统配置,非调用方可控 | +| 敏感数据处理(传输/存储/日志) | 不存储敏感数据 | 会话内存态;日志不打印 args 明文(args 仅 Key 校验) | + +### 深度威胁分析(如需) + +> 命中高风险判据评估:execTool 涉及沙箱/子进程/权限,但无网络暴露、无认证授权(仅本机系统应用+权限)、无敏感数据存储、无合规强约束。判定为不升级独立 threat-model.md。如 Owner 复核认为子进程沙箱逃逸风险需深入,再由 `ohos-security-threat-model` 产出。 + +## 风险和开放问题 + +| 项 | 类型 | 影响 | 处理方式 | Owner | +|----|------|------|----------|-------| +| 目标版本/Owner 未确认 | 进度 | 基线无法冻结为「通过」 | 需求方/SIG 确认 | 待确认 | +| d.ts 位置/SysCap 未确认 | API | 影响 @since 与 SysCap 声明 | API 评审 | 待确认 | +| `ohos.permission.EXEC_CLI_TOOL` 权限登记仓 | 构建 | 权限须在定义仓声明 | 跨仓协调 | 待确认 | +| yield/timeout 定时器在会话清理后触发 | 可靠性 | 幂等检查 record 存在性,已缓解 | 代码评审 + 单测 | — | + +## 设计审批 + +- [x] 需求基线已确认,设计覆盖 P0/P1 AC(AC-1.1–1.15) +- [x] 不涉及项已承接,N/A 和展开项都有结论 +- [x] 涉及仓和模块职责清楚 +- [x] 调用链层级分析完整,每层覆盖到位 +- [x] 适用架构规则已识别并形成设计结论 +- [x] 分层和子系统边界合规 +- [x] API 变更有签名、权限、错误码和兼容性说明 +- [x] BUILD.gn/bundle.json 影响明确(无新增源文件,固化契约) +- [x] 设计输出和后续 Task 拆分明确 +- [x] 关键设计决策有理由和影响说明 +- [x] 风险和开放问题有 Owner(部分待确认) + +**结论:** 条件通过(待 Owner 复核后转「通过」) diff --git a/.codespec/changes/issue-15383-cli-exectool/execution-plan.md b/.codespec/changes/issue-15383-cli-exectool/execution-plan.md new file mode 100644 index 0000000000..1c639c3718 --- /dev/null +++ b/.codespec/changes/issue-15383-cli-exectool/execution-plan.md @@ -0,0 +1,626 @@ +# 执行计划 + +> 将 Approved Spec 拆成可独立执行、可验证、可审查的 Task。本计划针对 `execTool` 既有实现进行契约固化与测试覆盖验证:实现已存在,Task 聚焦「验证既有链路符合 spec + 补齐测试缺口 + 跨仓协调」。 + +## Plan 元数据 + +| 字段 | 内容 | +|------|-----| +| Plan ID | PLAN-CLI-001 | +| 关联 Feature/Bug | FEAT-CLI-001(REQ-010) | +| 关联文档 | proposal.md / design.md / spec.md | +| 复杂度 | 标准 | +| 状态 | Draft | +| Owner | 待确认 | + +## 输入状态 + +| 输入 | 路径 | 要求状态 | +|------|------|----------| +| Requirement | `proposal.md` | Approved(条件通过,待 Owner 转正) | +| Design | `design.md` | Approved(条件通过,待 Owner 转正) | +| Spec | `spec.md` | Approved(Draft→待转 Approved) | + +## 受影响文件全量清单 + +| 仓 | 层(来自 design.md) | 文件路径 | 修改类型 | 说明 | +|----|---------------------|----------|----------|------| +| ability_runtime | NAPI | `cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp` | 验证/补测试 | `execTool`/`OnExecTool` 参数解析与回调 | +| ability_runtime | NAPI | `cli_tool_framework/frameworks/js/napi/cli_tool_manager/include/js_cli_manager.h` | 只读参考 | 声明 | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl` | 只读参考 | `ExecTool` oneway 声明 | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/ICliToolManagerScheduler.idl` | 只读参考 | `SchedulerExecToolReplyEvent` 回复 | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/include/exec_tool_param.h` | 验证 | ExecToolParam Parcelable | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/include/exec_options.h` | 验证 | ExecOptions | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/include/cli_session_info.h` | 验证 | CliSessionInfo | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/include/exec_result.h` | 验证 | ExecResult | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/include/cli_error_code.h` | 验证 | 错误码 357000xx | +| ability_runtime | InnerAPI/IPC | `cli_tool_framework/interfaces/cli_tool/src/cli_tool_mgr_client.cpp` | 验证 | 客户端 ExecTool + SA 拉起 | +| ability_runtime | 服务 | `cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp` | 验证 | 服务端 ExecTool 全链路 | +| ability_runtime | 服务 | `cli_tool_framework/services/climgr/src/tool_util.cpp` | 验证 | 参数/schema/沙箱校验 | +| ability_runtime | 服务 | `cli_tool_framework/services/climgr/src/process_manager.cpp` | 验证 | 子进程创建 | +| ability_runtime | 服务 | `cli_tool_framework/services/climgr/src/session_record.cpp` | 验证 | 会话状态机 | +| ability_runtime | 服务 | `cli_tool_framework/services/climgr/src/event_dispatcher.cpp` | 验证 | 事件/回复派发 | +| ability_runtime | DFX | `cli_tool_framework/services/common/src/cli_event_report*.cpp` | 验证 | HiSysEvent 上报 | +| ability_runtime | SA | `services/sa_profile/186.json` | 只读参考 | SA 186 注册 | +| ability_runtime | 配置 | `cli_tool_framework/etc/profile/aimgr.cfg` | 只读参考 | 进程/权限/caps | +| 跨仓(权限定义仓) | 权限 | `ohos.permission.EXEC_CLI_TOOL` 定义 | 跨仓协调 | 权限登记(不在本仓) | + +**检查项:** +- [x] design.md 调用链每一层都有对应文件列出 +- [x] 每个文件修改类型和职责说明明确 +- [x] 无映射行的层缺失 + +## AC 到 Task 追溯 + +| AC | 来源 | Task | 验证方式 | 覆盖? | +|----|------|------|----------|--------| +| AC-1.1 | spec.md | TASK-CLI-001 | 集成 | 是 | +| AC-1.2 | spec.md | TASK-CLI-002 | 集成 | 是 | +| AC-1.3 | spec.md | TASK-CLI-002 | 集成 | 是 | +| AC-1.4 | spec.md | TASK-CLI-003 | 集成 | 是 | +| AC-1.5 | spec.md | TASK-CLI-004 | 单测 | 是 | +| AC-1.6 | spec.md | TASK-CLI-004 | 单测 | 是 | +| AC-1.7 | spec.md | TASK-CLI-005 | 单测 | 是 | +| AC-1.8 | spec.md | TASK-CLI-005 | 单测 | 是 | +| AC-1.9 | spec.md | TASK-CLI-005 | 单测 | 是 | +| AC-1.10 | spec.md | TASK-CLI-005 | 单测 | 是 | +| AC-1.11 | spec.md | TASK-CLI-005 | 单测 | 是 | +| AC-1.12 | spec.md | TASK-CLI-006 | 单测 | 是 | +| AC-1.13 | spec.md | TASK-CLI-007 | 集成 | 是 | +| AC-1.14 | spec.md | TASK-CLI-004 | 集成 | 是 | +| AC-1.15 | spec.md | TASK-CLI-008 | 单测 | 是 | + +## 首批实现边界 + +**首批必须实现:** TASK-CLI-001(正常链路)+ TASK-CLI-005(参数/边界校验)+ TASK-CLI-004(权限/非HAP),构成主链与安全边界。 +**可后置:** TASK-CLI-008(DFX 跨仓协调)。 +**不建议延后:** TASK-CLI-002/003(会话语义/超时)延后会导致主链行为不闭合。 + +## 阶段计划(如适用) + +| 阶段 | 目标 | 关键 Task | 结束门槛 | 最小验证 | +|------|------|-----------|----------|----------| +| Phase-1 | 主链+安全+参数 | TASK-CLI-001,004,005,006 | 正常执行与异常路径单测通过 | `run -t UT -ts cli_tool_mgr_client_test` | +| Phase-2 | 会话语义+超时+并发 | TASK-CLI-002,003,007 | yield/background/timeout/上限验证通过 | `run -t UT -ts process_manager_test` | +| Phase-3 | DFX+SA 不可用 | TASK-CLI-008 | 失败上报与 SA 不可用覆盖 | `run -t UT -ts cli_event_report_test` | + +## Task 粒度原则 + +- 每个 Task 对应一个可独立验收的最小能力闭环 +- 文件范围、验证闭环和风险边界足够分离 → 拆分 +- 简单变更:1-2 张 Task Card;本计划按主链/会话/超时/权限/参数/NAPI/并发/DFX 拆为 8 张 +- 每个 Task 自包含,不依赖外部文件路径引用 + +## 禁止项 + +- [x] 没有 TBD / TODO / 占位符(「待确认」为需 Owner 决议项,非规格占位) +- [x] 没有"根据需要实现""酌情处理"等模糊指令 +- [x] 没有跨 Task 隐式依赖(依赖显式声明在前置依赖列) +- [x] 没有要求 Agent 自行寻找未列出的上下文文件 +- [x] 没有无验证方式的 AC +- [x] 没有"与 Task-N 类似""参考 Task-N 实现"等引用 + +## Task 列表 + +| Task ID | 目标 | 文件范围 | AC 映射 | 前置依赖 | 完成判据 | 验证命令 | +|---------|------|----------|---------|----------|----------|----------| +| TASK-CLI-001 | 正常执行链路契约验证 | climgr/cli_tool_mgr_client | AC-1.1 | 无 | 正常调用返回 completed 会话与退出码 | `run -t UT -ts cli_tool_mgr_service_test` | +| TASK-CLI-002 | 前台让出/后台会话语义验证 | cli_tool_manager_service/session_record | AC-1.2,AC-1.3 | TASK-CLI-001 | yieldMs 与 background reply 时机/状态正确 | `run -t UT -ts cli_tool_mgr_service_test` | +| TASK-CLI-003 | 超时终止与终态派发验证 | cli_tool_manager_service/process_manager | AC-1.4 | TASK-CLI-002 | timeout 触发 kill+timeout=true+错误事件 | `run -t UT -ts process_manager_test` | +| TASK-CLI-004 | 权限/非HAP异常路径验证 | cli_tool_manager_service/cli_tool_mgr_client | AC-1.5,AC-1.6,AC-1.14 | TASK-CLI-001 | 非系统/缺权限/非HAP 返回正确码 | `run -t UT -ts cli_tool_mgr_client_test` | +| TASK-CLI-005 | 工具/子命令/schema/超时边界校验验证 | tool_util/exec_options/exec_tool_param | AC-1.7–1.11 | TASK-CLI-001 | 各非法输入返回 35700005/35700002 | `run -t UT -ts tool_util_test` | +| TASK-CLI-006 | NAPI 参数同步校验验证 | js_cli_manager | AC-1.12 | TASK-CLI-001 | 必填缺失/类型错/argc<4 同步抛错 | `run -t UT -ts cli_tool_mgr_client_test` | +| TASK-CLI-007 | 会话并发上限验证 | cli_tool_manager_service | AC-1.13 | TASK-CLI-001 | 超上限返回 35700001 | `run -t UT -ts cli_tool_mgr_service_test` | +| TASK-CLI-008 | DFX 失败上报 + SA 不可用验证 | cli_event_report/cli_tool_mgr_client | AC-1.15 | TASK-CLI-004 | SA 不可用返回 35700000;失败经 HiSysEvent | `run -t UT -ts cli_event_report_test` | + +## Task 详情 + +### TASK-CLI-001: 正常执行链路契约验证 + +| 字段 | 内容 | +|------|-----| +| 任务目标 | 验证既有 execTool 正常链路符合 spec AC-1.1:合法调用返回 completed 会话与退出码 | +| AC 映射 | AC-1.1 | +| 前置依赖 | 无 | +| 非目标 | 不验证 yield/background/timeout(属 TASK-CLI-002/003) | +| 完成判据 | 集成测试覆盖:合法 toolName+subcommand+args+challenge→resolve status="completed",result.exitCode=进程退出码 | +| 停止条件 | 发现既有实现与 spec 行为不一致且无法在 Task 范围内修复 | + +**Files** + +| 操作 | 文件 | 说明 | +|------|------|------| +| Test | `cli_tool_framework/test/unittest/cli_tool_mgr_service_test/` | 正常链路用例 | +| Test | `cli_tool_framework/test/unittest/process_manager_test/` | 子进程创建用例 | + +**Spec Context** + +AC-1.1:WHEN 系统应用持 EXEC_CLI_TOOL 调用 execTool,传入已注册 toolName、工具支持 subcommand、符合 inputSchema 的 args、非空 challenge THEN 接口返回 Promise,工具执行结束后 resolve 为 CliSessionInfo(status="completed",result.exitCode 等于子进程退出码)。 + +R-1:合法输入→创建会话与受沙箱子进程执行工具,结束后 resolve CliSessionInfo{status="completed", result.exitCode=进程退出码, outputText, errorText, executionTime}。 + +**Design Context** + +调用链:NAPI→cli_tool_client Proxy→SA 186 ExecTool(oneway)→权限/查找/校验/沙箱→ProcessManager.CreateChildProcess→IOMonitor.RegisterSession→EventDispatcher.DispatchExecToolReplyEvent→client Scheduler Stub→NapiAsyncTask.Resolve。设计 ADR-1(SA 集中承载)、ADR-2(oneway+回调)。 + +**Required Rules** + +| Rule ID | Must / Must Not | +|---------|-----------------| +| OH-ARCH-LAYERING | Must:NAPI 不直接调 services 内部;经 InnerAPI/IPC | +| OH-ARCH-IPC-SAF | Must:ExecTool 为 oneway;回复经 Scheduler | + +**Steps** + +- [ ] 写失败测试:合法调用断言 resolve completed + exitCode +- [ ] 运行测试,确认当前结果 +- [ ] 若不一致,做最小实现修正 +- [ ] 运行测试,确认通过 +- [ ] 填写完成证据 + +**Completion Evidence** + +| 证据类型 | 命令/路径 | 结果 | +|----------|-----------|------| +| 测试 | `run -t UT -ts cli_tool_mgr_service_test` | PASS | +| 测试 | `run -t UT -ts process_manager_test` | PASS | + +**Handoff Summary** + +| 项 | 内容 | +|----|------| +| 任务描述 | 验证 execTool 正常链路返回 completed 会话与退出码(AC-1.1) | +| 允许修改 | `cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp`、`cli_tool_framework/test/unittest/cli_tool_mgr_service_test/` | +| 允许新建 | 测试用例文件 | +| 只读参考 | `spec.md` AC-1.1、`design.md` ADR-1/ADR-2、`ICliToolManager.idl` | +| Spec 摘要 | AC-1.1 + R-1:合法输入→completed 会话+exitCode | +| Design 摘要 | NAPI→IPC→SA oneway+Scheduler 回复;ProcessManager.CreateChildProcess | +| 执行步骤 | 写失败测试→运行→最小修正→运行通过→记录证据 | +| 验证命令 | `run -t UT -ts cli_tool_mgr_service_test` / 期望: PASS | +| 完成规则 | 不得修改允许范围外文件;如需扩大范围停止并修订 Plan;无 fresh evidence 不得声明完成 | + +### TASK-CLI-002: 前台让出/后台会话语义验证 + +| 字段 | 内容 | +|------|-----| +| 任务目标 | 验证 yieldMs 让出与 background 立即返回的 reply 时机与 status 符合 AC-1.2/AC-1.3 | +| AC 映射 | AC-1.2, AC-1.3 | +| 前置依赖 | TASK-CLI-001 | +| 非目标 | 不验证超时终止(TASK-CLI-003) | +| 完成判据 | background=true 立即 resolve running;foreground+yieldMs>0 在 yieldMs 处 resolve running 且转后台 | +| 停止条件 | 定时器或状态机行为与 spec 不一致且超范围 | + +**Files** + +| 操作 | 文件 | 说明 | +|------|------|------| +| Test | `cli_tool_framework/test/unittest/cli_tool_mgr_service_test/` | 会话语义用例 | +| Test | `cli_tool_framework/test/unittest/session_record_test/` | 状态机用例 | + +**Spec Context** + +AC-1.2:WHEN background=false 且 yieldMs>0 THEN 在 yieldMs 毫秒后 resolve 为 status="running",会话转后台继续运行。 +AC-1.3:WHEN background=true THEN 立即 resolve 为 status="running"。 +R-2/R-3:yield 让出、background 立即返回。 + +**Design Context** + +RegisterSessionWithMonitors:非 background 且 yieldMs!=0 → PostExecToolTask(yieldMs, isTimeout=false);background → HandleBackgroundSessionReply 立即派发。HandleProcessYieldTimeout 切后台并派发 running。状态机 SPAWNING→RUNNING→CANCELLING/COMPLETED/FAILED。设计 ADR-3。 + +**Required Rules** + +| Rule ID | Must / Must Not | +|---------|-----------------| +| OH-ARCH-IPC-SAF | Must:回复经 SchedulerExecToolReplyEvent | + +**Steps** + +- [ ] 写失败测试:background 立即返回 + yieldMs 让出时机 +- [ ] 运行测试 +- [ ] 最小修正 +- [ ] 运行通过 +- [ ] 记录证据 + +**Completion Evidence** + +| 证据类型 | 命令/路径 | 结果 | +|----------|-----------|------| +| 测试 | `run -t UT -ts cli_tool_mgr_service_test` | PASS | +| 测试 | `run -t UT -ts session_record_test` | PASS | + +**Handoff Summary** + +| 项 | 内容 | +|----|------| +| 任务描述 | 验证 yield 让出与 background 立即返回语义(AC-1.2/1.3) | +| 允许修改 | `cli_tool_manager_service.cpp`、`session_record.cpp`、对应测试 | +| 允许新建 | 测试用例 | +| 只读参考 | spec AC-1.2/1.3、design ADR-3、`session_record.h` 状态枚举 | +| Spec 摘要 | AC-1.2/1.3 + R-2/R-3 | +| Design 摘要 | RegisterSessionWithMonitors 调度 yield;HandleBackgroundSessionReply/HandleProcessYieldTimeout | +| 执行步骤 | 写失败测试→运行→修正→通过→证据 | +| 验证命令 | `run -t UT -ts cli_tool_mgr_service_test` / 期望: PASS | +| 完成规则 | 不改范围外文件;无 evidence 不声明完成 | + +### TASK-CLI-003: 超时终止与终态派发验证 + +| 字段 | 内容 | +|------|-----| +| 任务目标 | 验证 timeout 秒后进程被终止、result.timeout=true、派发超时错误事件(AC-1.4) | +| AC 映射 | AC-1.4 | +| 前置依赖 | TASK-CLI-002 | +| 非目标 | 不验证正常完成路径 | +| 完成判据 | 进程达 timeout 被 kill,终态 result.timeout=true,订阅者收到 "session timed out" 错误事件 | +| 停止条件 | kill/定时器逻辑与 spec 不一致且超范围 | + +**Files** + +| 操作 | 文件 | 说明 | +|------|------|------| +| Test | `cli_tool_framework/test/unittest/process_manager_test/` | 超时/kill 用例 | + +**Spec Context** + +AC-1.4:WHEN 进程运行达 options.timeout 秒 THEN 进程被终止、result.timeout=true,并向订阅者派发超时错误事件。 +R-4:timeout>0 达阈值→终止、timeout=true、错误事件;未后台则派发终态 reply。 + +**Design Context** + +PostExecToolTask(timeoutMs, isTimeout=true) → HandleProcessTimeout:SetTimeout(true)、SetState(CANCELLING)、DispatchExecToolReplyEvent(未后台)、DispatchErrorEvent("session timed out")、ProcessManager.Killpg。设计 ADR-4(ffrt 延时)。 + +**Required Rules** + +| Rule ID | Must / Must Not | +|---------|-----------------| +| OH-ARCH-ERROR-LOG | Must:超时经 HiSysEvent ReportCliTimeout 上报 | + +**Steps** + +- [ ] 写失败测试:timeout 触发 kill + timeout=true + 错误事件 +- [ ] 运行测试 +- [ ] 最小修正 +- [ ] 运行通过 +- [ ] 记录证据 + +**Completion Evidence** + +| 证据类型 | 命令/路径 | 结果 | +|----------|-----------|------| +| 测试 | `run -t UT -ts process_manager_test` | PASS | + +**Handoff Summary** + +| 项 | 内容 | +|----|------| +| 任务描述 | 验证超时终止与终态派发(AC-1.4) | +| 允许修改 | `cli_tool_manager_service.cpp`、`process_manager.cpp`、对应测试 | +| 允许新建 | 测试用例 | +| 只读参考 | spec AC-1.4 + R-4、design ADR-4 | +| Spec 摘要 | AC-1.4:timeout→kill+timeout=true+错误事件 | +| Design 摘要 | HandleProcessTimeout + Killpg + ffrt 延时任务 | +| 执行步骤 | 写失败测试→运行→修正→通过→证据 | +| 验证命令 | `run -t UT -ts process_manager_test` / 期望: PASS | +| 完成规则 | 不改范围外文件;无 evidence 不声明完成 | + +### TASK-CLI-004: 权限/非HAP异常路径验证 + +| 字段 | 内容 | +|------|-----| +| 任务目标 | 验证非系统应用、缺权限、非 HAP 调用分别返回 35700008/35700007/35700003(AC-1.5/1.6/1.14) | +| AC 映射 | AC-1.5, AC-1.6, AC-1.14 | +| 前置依赖 | TASK-CLI-001 | +| 非目标 | 不验证工具不存在/参数非法(TASK-CLI-005) | +| 完成判据 | 三类调用方均被正确拒绝并返回对应错误码,失败经 HiSysEvent 上报 | +| 停止条件 | 权限/沙箱判定与 spec 不一致 | + +**Files** + +| 操作 | 文件 | 说明 | +|------|------|------| +| Test | `cli_tool_framework/test/unittest/cli_tool_mgr_client_test/` | 权限/非HAP 用例 | + +**Spec Context** + +AC-1.5:非系统应用→reject 35700008。AC-1.6:缺权限→reject 35700007。AC-1.14:非 HAP→reject 35700003。 +R-5/R-11。 + +**Design Context** + +ValidateExecToolPermissions:IsSystemAppByFullTokenID→ERR_NOT_SYSTEM_APP;VerifyAccessToken(EXEC_CLI_TOOL)→ERR_PERMISSION_DENIED。ValidateAndPrepareTool→GenerateSandboxConfig 失败→ERR_NOT_HAP。ReportCliExecuteFailed 上报。设计「安全基础检查」信任边界。 + +**Required Rules** + +| Rule ID | Must / Must Not | +|---------|-----------------| +| OH-ARCH-API-LEVEL | Must:System API + 系统应用 + EXEC_CLI_TOOL | +| OH-ARCH-ERROR-LOG | Must:失败经 HiSysEvent | + +**Steps** + +- [ ] 写失败测试:三类调用方断言对应错误码 +- [ ] 运行测试 +- [ ] 最小修正 +- [ ] 运行通过 +- [ ] 记录证据 + +**Completion Evidence** + +| 证据类型 | 命令/路径 | 结果 | +|----------|-----------|------| +| 测试 | `run -t UT -ts cli_tool_mgr_client_test` | PASS | + +**Handoff Summary** + +| 项 | 内容 | +|----|------| +| 任务描述 | 验证权限/非HAP 异常路径错误码(AC-1.5/1.6/1.14) | +| 允许修改 | `cli_tool_manager_service.cpp`、`cli_tool_mgr_client.cpp`、对应测试 | +| 允许新建 | 测试用例 | +| 只读参考 | spec AC-1.5/1.6/1.14 + R-5/R-11、design 安全基础检查 | +| Spec 摘要 | 非系统→35700008;缺权限→35700007;非HAP→35700003 | +| Design 摘要 | ValidateExecToolPermissions + GenerateSandboxConfig + ReportCliExecuteFailed | +| 执行步骤 | 写失败测试→运行→修正→通过→证据 | +| 验证命令 | `run -t UT -ts cli_tool_mgr_client_test` / 期望: PASS | +| 完成规则 | 不改范围外文件;无 evidence 不声明完成 | + +### TASK-CLI-005: 工具/子命令/schema/超时边界校验验证 + +| 字段 | 内容 | +|------|-----| +| 任务目标 | 验证工具/子命令不存在、schema 不匹配、timeout/yieldMs 越界返回 35700005/35700002(AC-1.7–1.11) | +| AC 映射 | AC-1.7, AC-1.8, AC-1.9, AC-1.10, AC-1.11 | +| 前置依赖 | TASK-CLI-001 | +| 非目标 | 不验证权限路径(TASK-CLI-004) | +| 完成判据 | 各非法输入返回正确错误码;空 args 合法;help 特殊键放行 | +| 停止条件 | 校验逻辑与 spec 不一致 | + +**Files** + +| 操作 | 文件 | 说明 | +|------|------|------| +| Test | `cli_tool_framework/test/unittest/tool_util_test/` | 工具/schema 校验 | +| Test | `cli_tool_framework/test/unittest/exec_options_test/` | timeout/yieldMs 边界 | +| Test | `cli_tool_framework/test/unittest/exec_tool_param_test/` | Parcelable + schema | + +**Spec Context** + +AC-1.7:toolName 未注册→35700005。AC-1.8:subcommand 非法→35700005。AC-1.9:args 不符 schema→35700002。AC-1.10:timeout<0 或 >1800→35700002。AC-1.11:非后台 yieldMs>timeout*1000→35700002。 +R-6/R-7/R-8。 + +**Design Context** + +ValidateProperties:subcommand 非空但工具无子命令/不在表→ERR_TOOL_NOT_EXIST。ValidateExecOptionsProperties:timeout<0/yieldMs<0/timeout>1800/yieldMs>timeout*1000→ERR_INVALID_PARAM。ValidateInputSchemaProperties:args 键须在 properties 且类型匹配;help 单独放行;空 args 合法。接口参数规约表。 + +**Required Rules** + +| Rule ID | Must / Must Not | +|---------|-----------------| +| OH-ARCH-ERROR-LOG | Must:错误码 35700005/35700002 | + +**Steps** + +- [ ] 写失败测试:各非法输入断言错误码 +- [ ] 运行测试 +- [ ] 最小修正 +- [ ] 运行通过 +- [ ] 记录证据 + +**Completion Evidence** + +| 证据类型 | 命令/路径 | 结果 | +|----------|-----------|------| +| 测试 | `run -t UT -ts tool_util_test` | PASS | +| 测试 | `run -t UT -ts exec_options_test` | PASS | +| 测试 | `run -t UT -ts exec_tool_param_test` | PASS | + +**Handoff Summary** + +| 项 | 内容 | +|----|------| +| 任务描述 | 验证工具/子命令/schema/超时边界校验(AC-1.7–1.11) | +| 允许修改 | `tool_util.cpp`、`exec_options.cpp`、`exec_tool_param.cpp`、对应测试 | +| 允许新建 | 测试用例 | +| 只读参考 | spec AC-1.7–1.11 + R-6/R-7/R-8、design 接口参数规约 | +| Spec 摘要 | 工具/子命令→35700005;schema/超时边界→35700002 | +| Design 摘要 | ValidateProperties + ValidateExecOptionsProperties + ValidateInputSchemaProperties | +| 执行步骤 | 写失败测试→运行→修正→通过→证据 | +| 验证命令 | `run -t UT -ts tool_util_test` / 期望: PASS | +| 完成规则 | 不改范围外文件;无 evidence 不声明完成 | + +### TASK-CLI-006: NAPI 参数同步校验验证 + +| 字段 | 内容 | +|------|-----| +| 任务目标 | 验证必填缺失/类型错/argc<4 同步抛 invalid parameter 异常(AC-1.12) | +| AC 映射 | AC-1.12 | +| 前置依赖 | TASK-CLI-001 | +| 非目标 | 不验证服务端校验(TASK-CLI-005) | +| 完成判据 | toolName/challenge 空或非串、args 非对象、argc<4 均同步抛错,不进入异步 | +| 停止条件 | NAPI 校验与 spec 不一致 | + +**Files** + +| 操作 | 文件 | 说明 | +|------|------|------| +| Test | `cli_tool_framework/test/unittest/cli_tool_mgr_client_test/` | NAPI 校验用例 | + +**Spec Context** + +AC-1.12:toolName 空/非串、challenge 空/非串、args 非对象、实参<4 → 同步抛 invalid parameter 异常。 +R-9:NAPI 层校验先于服务端。 + +**Design Context** + +OnExecTool:argc 一份文档,从原始需求到基线结论。本需求 `REQ-010` 原始条目未在工作区检索到,以下内容依据 `cli_tool_framework` 中 `execTool` 既有实现反推并固化,待需求方/Owner 确认后基线。 + +## 一、原始需求 + +### 基本信息 + +| 字段 | 内容 | +|------|------| +| 需求ID | REQ-010 | +| 需求名称 | 执行 CLI 工具(execTool)System API | +| 来源 | 待确认(实现已存在于 cli_tool_framework,2026 版权) | +| 提出人 | 待确认 | +| 目标发行版本 | OpenHarmony-6.0-Release(待确认) | +| 候选 Profile | none | +| 优先级 | P1 | +| 状态 | Clarifying | + +### 原始描述 + +**原始问题:** 系统应用需要一种受控、受沙箱约束的方式按名称执行系统中已注册的命令行工具(CLI Tool),并获取执行会话的状态与结果,而不应直接 fork 任意命令或绕过权限审计。 + +**痛点:** + +| 用户类型 | 当前痛点 | 影响 | +|----------|----------|------| +| 系统应用开发者 | 无统一受控入口执行已注册 CLI 工具,需自建子进程与权限处理 | 集成成本高、安全风险大 | +| 系统安全/审计方 | 缺少统一的权限校验、沙箱隔离与失败上报 | 故障归因与合规审计困难 | +| 平台方 | 工具执行无并发上限与超时控制 | 易被滥用导致资源耗尽 | + +**期望结果:** 系统应用通过一个 System API(`execTool`)执行已注册 CLI 工具,系统统一完成权限校验、沙箱子进程创建、超时/让出/后台会话管理与结果回传,并在失败路径经 HiSysEvent 上报。 + +### 背景证据 + +| 证据类型 | 链接/路径 | 说明 | +|----------|-----------|------| +| 源码实现 | `cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp` | NAPI 入口 `execTool`/`OnExecTool` 已实现 | +| 源码实现 | `cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp` | 服务端 `ExecTool`、超时/让出/会话管理已实现 | +| SA 注册 | `services/sa_profile/186.json` | SA 186(进程 aimgr,库 libclimgr.z.so) | +| 进程配置 | `cli_tool_framework/etc/profile/aimgr.cfg` | ondemand、uid=aimgr、caps=KILL、SELinux 域 aimgr | + +### 初始范围 + +**可能包含:** +- `execTool` System API 的参数契约(toolName/subcommand/args/challenge/options) +- 前台/让出(yieldMs)/后台/超时 四种会话语义 +- 权限校验(系统应用 + `ohos.permission.EXEC_CLI_TOOL`)、HAP 沙箱校验 +- 错误码 35700000–35700008、35700020 + +**明确不包含:** +- `execCmd`(shell 命令执行)、`SubscribeSession`/`SendMessage`/`RegisterFunction` 等同模块其他接口 +- 工具注册/数据管理(`CliToolDataManager`/`RegisterFunction`)的内部实现 +- 跨设备会话同步 + +### 初始假设 + +| 假设 | 类型 | 验证方式 | 状态 | +|------|------|----------|------| +| 调用方须为系统应用 HAP | 技术/安全 | 源码 `ValidateExecToolPermissions` | 已验证 | +| 沙箱由系统按调用方 Token 生成 | 技术 | 源码 `ToolUtil::GenerateSandboxConfig` | 已验证 | +| 会话为运行态内存对象,不持久化 | 兼容性 | 源码 `SessionRecord` 生命周期 | 已验证 | +| 并发上限由系统配置决定 | 技术 | 源码 `CcmUtil::GetCliConcurrencyLimit` | 已验证 | + +### 初始分级判断 + +| 判断项 | 结果 | 依据 | +|--------|------|------| +| 复杂度 | 标准 | 单 System API,行为分支有限但涉及沙箱/IPC/会话生命周期 | +| 涉及仓数量 | 1 | `foundation/ability/ability_runtime` | +| 是否涉及 Public/System API | 是 | 新增 System API `execTool` | +| 是否涉及安全/性能关键路径 | 是 | 权限校验、沙箱、子进程、超时 | +| 是否跨 SIG | 否 | 全部在 Sig-Ability 内 | + +### 进入澄清条件 + +- [x] 原始问题和期望结果已记录 +- [ ] 需求来源和责任人已明确(待确认) +- [x] 初始范围和不包含项已记录 +- [x] 关键假设和待澄清问题已列出 +- [x] 复杂度有判断或明确为待定 + +--- + +## 二、澄清记录 + +> 本需求无原始对话记录,澄清项依据实现反推。标记「已澄清(实现反推)」的项需 Owner 复核确认。 + +### 待澄清问题 + +| 编号 | 问题 | 为什么需要澄清 | 状态 | +|------|------|----------------|------| +| Q-1 | `execTool` 是否仅限系统应用? | 决定 API 开放范围与权限模型 | 已澄清(实现反推:仅系统应用) | +| Q-2 | 是否允许非 HAP 调用? | 决定沙箱生成可行性 | 已澄清(实现反推:须 HAP) | +| Q-3 | 让出(yieldMs)与后台(background)是否互斥? | 决定会话语义模型 | 已澄清(实现反推:yieldMs 仅前台生效) | +| Q-4 | 超时上限是否固定 1800 秒? | 决定边界约束 | 已澄清(实现反推:MAX_TIMEOUT=1800) | +| Q-5 | 目标发行版本? | 基线必需 | 待确认 | + +### 讨论记录 + +| 日期 | 参与人 | 讨论主题 | 结论 | 后续动作 | +|------|--------|----------|------|----------| +| 2026-08-05 | AI 反推 | 会话语义 | 前台/让出/后台/超时四态 | Owner 复核 | + +### 功能范围确认 + +| 问题 | 回答 | 确认人 | 状态 | +|------|------|--------|------| +| 核心功能包含哪些? | execTool 执行已注册 CLI 工具;前台/让出/后台/超时会话;错误码 | 待确认 | 已确认(反推)/待确认 | +| 明确不包含哪些? | execCmd、订阅、注册函数、跨设备同步 | 待确认 | 已确认(反推)/待确认 | +| 是否有分期策略? | 否 | 待确认 | 已确认(反推) | + +### 方案探索 + +| 编号 | 方案概述 | 优势 | 风险/代价 | 选择结论 | +|------|----------|------|-----------|----------| +| A-1 | SA(186/aimgr)统一承载:NAPI→IPC→服务端做权限/沙箱/子进程/会话管理 | 集中权限审计、统一沙箱、可并发控制、失败可上报 | 跨进程 IPC 开销、SA 须按需拉起 | 推荐 | +| A-2 | 应用进程内直接 fork+exec 工具 | 无 IPC 开销、延迟低 | 绕过权限审计、沙箱不可控、无并发上限、难审计 | 放弃 | + +**取舍理由:** CLI 工具执行涉及权限/沙箱/超时/审计,集中到 SA 可统一安全边界与并发控制,IPC 开销可接受;A-2 安全风险不可接受。 + +### 上下文与知识源检索日志 + +| 编号 | 来源 | 查询/读取内容 | 关键发现 | 可信度 | 用于 | 命中/原因 | +|------|------|---------------|----------|--------|------|-----------| +| K-1 | 源码 `js_cli_manager.cpp` | `OnExecTool` 参数解析与回调派发 | 必填:toolName/subcommand/args/challenge,options 可选;argc<4 同步抛错 | 高 | 范围/API | 命中 | +| K-2 | 源码 `cli_tool_manager_service.cpp` | `ExecTool`/`ValidateExecToolPermissions`/`ValidateAndPrepareTool`/`SetupAndStartSession`/超时与让出处理 | 权限链、会话生命周期、超时=1800、yieldMs 仅前台、后台立即返回 | 高 | 设计/测试 | 命中 | +| K-3 | 源码 `tool_util.cpp` | `ValidateProperties`/`ValidateExecOptionsProperties`/`ValidateInputSchemaProperties` | subcommand 与 inputSchema 校验规则、help 特殊键 | 高 | 设计/测试 | 命中 | +| K-4 | `cli_error_code.h` | 错误码枚举 | 35700000–35700020 区间 | 高 | API | 命中 | +| K-5 | `ICliToolManager.idl` | IPC 接口签名 | `ExecTool(param, eventId, scheduler)` oneway 回复经 Scheduler | 高 | 设计 | 命中 | +| K-6 | `services/sa_profile/186.json`、`aimgr.cfg` | SA 注册与进程配置 | SA 186、进程 aimgr、ondemand、caps=KILL | 高 | 设计/构建 | 命中 | +| K-7 | `AGENTS.md` | 目标仓 Agent 指南 | 服务层与 SDK 层解耦、PermissionVerification、hisysevent 硬约束 | 高 | 设计约束 | 命中 | + +**上下文结论:** +- 高可信结论:execTool 行为链路、参数契约、错误码、SA/进程模型均已由源码固化,可直接进入基线与设计。 +- 待确认结论:目标发行版本、需求来源与责任人、并发上限具体数值(由产品配置)。 +- 未使用来源及原因:未使用多仓知识库(本需求单仓内闭环)。 + +### 子系统影响 + +| 问题 | 回答 | 确认人 | 状态 | +|------|------|--------|------| +| 涉及哪些子系统? | ability(ability_runtime) | 待确认 | 已确认(反推) | +| 是否需要新增子系统或部件? | 否 | 待确认 | 已确认(反推) | + +### API 变更评估 + +| 问题 | 回答 | 确认人 | 状态 | +|------|------|--------|------| +| 是否需要新增/修改 Public API? | 否 | 待确认 | 已确认(反推) | +| 是否需要新增 System API? | 是,1 个(`execTool`) | 待确认 | 已确认(反推) | +| 是否会废弃已有 API? | 否 | 待确认 | 已确认(反推) | +| 是否需要新增权限声明? | 是,`ohos.permission.EXEC_CLI_TOOL` | 待确认 | 已确认(反推) | + +### 兼容性与非功能需求 + +| 类别 | 核心问题 | 结论 | 确认人 | 状态 | +|------|----------|------|--------|------| +| 兼容性 | 向前/向后兼容要求?破坏性变更? | 新增 API,无破坏性;会话内存态无持久化迁移 | 待确认 | 已确认(反推) | +| 性能 | 响应时间/内存/并发要求? | 并发受系统上限约束;无公开 P 指标 | 待确认 | 已确认(反推) | +| 安全 | 权限/隐私/加密/审计要求? | 系统应用+权限+HAP 沙箱;失败经 HiSysEvent | 待确认 | 已确认(反推) | +| 可靠性 | 崩溃率/容错/恢复要求? | SA 不可用回 35700000;单次调用不应致 SA 崩溃 | 待确认 | 已确认(反推) | + +### 依赖与风险 + +| 依赖项 | 类型 | 说明 | 状态 | +|--------|------|------|------| +| `safwk`/`samgr` | 编译/运行 | SA 186 按需注册与拉起 | 已确认 | +| `access_token` | 运行 | 系统应用判定与权限校验 | 已确认 | +| `bundle_framework` | 运行 | HAP 判定与 bundleName 获取 | 已确认 | +| `kv_store` | 运行 | 工具/函数元数据存储(不影响 execTool 行为契约) | 已确认 | + +| 风险 | 类型 | 影响 | 缓解措施 | 状态 | +|------|------|------|----------|------| +| 需求来源/Owner 未确认 | 进度 | 基线无法冻结 | 需求方/SIG 确认 | 待确认 | +| 目标版本未确认 | 进度 | 影响 @since 与发布 | proposal.target_release 确认 | 待确认 | +| 并发上限随产品配置 | 技术 | 行为语义不变但数值差异 | spec 标注「由系统配置决定」 | 已确认 | + +### AC 完整性 + +- [x] 每个用户故事有验收标准 +- [x] AC 全部使用 WHEN/THEN 格式 +- [x] 覆盖正常流程、异常流程、边界条件 +- [x] AC 可测试、可度量 + +### 澄清结论 + +- [x] 功能范围已完全明确 +- [x] 子系统影响已识别 +- [x] API 变更已评估 +- [x] 兼容性和非功能需求已确认 +- [x] 依赖和风险已识别且有缓解方案 +- [x] AC 完整可测试 +- [x] 标准及以上复杂度已完成方案探索(A-1/A-2 + 取舍理由) + +**结论:** 条件通过(实现反推完整,待 Owner/需求方确认后转「通过」) + +--- + +## 三、需求基线 + +> 澄清完成后固化。manifest.md 是事实源,此处为审批结论。 + +### 基线信息 + +| 字段 | 内容 | +|------|-----| +| 基线版本 | v1.0 | +| 基线日期 | 2026-08-05 | +| Owner | 待确认 | +| 确认人 | 需求方/模块Owner/SIG代表(待确认) | +| 复杂度 | 标准 | +| Profile | none | +| 目标发行版本 | OpenHarmony-6.0-Release(待确认) | +| 版本状态 | proposed | + +### 问题陈述 + +系统应用缺少受控、可审计、受沙箱约束的 CLI 工具执行入口。本需求新增 `execTool` System API,由 SA 186(aimgr)统一承载权限校验、沙箱子进程创建、会话生命周期(前台/让出/后台/超时)与结果回传,并在失败路径经 HiSysEvent 上报。 + +### 目标和成功指标 + +| 目标 | 成功指标 | 验证方式 | +|------|----------|----------| +| 受控执行已注册 CLI 工具 | 合法调用返回 completed 会话与退出码 | 集成测试 | +| 权限/沙箱边界生效 | 非系统应用/缺权限/非 HAP 均被拒绝并返回正确错误码 | 单测 | +| 会话语义正确 | 前台/让出/后台/超时各态 reply 时机与 status 正确 | 集成测试 | +| 失败可归因 | 失败路径经 HiSysEvent 上报 bundleName/toolName/failureReason | hisysevent 校验 | + +### 用户故事与 AC + +| Story ID | 用户故事 | 优先级 | +|----------|----------|--------| +| US-1 | 作为系统应用开发者,我想要通过 execTool 按名称执行已注册 CLI 工具并获取会话信息,以便在系统应用内集成受沙箱约束的命令行工具能力 | P1 | + +> AC 共 15 条(AC-1.1–AC-1.15),详见 `spec.md`。此处不重复摘录,避免与 spec 不一致。 + +### 范围边界 + +**包含:** `execTool` System API 行为契约、参数校验、会话生命周期(前台/让出/后台/超时)、错误码、权限/沙箱前置校验。 +**不包含:** `execCmd`、`SubscribeSession`/`SendMessage`、`RegisterFunction`、工具注册数据管理、跨设备同步。 + +### 影响范围 + +| 子系统 | 仓库 | 模块/路径 | 当前职责 | 影响类型 | Owner | +|--------|------|-----------|----------|----------|-------| +| ability | foundation/ability/ability_runtime | cli_tool_framework/frameworks/js/napi/cli_tool_manager | NAPI 绑定 | 新增 API(既有实现固化契约) | 待确认 | +| ability | foundation/ability/ability_runtime | cli_tool_framework/services/climgr | 服务端实现 | 新增(既有实现固化契约) | 待确认 | +| ability | foundation/ability/ability_runtime | cli_tool_framework/interfaces/cli_tool | IPC 接口与数据结构 | 新增(既有实现固化契约) | 待确认 | +| ability | foundation/ability/ability_runtime | services/sa_profile/186.json | SA 注册 | 不变(已注册) | — | + +### API 变更项清单 + +| API 名称 | 变更类型 | 开放范围 | 概要说明 | +|----------|----------|----------|----------| +| `cliTool.execTool` | 新增 | System | 按名称执行已注册 CLI 工具,返回 Promise | + +### 不涉及项确认 + +| 维度 | 涉及? | 依据 | 若涉及,进入哪个下游文档 | +|------|--------|------|--------------------------| +| 性能 | 否 | 无公开 P 指标;并发上限由系统配置,非本 API 行为契约 | — | +| 安全与权限 | 是 | 系统应用+EXEC_CLI_TOOL 权限、HAP 沙箱、失败上报 | design.md / spec.md | +| 兼容性 | 否 | 新增 API,无破坏性;会话内存态无迁移 | spec.md | +| API/SDK | 是 | 新增 System API | design.md / spec.md | +| IPC/跨进程 | 是 | NAPI→IPC→SA 186 | design.md | +| 构建与部件 | 否 | 复用既有 component/parts,无新增部件 | — | +| 国际化/无障碍 | 否 | 无界面 System API | — | +| 数据迁移 | 否 | 无持久化 | — | + +### 变更控制 + +| 变更类型 | 触发条件 | 处理规则 | +|----------|----------|----------| +| 范围新增 | 新增用户故事或仓/模块 | 重新评估复杂度和设计影响 | +| AC 变更 | 修改可观察行为或错误码 | 重新审批基线和 Spec | +| API 变更 | 新增/修改 Public/System API | 触发设计审批 | +| 非功能指标变更 | 性能/安全/兼容性阈值变化 | 重新确认测试计划 | +| 目标版本变更 | 交付版本调整 | 更新 proposal.target_release | + +### 进入设计/Spec 条件 + +- [x] 所有 P0/P1 用户故事有 AC +- [x] 每条 AC 可测试、可度量 +- [x] 范围内/外已确认 +- [ ] `proposal.target_release` 已确认或明确 TBD(待确认) +- [x] `manifest.profile` 已确认或明确 none +- [x] 涉及仓、模块、SIG 已识别 +- [x] 不涉及项已标记 N/A +- [x] 变更控制规则已确认 +- [x] 标准及以上复杂度的澄清问题已逐项关闭,且讨论记录包含需求方/Owner/SIG 明确确认(实现反推,待 Owner 复核) +- [x] 上下文与知识源检索日志已填写;未查询关键来源的原因已记录 +- [x] 目标仓 Agent 指南已检查并记录关键约束(AGENTS.md 服务/SDK 解耦、PermissionVerification、hisysevent 硬约束) + +**基线结论:** 条件通过 diff --git a/.codespec/changes/issue-15383-cli-exectool/spec.md b/.codespec/changes/issue-15383-cli-exectool/spec.md new file mode 100644 index 0000000000..303e7cc847 --- /dev/null +++ b/.codespec/changes/issue-15383-cli-exectool/spec.md @@ -0,0 +1,278 @@ +# 特性规格 + +> 本规格仅覆盖 `execTool` 接口行为。范围限定:`execTool` 的用户可见行为、参数契约、错误码、会话生命周期与超时/让出/后台语义。`execCmd`、`SubscribeSession`、`SendMessage`、`RegisterFunction` 等同模块其他接口不在本规格范围内。 +> +> **输入文档说明:** 工作区未检索到 `REQ-010` 需求条目与已批准的 `proposal.md`。本规格依据 `cli_tool_framework` 中 `execTool` 的既有实现(`frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp`、`services/climgr/src/cli_tool_manager_service.cpp`、`interfaces/cli_tool/`)反推固化。待 `proposal.md` 基线化后,以下「优先级/目标版本/SIG 归属」字段应回填 proposal 值。 + +## 概述 + +| 属性 | 值 | +|------|-----| +| 特性名称 | 执行 CLI 工具(execTool) | +| 特性编号 | FEAT-CLI-001 | +| 所属 Epic | REQ-010 | +| 优先级 | P1 | +| 目标版本 | 参见 proposal.md(待基线) | +| SIG 彾属 | Sig-Ability | +| 状态 | Draft | +| 复杂度 | 标准 | + +## 本次变更范围(Delta) + +本特性为新增能力(lineage: new)。`execTool` 为 `cli_tool_framework` 对外暴露的 System API,此前不存在对外契约。 + +| 类型 | 内容 | 说明 | +|------|------|------| +| ADDED | `execTool` System API(JS) | 系统应用按名称执行已注册 CLI 工具,返回会话信息 | +| ADDED | 错误码 35700000–35700008、35700020 | 见 cli_error_code.h,本规格仅声明 execTool 链路涉及项 | +| ADDED | 权限 `ohos.permission.EXEC_CLI_TOOL` | execTool 调用前置权限 | +| ADDED | 数据结构 `ExecOptions`/`CliSessionInfo`/`ExecResult` | 对外行为契约,非内部实现 | + +## 输入文档 + +| 文档 | 路径 | 状态 | +|------|------|------| +| Requirement | `REQ-010`(未在工作区检索到) | Pending | +| Proposal | `proposal.md`(未提供) | Pending | + +> 需求基线、不涉及项、受影响子系统与仓库详见 proposal.md,本文档不重复摘录。design.md 与本文档并行产出,互不依赖。 + +## 用户故事 + +### US-1: 系统应用执行已注册的 CLI 工具 + +**作为** 系统应用开发者, +**我想要** 通过 `execTool` 接口按名称执行已注册的 CLI 工具并获取执行会话信息, +**以便** 在系统应用内集成受沙箱约束的命令行工具能力。 + +**验收标准(AC, Acceptance Criteria):** + +| AC编号 | 验收标准 | 类型 | +|--------|----------|------| +| AC-1.1 | WHEN 系统应用持 `ohos.permission.EXEC_CLI_TOOL` 调用 `execTool`,传入已注册的 `toolName`、工具支持的 `subcommand`、符合工具 `inputSchema` 的 `args`、非空 `challenge` THEN 接口返回 Promise,工具执行结束后 resolve 为 `CliSessionInfo`(`status="completed"`,`result.exitCode` 等于子进程退出码) | 正常 | +| AC-1.2 | WHEN `options.background=false` 且 `options.yieldMs>0` THEN 在 `yieldMs` 毫秒后 resolve 为 `status="running"` 的 `CliSessionInfo`,会话转入后台继续运行 | 行为 | +| AC-1.3 | WHEN `options.background=true` THEN 接口立即 resolve 为 `status="running"` 的 `CliSessionInfo`,不等待执行结束 | 行为 | +| AC-1.4 | WHEN 进程持续运行至 `options.timeout` 秒 THEN 进程被终止、最终会话 `result.timeout=true`,并向会话订阅者派发超时错误事件 | 边界 | +| AC-1.5 | WHEN 非系统应用调用 `execTool` THEN Promise reject 错误码 `35700008`(ERR_NOT_SYSTEM_APP) | 异常 | +| AC-1.6 | WHEN 系统应用未持有 `ohos.permission.EXEC_CLI_TOOL` THEN Promise reject 错误码 `35700007`(ERR_PERMISSION_DENIED) | 异常 | +| AC-1.7 | WHEN `toolName` 未在系统中注册 THEN Promise reject 错误码 `35700005`(ERR_TOOL_NOT_EXIST) | 异常 | +| AC-1.8 | WHEN 传入非空 `subcommand` 但工具未声明子命令,或 `subcommand` 不在工具子命令列表中 THEN Promise reject 错误码 `35700005`(ERR_TOOL_NOT_EXIST) | 异常 | +| AC-1.9 | WHEN `args` 含工具 `inputSchema` 未定义的键,或某键值类型与 schema 声明不符 THEN Promise reject 错误码 `35700002`(ERR_INVALID_PARAM) | 异常 | +| AC-1.10 | WHEN `options.timeout<0` 或 `options.timeout>1800` THEN Promise reject 错误码 `35700002`(ERR_INVALID_PARAM) | 边界 | +| AC-1.11 | WHEN `options.background=false` 且 `options.yieldMs>options.timeout*1000` THEN Promise reject 错误码 `35700002`(ERR_INVALID_PARAM) | 边界 | +| AC-1.12 | WHEN `toolName` 为空字符串/非字符串、`challenge` 为空字符串/非字符串、`args` 非对象,或实参个数小于 4 THEN 同步抛出 invalid parameter 异常,不进入异步链路 | 边界 | +| AC-1.13 | WHEN 调用时系统并发会话数已达上限 THEN Promise reject 错误码 `35700001`(ERR_SESSION_LIMIT_EXCEEDED) | 边界 | +| AC-1.14 | WHEN 调用方进程非 HAP THEN Promise reject 错误码 `35700003`(ERR_NOT_HAP) | 异常 | +| AC-1.15 | WHEN CliToolManager 系统能力未就绪或代理获取失败 THEN Promise reject 错误码 `35700000`(GET_CLI_TOOL_MGR_SERVICE_FAILED) | 恢复 | + +## 验收追溯 + +| AC | 关联规则 | 关联 Task | 验证方式 | 证据 | +|----|----------|-----------|----------|------| +| AC-1.1 | R-1 | TASK-CLI-001 | 集成 + 单测 | `cli_tool_framework/test/unittest/process_manager_test/` | +| AC-1.2 | R-2 | TASK-CLI-002 | 集成 | `cli_tool_framework/test/` | +| AC-1.3 | R-3 | TASK-CLI-002 | 集成 | `cli_tool_framework/test/` | +| AC-1.4 | R-4 | TASK-CLI-003 | 集成 | `cli_tool_framework/test/` | +| AC-1.5 | R-5 | TASK-CLI-004 | 单测 | `cli_tool_mgr_client_test/` | +| AC-1.6 | R-5 | TASK-CLI-004 | 单测 | `cli_tool_mgr_client_test/` | +| AC-1.7 | R-6 | TASK-CLI-005 | 单测 | `cli_tool_mgr_client_test/` | +| AC-1.8 | R-6 | TASK-CLI-005 | 单测 | `cli_tool_mgr_client_test/` | +| AC-1.9 | R-7 | TASK-CLI-005 | 单测 | `exec_tool_param_test/` | +| AC-1.10 | R-8 | TASK-CLI-005 | 单测 | `exec_options_test/` | +| AC-1.11 | R-8 | TASK-CLI-005 | 单测 | `exec_options_test/` | +| AC-1.12 | R-9 | TASK-CLI-006 | 单测 | `js_cli_manager` NAPI 单测 | +| AC-1.13 | R-10 | TASK-CLI-007 | 集成 | `cli_tool_framework/test/` | +| AC-1.14 | R-11 | TASK-CLI-004 | 集成 | `cli_tool_framework/test/` | +| AC-1.15 | R-12 | TASK-CLI-008 | 集成 | `cli_tool_mgr_client_test/` | + +## 规则定义 + +| 规则ID | 类型 | 触发条件 | 预期行为 | 边界/约束 | 关联AC | +|--------|------|----------|----------|-----------|--------| +| R-1 | 行为 | 系统应用 + 持 EXEC_CLI_TOOL + toolName 已注册 + subcommand 合法 + args 匹配 inputSchema + challenge 非空 + options 合法 | 创建会话与受沙箱子进程执行工具,结束后 resolve `CliSessionInfo{status="completed", result.exitCode=进程退出码, outputText, errorText, executionTime}` | 退出码为 int32;executionTime 为 int64 毫秒 | AC-1.1 | +| R-2 | 行为 | foreground(yieldMs>0) 模式 | 会话在 `yieldMs` 毫秒处派发 reply,resolve 为 `status="running"` 的会话;会话切后台继续运行;后续结束通过会话事件(订阅)派发 | yieldMs 单位毫秒,int64 | AC-1.2 | +| R-3 | 行为 | background=true 模式 | 立即 resolve 为 `status="running"` 的会话;不调度 yield 任务;结束时向订阅者派发退出事件 | — | AC-1.3 | +| R-4 | 边界 | 进程运行时间 = options.timeout 秒(timeout>0) | 终止进程、`result.timeout=true`、向订阅者派发 "session timed out" 错误事件;若此前未后台则派发终态 reply | timeout 单位秒,上限 1800(=30 分钟);=0 表示不启用超时 | AC-1.4 | +| R-5 | 异常 | 调用方 Token 非系统应用,或未持 EXEC_CLI_TOOL 权限 | reject:非系统应用→35700008;缺权限→35700007 | 校验在入口执行 | AC-1.5, AC-1.6 | +| R-6 | 异常 | toolName 未注册;或 subcommand 非空但工具无子命令/不在子命令表 | reject 35700005(ERR_TOOL_NOT_EXIST) | subcommand 为空串时使用工具顶层 inputSchema | AC-1.7, AC-1.8 | +| R-7 | 异常 | args 含 inputSchema 未声明的键,或键值类型与 schema.type 不符 | reject 35700002(ERR_INVALID_PARAM);特殊键 `help` 单独存在时放行 | args 为空对象视为合法 | AC-1.9 | +| R-8 | 边界 | options.timeout<0 或 >1800;或非后台且 yieldMs>timeout*1000;或 yieldMs<0 | reject 35700002(ERR_INVALID_PARAM) | timeout∈[0,1800] 秒;yieldMs∈[0, timeout*1000] 毫秒(非后台) | AC-1.10, AC-1.11 | +| R-9 | 边界 | 实参个数<4;或 toolName/challenge 为空串或非字符串;或 args 非对象 | 同步抛出 invalid parameter 异常(不进入异步 Promise) | NAPI 层校验先于服务端 | AC-1.12 | +| R-10 | 边界 | 调用时活动会话数 ≥ 系统并发上限 | reject 35700001(ERR_SESSION_LIMIT_EXCEEDED) | 上限由系统配置 CcmUtil.GetCliConcurrencyLimit 决定 | AC-1.13 | +| R-11 | 异常 | 调用方 Token 非 HAP(无法生成沙箱配置) | reject 35700003(ERR_NOT_HAP) | 沙箱配置生成失败前置 | AC-1.14 | +| R-12 | 恢复 | CliToolManager SA 未加载或代理为空 | reject 35700000(GET_CLI_TOOL_MGR_SERVICE_FAILED) | 客户端按需拉起 SA;拉起失败即此码 | AC-1.15 | + +## 验证映射 + +| 编号 | 对应规格项 | 验证方式 | 验证重点 | +|------|------------|----------|----------| +| VM-1 | R-1 / AC-1.1 | 集成 + 单测 | 正常执行返回 completed 会话与退出码 | +| VM-2 | R-2,R-3 / AC-1.2,AC-1.3 | 集成 | yield/background 模式 reply 时机与 status | +| VM-3 | R-4 / AC-1.4 | 集成 | 超时终止、result.timeout、错误事件派发 | +| VM-4 | R-5 / AC-1.5,AC-1.6 | 单测 | 系统应用判定与权限校验路径 | +| VM-5 | R-6,R-7,R-8 / AC-1.7–AC-1.11 | 单测 | 工具/子命令/schema/超时参数校验 | +| VM-6 | R-9 / AC-1.12 | 单测 | NAPI 参数校验同步抛错 | +| VM-7 | R-10,R-11,R-12 / AC-1.13–AC-1.15 | 集成 + 单测 | 会话上限、非 HAP、SA 不可用 | + +## API 变更分析 + +### 新增 API + +| API 名称 | 开放范围 | 入参概要 | 返回值 | 错误码范围 | 功能描述 | 关联 AC | +|----------|----------|----------|--------|------------|----------|---------| +| `cliTool.execTool` | System | `(toolName: string, subcommand: string, args: object, challenge: string, options?: ExecOptions)` | `Promise` | 35700000–35700008, 35700020 | 按名称执行已注册 CLI 工具,返回会话信息 | AC-1.1–1.15 | + +> API 签名、d.ts 位置、权限要求等实现细节见 design.md。ExecOptions/CliSessionInfo/ExecResult 的字段语义见下「接口规格」。 + +### 变更/废弃 API + +无变更或废弃项。 + +## 接口规格 + +### 接口定义 + +**execTool** + +| 属性 | 值 | +|------|-----| +| 函数签名 | `execTool(toolName: string, subcommand: string, args: object, challenge: string, options?: ExecOptions): Promise` | +| 返回值 | `Promise` — resolve 为会话信息;reject 为错误码 | +| 开放范围 | System | +| 权限 | `ohos.permission.EXEC_CLI_TOOL`,且调用方须为系统应用 | +| 错误码 | 35700000, 35700001, 35700002, 35700003, 35700004, 35700005, 35700007, 35700008 | +| 关联 AC | AC-1.1–1.15 | + +**参数约束** + +| 参数 | 类型 | 必填 | 默认值 | 约束条件 | +|------|------|------|--------|---------| +| toolName | string | 是 | — | 非空;须为已注册工具名,否则 35700005 | +| subcommand | string | 是 | — | 可为空串(工具无子命令时);非空时须在工具子命令表内,否则 35700005 | +| args | object(WantParams 键值对) | 是 | — | 键须在工具 inputSchema.properties 内且类型匹配;空对象合法;特殊键 `help` 须单独存在 | +| challenge | string | 是 | — | 非空 | +| options | ExecOptions | 否 | `{background:false, yieldMs:0, timeout:0}` | 见 ExecOptions 约束 | + +**ExecOptions 约束** + +| 字段 | 类型 | 默认 | 约束 | +|------|------|------|------| +| background | boolean | false | true=后台立即返回;false=前台,可由 yieldMs 触发让出 | +| yieldMs | number(int64) | 0 | ≥0,单位毫秒;仅 foreground 生效;foreground 下须 ≤ timeout*1000 | +| timeout | number(int64) | 0 | ∈[0,1800],单位秒;0=不启用超时;timeoutMs=timeout*1000 | + +**CliSessionInfo(resolve 值)** + +| 字段 | 类型 | 说明 | +|------|------|------| +| sessionId | string | 会话唯一标识 | +| toolName | string | 工具名 | +| status | string | `"running"` / `"completed"` / `"failed"` | +| result | ExecResult \| undefined | 仅 completed/failed 时存在 | + +**ExecResult** + +| 字段 | 类型 | 说明 | +|------|------|------| +| exitCode | number(int32) | 子进程退出码,默认 1 | +| outputText | string | 标准输出累计 | +| errorText | string | 标准错误累计 | +| signalNumber | number(int32) | 终止信号,0 表示正常 | +| timeout | boolean | 是否因超时终止 | +| executionTime | number(int64) | 执行耗时(毫秒) | + +**行为场景** + +| # | 触发条件 | 预期行为 | 关联 AC | +|---|----------|----------|---------| +| 1 | 前台 + timeout=0 + yieldMs=0 + 进程正常退出 | 进程退出且输出排空后 resolve `status="completed"`,含 exitCode/outputText | AC-1.1 | +| 2 | 前台 + yieldMs>0 | yieldMs 毫秒处 resolve `status="running"`,会话转后台;后续结束经订阅事件通知 | AC-1.2 | +| 3 | background=true | 立即 resolve `status="running"`;结束时向订阅者派发退出事件,不再二次 resolve | AC-1.3 | +| 4 | timeout>0 且进程未在 timeout 秒内退出 | 终止进程、`result.timeout=true`、派发 "session timed out" 事件;未后台则派发终态 reply | AC-1.4 | +| 5 | 非系统应用调用 | reject 35700008 | AC-1.5 | +| 6 | 系统应用缺权限 | reject 35700007 | AC-1.6 | +| 7 | toolName 未注册 / subcommand 非法 | reject 35700005 | AC-1.7, AC-1.8 | +| 8 | args 不符 inputSchema | reject 35700002 | AC-1.9 | +| 9 | options.timeout/yieldMs 越界 | reject 35700002 | AC-1.10, AC-1.11 | +| 10 | 必填参数缺失/类型错/实参<4 | 同步抛 invalid parameter 异常 | AC-1.12 | +| 11 | 会话数达上限 | reject 35700001 | AC-1.13 | +| 12 | 非 HAP 调用 | reject 35700003 | AC-1.14 | +| 13 | SA 不可用 | reject 35700000 | AC-1.15 | + +## 兼容性声明 + +- **已有 API 行为变更:** 否。本特性为新增 System API,不改变既有公共 API 行为。 +- **配置文件格式变更:** 否(沙箱配置为内部生成,非对外配置文件)。 +- **数据存储格式变更:** 否。会话为运行态内存对象,不持久化。 +- **最低支持版本:** 参见 proposal.md(待基线)。 +- **API 版本号策略:** 新增 API 自首个引入版本起标注 `@since`;错误码 357000xx 为本特性专属区间,不可被其他特性复用数值。 + +## 架构约束 + +| 关键约束 | 约束说明 | 影响 AC | +|----------|----------|---------| +| 仅系统应用 + `ohos.permission.EXEC_CLI_TOOL` 可调用 | 入口须做系统应用判定与权限校验 | AC-1.5, AC-1.6 | +| 执行须在受限沙箱子进程中进行 | 调用方须为 HAP 以生成沙箱配置 | AC-1.14 | +| 回复经 IPC Scheduler 异步派发 | 回调不在调用线程同步执行 | AC-1.1–1.4 | +| 并发会话受系统上限约束 | 超限拒绝,不排队 | AC-1.13 | + +> 架构规则适用性及设计方案(SA 注册、IPC Stub/Proxy、沙箱生成、IOMonitor 调度等)见 design.md。 + +## 非功能性需求 + +| 类型 | 指标/阈值 | 验证方式 | 证据 | +|------|-----------|----------|------| +| 可靠性 | 单次 execTool 调用不应导致 CliToolManager SA 崩溃 | 压力测试 | `cli_tool_framework/test/` | +| 安全 | 非系统应用/无权限/非 HAP 调用均被拒绝 | 单测 | `cli_tool_mgr_client_test/` | +| 可测试性 | execTool 行为可经 mock 服务端校验错误码与回复时机 | 单测 | `cli_tool_mgr_client_test/`、`exec_options_test/` | +| 定界定位 | 失败路径经 HiSysEvent 上报(bundleName、toolName、failureReason/duration) | hisysevent | `hisysevent.yaml` | + +## 多设备适配声明 + +| 设备类型 | 行为差异 | 规格/约束 | 验证方式 | 证据 | +|----------|----------|-----------|----------|------| +| 手机 | 无差异 | — | 集成 | `cli_tool_framework/test/` | +| 平板 | 无差异 | — | 集成 | `cli_tool_framework/test/` | +| 折叠屏 | 无差异 | — | 集成 | `cli_tool_framework/test/` | + +> execTool 行为与设备形态无关;并发上限等可随产品配置调整,不影响行为语义。 + +## 全局特性影响 + +| 特性 | 适用? | 结论 | 关联场景 | +|------|--------|------|----------| +| 无障碍 | 否 | execTool 为无界面 System API | — | +| 大字体 | N/A | — | — | +| 深色模式 | N/A | — | — | +| 多窗口/分屏 | 否 | 与窗口无关 | — | +| 多用户 | 否 | 权限与沙箱按调用方 Token 校验,不依赖用户切换 | — | +| 版本升级 | 否 | 无持久化数据需迁移 | — | +| 生态兼容 | 否 | 仅系统应用可用 | — | + +## Spec 自审清单 + +在提交审查前逐项自检: + +- [x] 无"待定""TBD""TODO"等占位符("待基线"为上游 proposal 缺失的如实标注,非规格占位) +- [x] 所有 AC 使用 WHEN/THEN 格式,可独立测试 +- [x] 范围边界明确(仅 execTool;execCmd 等不涉及) +- [x] 无语义模糊表述 +- [x] AC 与规则表交叉一致(每个 AC 至少关联一条规则,每条规则至少关联一个 AC) +- [x] 规则表每条通过 5 项质量检查(可复现/可观测/边界值/关联AC/无冲突) + +## context-references + +```yaml +context-queries: + - repo: "openharmony/ability_runtime" + query: "cli_tool_framework execTool 的 SA 注册、IPC Stub/Proxy 序列化与沙箱生成实现" + - repo: "openharmony/ability_runtime" + query: "ExecToolParam/ExecOptions/CliSessionInfo 的 Parcelable 编解码分支" +``` + +**关键文档:** +- `cli_tool_framework/frameworks/js/napi/cli_tool_manager/src/js_cli_manager.cpp`(NAPI 入口 `execTool`/`OnExecTool`) +- `cli_tool_framework/services/climgr/src/cli_tool_manager_service.cpp`(服务端 `ExecTool`、超时/让出处理) +- `cli_tool_framework/services/climgr/src/tool_util.cpp`(参数与 inputSchema 校验) +- `cli_tool_framework/interfaces/cli_tool/include/cli_error_code.h`(错误码定义) +- `cli_tool_framework/interfaces/cli_tool/ICliToolManager.idl`(IPC 接口)