Skip to content

[Bug] ToolPkg hiddenExec 调用永久挂起:qqbot「开启监听」卡死(Operit 1.12.1) #1180

Description

@GrapeJellyQwq

[Bug] ToolPkg hiddenExec 调用永久挂起:qqbot「开启监听」卡死(Operit 1.12.1)

环境

  • Operit 1.12.1(versionCode 46)
  • 设备:vivo V2180GA,Android 11(SDK 30)
  • 插件:内置 qqbot.toolpkg v0.3.0(container com.operit.qqbot_bundle)
  • 终端环境(Ubuntu 24.04)正常;qqbot_test_connection 返回 HTTP 200(凭证/网络正常)

问题

调用 qqbot:qqbot_service_start(restart=true / timeout_ms=10000 / 默认参数,各种组合都试过)后:

  • 工具调用永不返回,持续挂起(实测 5~10+ 分钟);
  • 只有用户发送新消息打断 AI 生成时才被取消(显示 "User cancelled");
  • 重启应用(换新进程)后 100% 复现。

期望行为

hiddenExec 应正常执行并返回结果;即使执行失败也应返回错误(或至少超时),而不是让 Promise 永久挂起、把上层工具调用一起拖死。

复现步骤

  1. 启用内置 qqbot 工具包,配置 AppID/Secret(沙箱,连接测试正常)。
  2. 调用 qqbot:qqbot_service_start。
  3. 观察:调用挂起;日志停在下方"关键日志"最后一行,之后再无任何 hiddenExec 执行痕迹。

关键日志(logcat,新进程会话,2026-09-13 15:38:38)

工具执行到"应调用 hiddenExec 拉起 Python 网关服务"这一步即静默:

D/ToolExecutionManager: Found 1 tool invocations: [qqbot:qqbot_service_start]
D/AIToolHandler: Auto-activating package 'qqbot' for tool qqbot:qqbot_service_start
D/PackageManager: Successfully loaded and activated package: qqbot
(插件数据目录初始化、config.json 写入均成功)
D/Linux: [Posix_connect Debug]Process com.ai.assistance.operit :32145
E/HttpTools: java.net.ConnectException: Failed to connect to /***:32145 (ECONNREFUSED,此处预期:服务尚未启动)

之后没有任何后续日志:按插件源码(qqbot.toolpkg 内 dist/shared/qqbot_service.js),下一步是
Tools.System.terminal.hiddenExec("python3 ...", { executorKey: "qqbot_gateway_service" }),
该调用此后既无执行记录、也无失败返回,Promise 永不 resolve。

更早的会话中还出现过:

  • [qqbot_ipc] withContext call failed: kind=main, error=Script execution timed out after 15 seconds
  • [qqbot_listener_app_foreground] JS ERROR: Script execution timed out after 1800 seconds(JsEngine TimeoutException 堆栈)

已确认问题不在插件/凭证/网络侧(附验证方法)

手动运行插件资源中的 resources/qqbot_gateway_service.py(纯标准库、无第三方依赖)并让其绑定 127.0.0.1:32145 后:

  • 插件的状态接口立即恢复正常:healthy=true, running=true, connected=true, configMatchesCurrent=true,机器人成功登录网关并正常收发心跳。
  • 说明:唯一故障点是 Tools.System.terminal.hiddenExec 这条系统调用通道(不执行、不报错、不超时)。

影响范围

  • qqbot「开启监听」完全不可用;
  • 内置包 code_runner(CODE_RUNNER_HIDDEN_EXECUTOR_KEY)、linux_ssh 也使用同一 Tools.System.terminal.hiddenExec API,预计同样受影响。

建议

  1. 排查 hiddenExec 执行链路(executorKey 的创建/调度),修复"调用不落地"问题;
  2. 为 hiddenExec 增加超时与错误返回,避免 Promise 永久挂起。

(完整日志摘录与堆栈见附楼/附件。)

Activity

  1. yoruuuchan commented on Sep 16, 2026

    @yoruuuchan
    Contributor

    我来排查并修复 hiddenExec 挂起问题,会基于 dev 提交 PR。

  2. yoruuuchan commented on Sep 16, 2026

    @yoruuuchan
    Contributor

    修复已完成并提交 PR,基于最新 dev(5948dff9):

    真实挂起点在 LocalTerminalProvider.executeHiddenCommand(terminal 子模块),不在 JS bridge 或 Promise 层:

    1. shell 启动 / readiness / 全局创建 mutex 都在 withTimeout(timeoutMs) 之外,不受调用 deadline 约束;
    2. 命令写入使用结构化 withContext(Dispatchers.IO),管道写阻塞时协程取消仍需等待子任务归还,调用因此永久 pending;
    3. 超时后 shell 是异步退役的,同 executorKey 的下一次调用可能撞上半关闭状态。

    修复方式:timeout 统一覆盖 prepare / queue / write / read 全生命周期;阻塞写入改为可取消;失败、超时、取消的 executor 通过幂等关闭退役(先 destroy 进程,再关 writer);排队调用遇到已退役 shell 会在同一 deadline 内重新解析 key。QQbot、code_runner、linux_ssh 共用同一条通用链,结果字段保持不变。

    验证:新增 13 项 JVM 生命周期测试(成功复用、启动失败、readiness 超时、启动阻塞、创建锁 deadline、排队超时不影响 owner、owner 超时后排队调用接管、写入阻塞、取消、进程退出、reader 异常、分片 marker、disconnect)在修复后全部通过;在未修复的实现上,readiness / 创建锁 / 阻塞写入三例均以墙钟 TimeoutException 复现永久等待。

  3. added a commit that references this issue on Sep 16, 2026
    95e8fda
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions