Skip to content

02 Agent 进程管理

Agent 二进制文件

Agent 是一个 Node.js 应用程序,打包为平台特定的独立可执行文件:

文件名平台架构大小
x86_64_darwin_arm_nodemacOSARM64 (Apple Silicon)84 MB
x86_64_darwin_nodemacOSx86_64 (Intel)89 MB
x86_64_linux_nodeLinuxx86_6488 MB
x86_64_windows_node.exeWindowsx86_6468 MB
x86_64_windows7_node.exeWindows 7x86_6429 MB

主程序入口: agent/bin/index.js (3.8 MB webpack bundle)

Agent 启动流程

1. PluginStartupActivity.runActivity()
   └─► RestartableAgentProcessService.init()
       └─► createInitializedDelegate()
           └─► new PluginAgentProcessServiceImpl()
               ├─► unZipAgent()     — 首次运行解压 agent.zip
               ├─► copySource()     — 复制 WASM 文件
               └─► launchAgent()    — 启动 Agent 进程
                   └─► PluginAgentCommandLine.createAgentCommandLine()
                       └─► createAgentBinaryCommandline()
                           ├─► findAgentBinary()     — 查找平台二进制
                           ├─► chmod a+x (Unix)      — 设置可执行权限
                           └─► 构建启动命令

启动命令

bash
# 命令格式
<binary_path> <index.js_path> <os_arch>

# 实际示例 (macOS ARM)
~/.iflycode/bin/agent/bin/x86_64_darwin_arm_node \
    ~/.iflycode/bin/agent/bin/index.js \
    aarch64

# 环境变量
ELECTRON_RUN_AS_NODE=""   # 禁止 Electron 行为
NODE_OPTIONS=""            # 清除用户 Node 配置

端口发现机制

Agent 进程启动后通过 stdout 输出监听端口号:

java
// PluginAgentProcessHandler.onTextAvailable()
Pattern.compile("\\d+x+N&2");  // 混淆后的正则,匹配端口号

端口轮询获取:

java
// RestartableAgentProcessService.JD()
// 最多重试 5 次,每次等待递增时间
Pair pair = agentService.getAgentPort(pid, timeout);
while (StringUtils.isBlank(port) && retryCount < 5) &#123;
    pair = agentService.getAgentPort(pid, ++retryCount);
&#125;

WebSocket 连接建立

Agent 进程启动 ──stdout──► 输出端口号

插件解析端口 ◄─────────────┘


创建 WebSocket 连接: ws://127.0.0.1:&#123;port&#125;/ws/idea

     ├─ 可选 Header: traceparent (W3C Trace Context)


连接成功 (onOpen):
     ├─► 发送 ACTION_INIT (pluginVersion, clientName, apiVersion, projectPath)
     ├─► 发送 USER_LOGIN (data: &#123;count: 1&#125;)
     └─► 启动心跳检测

Agent 重启机制

触发条件:

场景RestartEnumCode
Agent 启动失败START_AGENT0
WebSocket 连接被拒CONNECT_REFUSED1
WebSocket 连接失败CONNECT_FAILED2
WebSocket 连接错误CONNECT_ERROR3
WebSocket 关闭异常CLOSE_EXCEPTION4
WebSocket 关闭错误CLOSE_ERROR5
端口为空BLANK_PORT6
刷新重连REFRESH7
心跳超时HEART_BEAT_ERROR8
关闭后重连CLOSE_RECONNECT9
刷新后重连REFRESH_RECONNECT10

重试策略:

  • 最大重启次数: 3 次
  • 重试间隔: 3 秒
  • 连接拒绝: 连续 3 次拒绝后重启
  • 达到上限后: 停止重试,通知 WebView 显示刷新状态

Agent 进程终止

java
// 关闭所有 WebSocket
PluginWebsocketClient.closeWebsocket("plugin dispose");
// 关闭 Agent 进程
agentProcess.shutdown();
// 强制终止
agentProcess.killProcess();
// 清理残留进程 (按进程名匹配)
RestartableAgentProcessService.killAgent();

本地存储

Agent 使用 sqlite3 进行本地数据持久化(Native Addon):

平台文件架构
macOS ARMsqlite3-darwin-arm64.nodearm64
macOS Intelsqlite3-darwin-x64.nodex86_64
Linuxsqlite3-linux-x64.nodex86_64
Windows 32sqlite3-win32-ia32.nodex86
Windows 64sqlite3-win32-x64.nodex86_64

WASM 代码解析

Agent 使用 tree-sitter 进行代码解析:

WASM 文件语言大小
tree-sitter.wasm基础运行时189 KB
tree-sitter-c.wasmC774 KB
tree-sitter-java.wasmJava420 KB
tree-sitter-javascript.wasmJavaScript628 KB
tree-sitter-python.wasmPython463 KB
tree-sitter-go.wasmGo202 KB
tree-sitter-cpp.wasmC++4.5 MB
tree-sitter-c_sharp.wasmC#5.6 MB
tree-sitter-typescript.wasmTypeScript2.2 MB
tree-sitter-tsx.wasmTSX1.4 MB

本项目仅供学习研究,逆向分析内容归原厂商所有。