关于 crewdroid
crewdroid 是面向开发者和 AI Agent 的无界面 Android 设备实验室,可在多个模拟器上测试应用。它在不同网络和时序条件下运行流程,并检查服务端数据中的并发错误;CLI 命令也可作为 MCP 工具和 Agent 技能使用。
主要功能
- 01启动多种配置的 Android 模拟器集群
- 02设置各设备的网络状态
- 03重放多设备场景
- 04检查服务端数据中的并发错误
- 05查看屏幕与 Android 诊断信息
- 06将 CLI 命令作为 MCP 工具提供
适用场景
- 01在重试时复现重复或丢失的上传
- 02测试网络中断期间的应用流程
- 03检查并发编辑导致的更新丢失
- 04跨 Android 版本和屏幕排查崩溃
MCP 相关
stdio MCP 服务暴露与 CLI 相同的功能,包括设备管理、场景运行、诊断和判定。它还提供包含命令步骤的 Agent 技能。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
14收录的工具列表 · 更新于 今天
此工具无需参数。
详细介绍
crewdroid
面向 AI Agent 的无头 Android 设备实验室。 通过一条命令启动一组不同型号的 Galaxy 模拟器,按各自的计划切断每台设备的网络,以不同时间安排重放相同的用户流程,然后检查服务端数据,判断是否存在并发错误——记录重复、缺失或被覆盖。没有窗口,也无需点击:每一步都是带有 --json 和退出码的 CLI 命令;这些命令同时也是 MCP 工具和 Agent 技能。
npx crewdroid up --count 3 # 3 devices: s24ultra/API 34, fold5/API 34, flip7/API 36 — booted in ~7 s each
npx crewdroid run scenarios/photo-upload.json --seed 1 # multi-user flow + network chaos + judge, exit 1 on a bug

为什么不直接使用 Android Emulator?
原生模拟器是一部带窗口、由人工操作的手机。crewdroid 是由程序驱动的设备群。
| Android Emulator / AVD Manager | crewdroid | |
|---|---|---|
| 设备 | 一个 AVD 对应一个窗口和一个磁盘映像 | 基于同一基础映像创建 N 个只读克隆,支持不同屏幕(S/Fold/Flip/任意 WxH@dpi)和 API 级别,一条命令即可启动 |
| 交互 | 在窗口中点击,读取屏幕截图 | 每条命令都提供 --json 输出和退出码;screen 返回无障碍树,而非像素 |
| 启动 | 冷启动需 31.6 秒 | 从精简快照启动需 6.7 秒 |
| 磁盘 | 24.7 GiB(3 个 AVD) | 6.99 GiB(3 个克隆,3 个 API 级别) |
| 主机 RAM | 8.45 GB | 3.93 GB |
| 空闲 CPU(100 % = 1 个核心) | 1000 % | ~600 % |
| 网络 | Extended Controls 中的一个开关 | 每台设备可按随机计划启用 airplane、nodata、slow、flaky,也可在上传过程中启用 |
| 多用户错误 | 不支持 | run 在每台设备上以不同时间安排重复运行一个流程,然后由 judge 检查服务端数据:unique、count、noLostUpdate |
| 设备状态 | GUI 面板 | env(GPS、电池、旋转、深色模式、字体、区域设置、GSM、SMS、通话)和 app(权限、深层链接、Doze、内存修剪、存储空间已满)——每个设置器都会读取回当前状态 |
| 折叠屏 / 翻盖屏 | 需要折叠屏 AVD | 在任意克隆上使用 fold / unfold:应用会收到真正的配置变更 |
| 面向 AI Agent | 无可调用内容 | MCP 服务、AGENTS.md、7 个根据症状触发的技能(“应用崩溃”“深层链接无法打开”“同步重复创建了一行”) |
数据在一台 Windows 11 PC(Ryzen 7 5700X、64 GB、WHPX)上测得,使用 3 台设备,并与 3 个原生 google_apis AVD 对比。原始 JSON 和测量方法见 docs/measurements/。
按设计,这里没有同步屏障。真正的并发错误来自重试、离线队列和延迟编辑相互重叠——而不是在完全相同的毫秒按下按钮。crewdroid 为每台设备设置不同的延迟和网络计划,让操作自然重叠,然后从服务端读取真实数据(ADR 0002)。
60 秒快速体验
启动一组不同型号的设备(无头运行,屏幕上不会出现任何内容):
$ crewdroid up --count 3 --json
[
{ "serial": "emulator-5580", "profile": "s24ultra", "api": 34, "screen": "1080x2340@450", "bootSeconds": 6.4, "readySeconds": 42.1 },
{ "serial": "emulator-5582", "profile": "fold5-main", "api": 34, "screen": "1812x2176@420", "bootSeconds": 6.7, "readySeconds": 41.8 },
{ "serial": "emulator-5584", "profile": "flip7-main", "api": 36, "screen": "1080x2520@480", "bootSeconds": 3.1, "readySeconds": 39.9 }
]
在上传过程中切断一台设备的数据连接,并让另一台设备进入不稳定网络状态:
$ crewdroid net emulator-5580 nodata
$ crewdroid net emulator-5582 flaky
针对存在竞争条件的服务端运行多用户场景(在捆绑的示例服务端中设置 BUGGY=1),并查看判定结果:
$ crewdroid run scenarios/photo-upload.json --seed 1
...
VIOLATION uploads unique(key): duplicate key="u13-1" (2 rows)
VIOLATION uploads count(acks): missing 1 of 48 expected key values
VIOLATION writes noLostUpdate(id,baseVersion): lost update: 3 writes to id="r2" all based on baseVersion=4; all but one were overwritten
FAIL: 5 violations # exit code 1
对修复后的服务端运行相同场景 → OK: 3 rules, 0 violations,退出码为 0。判定规则是一个 JSON 文件,因此同样的检查也可以用于你自己的 API 导出数据。
无需截图,直接询问屏幕上显示了什么:
$ crewdroid screen emulator-5580 --json
{ "focused": "dev.crewdroid.probe/.ProbeActivity",
"tree": [ { "cls": "TextView", "text": "outbox: 1 pending", "bounds": [32,180,620,230], "clickable": false, "depth": 3 }, ... ] }
专为 Agent 构建
- 每条命令都可由机器读取:
--json;失败时返回非零退出码;每次设置后都会读回;输入无效时,在任何 adb 调用前清晰报错。 - MCP 服务:
crewdroid mcp通过 stdio 暴露devices、up、down、net、env、app、fold、triage、screen、perf、apk、judge、hammer、run——与 CLI 调用的是同一组函数,没有第二套实现。 - 技能位于
.agents/skills/(由 Claude Code、Cursor、Gemini CLI、Copilot、Codex 读取):crewdroid、android-triage、android-screen、android-permissions-intents、android-apk、android-perf、android-offline-concurrency。每项都是一份简短操作指南,包含 Agent 可根据其输出采取行动的精确命令。 AGENTS.md包含 Agent 必须遵守的规则(adb 只能针对emulator-<port>执行;一次只运行一个任务;绝不使用屏障),另有供 Claude Code 使用的CLAUDE.md。- 适用于共享机器:绝不会触碰连接到同一台 PC 的 USB 手机;克隆实例为只读;
down只会终止crew-*。
{ "mcpServers": { "crewdroid": { "command": "npx", "args": ["-y", "crewdroid", "mcp"] } } }
claude plugin marketplace add namyunsu/crewdroid && claude plugin install crewdroid@crewdroid
Cursor:安装 MCP 服务 · Codex / Gemini CLI / Copilot:技能和 AGENTS.md 会从仓库中自动读取。
可发现的问题
| Bug 类别 | crewdroid 如何复现 | 捕获问题的规则 |
|---|---|---|
| 重试后重复上传(缺少幂等性) | flaky 网络会丢弃响应,应用的发件箱会使用相同的密钥重试 | unique(key) |
| 记录丢失(重启 / 飞行模式时发件箱数据丢失) | 保存期间启用 airplane,应用离线重启,然后重新连接 | count(acks) |
| 更新丢失(两位用户编辑同一行,最后写入者胜出) | 设备在不同时间读取同一版本,然后都执行 PUT | noLostUpdate(id,baseVersion) |
| 上传期间折叠 | 发件箱排空期间执行 fold / unfold:应用必须在配置更改后正常运行,且只上传一次 | unique + count |
| 仅在某个 Android 版本或屏幕上发生崩溃 / ANR | 一次运行中混合使用 API 31/34/36 和 S/Fold/Flip 配置;triage 会读取崩溃缓冲区、ANR 和退出原因 | — |
捆绑的示例应用(Kotlin、离线发件箱,probe-app/)和示例服务(sample/server/,通过 BUGGY=1 开关控制)让上表中的每个问题都能在笔记本电脑上复现。
要求
- Android SDK,包含命令行工具和版本不低于 36.4 的模拟器(
ANDROID_SDK_ROOT或ANDROID_HOME必须指向该 SDK,或必须存在~/.crewdroid/android-sdk)。尚未安装 SDK?运行npx crewdroid setup --yes,即可安装 JDK 17(仅供 sdkmanager 使用)、命令行工具、platform-tools、模拟器和google_atd镜像(--images 34,31,36,--dry-run会先列出大小);crewdroid 会下载主机 CPU 所需的google_atd镜像(x86_64,或 Apple Silicon / ARM Linux 上的 arm64-v8a;API 31/34/36,每个约 0.9 GB),并使用slim缩减镜像 - Node >= 22
- Windows 10/11 x64、Apple Silicon 上的 macOS,或 Linux x64/arm64
- 硬件加速:WHPX(Windows)、Hypervisor.framework(macOS)或 KVM(Linux,
/dev/kvm);setup会报告emulator -accel-check的结果 - macOS/Linux:
slim会跳过 NTFS 稀疏化 / 压缩步骤(快照清零和过期覆盖层清理仍会执行);RAM 数值为进程 RSS(共享页面不会拆分)
命令
每个命令都接受 --json,失败时以非零状态码退出。
| 命令 | 功能 |
|---|---|
crewdroid up --count N [--profiles a,b] [--screen WxH[@dpi],...] [--profiles-file f.json] | 启动 N 台模拟器,使用 Galaxy 配置或自定义屏幕(任意尺寸,例如 --screen 3840x2160@320) |
crewdroid down | 关闭所有 crew-* 模拟器 |
crewdroid net <serial> airplane|nodata|slow|flaky|online | 设置一台设备的网络状态 |
crewdroid fold <serial> / unfold <serial> | 在 Fold/Flip 配置上切换封面屏和主屏 |
crewdroid run <scenario.json> [--seed N] | 运行多设备场景,然后检查服务端数据 |
crewdroid judge --rules <file> --source <url|file> | 检查 unique / count / noLostUpdate 规则 |
crewdroid hammer --url <base> | 无需设备即可对服务端施加并发负载 |
crewdroid slim / prepare / identity | 缩减磁盘占用、构建基础 AVD、使设备各不相同 |
crewdroid measure --up N | 测量磁盘、RAM、启动时间和空闲 CPU |
crewdroid triage / screen / perf / apk | Android 诊断,见下文 |
crewdroid env <serial> <what> [args] | 设备环境:位置、电池、旋转、深色模式、字体、区域设置、移动网络、SMS、通话(见 Environment) |
crewdroid app <serial> <pkg> <what> [args] | 应用控制:权限、深层链接 / App Links、清除数据、备份 / 恢复、资源压力(见 App control) |
crewdroid shot / tap / type / swipe / key | 无需 mobile-mcp 即可截图和输入(见 Screenshots and input) |
crewdroid mcp | 通过 stdio MCP 服务向 Agent 提供上述功能 |
截图和输入
| 命令 | 功能 |
|---|---|
crewdroid shot <serial> [file.png] | 将 exec-out screencap -p 输出到 file.png(默认 ./crewdroid-<serial>-<yyyymmdd-HHMMSS>.png);打印路径、宽 x 高和 blackRelaunch(先恢复 API 31 黑屏,与 screen 相同)。MCP 工具会将 PNG 作为图像内容返回,并附带一行文本。 |
crewdroid tap <serial> <x> <y> | --text <T> | --id <resource-id> [--index N] | 在指定坐标点击,或点击 screen 树中与文本 / content-desc 或 resource-id(完整匹配或匹配 :id/ 后的部分)相符元素的中心:先精确匹配,再进行不区分大小写的包含匹配。没有匹配项,或未指定 --index(从 0 开始)但存在多个匹配项时,以状态码 1 退出并列出候选项(文本、id、边界)。 |
crewdroid type <serial> <text> [--into <text|id>] | 执行 input text(空格、引号、&、% 会进行转义);--into 会先点击字段。仅支持 ASCII,见下文。 |
crewdroid swipe <serial> up|down|left|right [--times N] | swipe <serial> x1 y1 x2 y2 [ms] | 沿当前屏幕中央 50 % 区域的指定方向滑动(up 会向下滚动内容)。 |
crewdroid key <serial> back|home|enter|delete|tab|menu|KEYCODE_* | 执行 input keyevent;随后打印当前聚焦的窗口。 |
屏幕范围之外的坐标会在发送任何内容之前以状态码 1 退出。不会输入非 ASCII 文本(例如韩文):type 会以状态码 1 退出并说明原因。input text 只能输入设备键盘映射中的字符;ATD 没有可用于设置剪贴板以便粘贴的 shell 命令(cmd clipboard 尚未实现),而 crewdroid 不会安装键盘应用;请通过你的应用传入此类文本(intent extra、测试钩子),或自行安装 ADBKeyboard 等 IME。探测应用提供了相应表单:--es check form(字段 id 为 name,按钮 Send -> CrewProbe FORM <text>;包含 3 个屏幕的滚动内容,其底部的 END 会记录 CrewProbe SCROLL END)。node scripts/check-input.mjs 会在 API 34 和 API 36 设备上运行所有这些测试。
诊断
只读命令(不会在设备上持续运行)。每条命令都支持 --json;这四条命令也都是 MCP 工具。
| 命令 | 输出 |
|---|---|
crewdroid triage <serial> [--app <pkg>] [--heap out.hprof] | crashes(logcat 崩溃缓冲区:包名、异常、应用中的顶部堆栈帧、时间)、anrs(ActivityManager 日志 + dumpsys activity exit-info)、anrTraces(/data/anr 标头,未获取 root 权限时为 "unreadable")、exits(退出原因)、recentLog(应用最近 200 行日志)、summary。--heap 会运行 am dumpheap 并拉取 hprof 文件。 |
crewdroid screen <serial> [--png file] | 当前焦点窗口(dumpsys window)和精简的 uiautomator 树 [{cls, text, desc, id, bounds, clickable, depth}]。仅当 testTagsAsResourceId = true 时,Compose testTag 才会显示为 id。在 API 31 上,如果应用重新启动后留下全黑屏幕(Android 12 模拟器缺陷,任何工具的 am start -S 都会触发),会先恢复屏幕(HOME + 恢复应用),并报告为 blackRelaunch,因此不会误判为应用缺陷。 |
crewdroid perf <serial> <pkg> [--activity .Main] [-- <am start extras>] | 冷启动(am force-stop、2 秒、am start -W;TotalTime 毫秒)、来自 dumpsys gfxinfo 的帧数 / 卡顿率 / p50-p90-p99,以及来自 dumpsys meminfo 的 PSS 总量 / Java / native 内存(KB)。ATD 镜像没有 GPU:请比较不同运行之间的帧数,不要与手机比较。 |
crewdroid apk <file.apk> | 仅在主机上运行(使用最新 build-tools 中的 aapt2):包名、版本、最低 / 目标 SDK、权限、导出的 Activity、深层链接过滤器。 |
探测应用提供了这些目标:adb -s emulator-5580 shell am start -n dev.crewdroid.probe/.ProbeActivity --es check crash|anr|jank(anr:点击按钮,然后在 10 秒内再次点击)。node scripts/check-triage.mjs 会在一台 API 34 设备上运行全部四项检查。
环境
crewdroid env <serial> <what> [args] [--json]。每个设置器都会回读状态;如果状态不符,会显示消息并以状态码 1 退出;无效值(battery 150、rotate 9、不是 emulator-<port> 格式的 serial)会在调用 adb 前以状态码 1 退出。另有一个 MCP 工具(env)。
| What | 含义 |
|---|---|
geo <lon> <lat> [alt] | GPS 定位(先经度)并开启位置服务。只有应用请求位置信息时,Android 才会收到定位结果,因此设置器无法因状态不符而失败:它只检查位置服务是否开启,并报告 Android 上次看到的定位结果(androidLastFix、delivered)。只有探测器的 ENV loc= 行(check=env)才能确认定位结果 |
| `battery <0-100> [ac | unplugged]` |
rotate <0-3> | 关闭自动旋转,固定旋转方向 |
sensor acceleration x:y:z | 加速度计数值 |
| `dark on | off/font ` |
locale <pkg> <tags> | 应用级语言区域设置,例如 locale dev.crewdroid.probe ko-KR,en;仅适用于 API 33+(没有用于设置设备全局语言区域的 shell 命令) |
| `gsm data home | roaming |
gsm signal <0-31> [--hold <sec>] | 信号强度;控制台会保持 15 s,--hold 会每隔 10 s 重新发送一次。没有回读机制(仅控制台确认) |
sms <from> <text> / `call [accept | cancel]` |
show | 回读设备上的上述所有状态 |
rotate 还会运行 wm fixed-to-user-rotation enabled:如果不这样做,在 API 36 镜像上,WindowManager 会在下次启动应用时恢复之前的旋转方向(revertOverride)。rotate 和 show 会从设置和 WindowManager 回读锁定状态。只有控制台返回 OK 才能确认 gsm signal(没有回读机制)。支持负数(env emulator-5580 geo -122.084 37.422)。ATD 没有 Messages 或 Dialer 应用:短信和电话只会更改电话状态并发送广播。探测器应用会记录它看到的内容:am start -n dev.crewdroid.probe/.ProbeActivity --es check env -> CrewProbe ENV dark=<bool> font=<scale> rot=<n> battery=<pct> loc=<lat>,<lon>|none(loc 需要位置权限:pm grant)。node scripts/check-env.mjs 会在 2 台设备上运行所有这些检查。
应用控制
crewdroid app <serial> <pkg> <what> [args] [--json]。设置操作会读回状态;如果状态不符,则显示消息并以状态码 1 退出。名称、分组或尺寸无效时,会在执行任何 adb 调用前以状态码 1 退出。也提供 MCP 工具(app)。
| 项目 | 含义 |
|---|---|
| `perm grant | revoke <perm…>/perm show [perm…]` |
open <uri> [--pkg] | am start -a VIEW -c BROWSABLE -d <uri>(--pkg:仅限此应用包)。没有应用能处理该 URI 时,以状态码 1 退出并显示 No Activity found(ATD 没有 Chrome)。运行中的应用只会将其任务调到前台,不会收到 URI:结果会显示 delivered: false;请先强制停止该应用 |
links show / links force <domain> / links reset | App Links(API 31+):pm get-app-links;set-app-links --package <pkg> 2 <domain>(无需联网即可批准);... 0 all |
clear | pm clear;使用 run-as 读回(适用于可调试应用),否则只能读取 pm 返回的 Success |
backup / restore | 使用 com.android.localtransport/.LocalTransport 执行 bmgr(API 34 和 36 镜像中提供;若缺失,则以状态码 1 退出并说明原因)。传输服务会拒绝备份没有数据的应用。restore 使用最新的备份集 |
pressure doze / `standby <active | working_set |
pressure trim <level> | am send-trim-memory(从 HIDDEN 到 COMPLETE)。设备上无法读回:只能读取 am 的确认信息。向前台进程设置后台级别,或目标进程未运行时,都会报错。探测程序会记录 CrewProbe TRIM <level> |
pressure reset | 撤销 doze、电池拔出、待机分组(-> active)、bg-restrict 和 battery-saver |
fill-storage <GB> / fill-storage free | 使用 fallocate 在 /data/local/tmp 中创建文件,并通过 df -k /data 读回;free 会删除该文件。镜像约有 5.8 GB 可用空间 |
探测应用配置了深层链接 crewdroid://probe/* 和 https://probe.crewdroid.example/*(autoVerify),并会记录 CrewProbe LINK <uri>。node scripts/check-app.mjs 会在 2 台设备上运行全部检查。
添加设备配置
配置是一个屏幕(宽 x 高、密度),启动后通过 wm size / wm density 应用,而不是单独的 AVD。在 profiles/galaxy.json 中添加一项:
{ "name": "s25", "model": "Galaxy S25", "width": 1080, "height": 2340, "density": 420, "minAndroid": "15", "minApi": 35 }
然后运行 crewdroid up --count 1 --profiles s25。minApi 决定设备使用哪个 Android 镜像。
无需编辑该文件即可使用任意尺寸:crewdroid up --count 2 --screen 1920x720@160,3840x2160@320(密度可选,会根据约 360dp 的短边推算),或使用 --profiles-file my.json(结构相同;参见 profiles/custom.example.json)。尺寸可以超过主机显示器范围——已测试至 7680x2160;参见 docs/measurements/size.md。
安全规则
- 每次 adb 调用都会经过防护机制,只接受
emulator-<port>序列号,因此绝不会操作同一台机器上的 USB 手机。 - 模拟器以一个基础 AVD 的只读克隆形式运行:不会保存任何更改,
down只会移除crew-*实例。 - 每台机器一次只能运行一个 crewdroid(
up/down会获取锁)。 - SDK 路径只取自
ANDROID_SDK_ROOT/ANDROID_HOME;不会硬编码。
如何保持轻量
克隆一个基础 AVD(-read-only),将系统映像重写为稀疏格式并进行 NTFS 压缩,在快照前将 quickboot RAM 映像填零,使用 -lowram 并将客户机 RAM 设为 896 MB,关闭主机 Vulkan、音频和窗口。每个参数都经过逐一测量:docs/measurements/slim.md(磁盘)、ram.md(RAM)、features.md(各运行时功能的空闲开销——均不会添加守护进程)。
韩语文档:README.ko.md · 许可证:MIT
关键词:Android 模拟器、无头、多设备测试、并发测试、竞争条件、幂等性、更新丢失、离线优先同步、不稳定网络、Galaxy Fold Flip 配置文件、MCP 服务、AI Agent、Claude Code 插件、Agent 技能、移动 QA 自动化。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。