Skip to content

fix(emulator): MuMu 命令输出混有日志时仍能取到设备信息 - #621

Merged
ClozyA merged 3 commits into
AUTO-MAS-Project:devfrom
qiyinxi:fix/sentry-mumujson-20260908
Sep 10, 2026
Merged

fix(emulator): MuMu 命令输出混有日志时仍能取到设备信息#621
ClozyA merged 3 commits into
AUTO-MAS-Project:devfrom
qiyinxi:fix/sentry-mumujson-20260908

Conversation

@qiyinxi

@qiyinxi qiyinxi commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Closes #620

问题

get_device_infoif_merge_std=TrueMuMuManager info -v,MuMu 自己的埋点C++ 日志因此和设备 JSON 混在同一份 stdout 里。mumu.py 里 5 处 json.loads 都要求整段是纯 JSON,多一行日志就整条失败——而那份设备 JSON 本身是完整可用的6K 的事件里 is_android_started: true 都在,只是尾部多了一行日志)。

近一日:1M 1,943 条(自 08-20 累计 2,113)、6G 1 条、6K 1 条。1M 是模拟器族里事件量最大的一条。

需要说清楚这条和「模拟器自身故障」不是一回事WinError 5 / WinError 2 那批确实是用户侧环境问题,不该我们修;这批是我方解析口径过严。

改动

新增 MumuManager._decode_polluted_json(text, prefer=None):扫出输出里所有顶层 JSON 值,由 prefer 判据挑出期望的那一份,都不命中时退回第一个,一个都解不出来才抛 JSONDecodeError

不能简单取第一个 —— 埋点 add record:{"_track_id":...} 本身也是合法 JSON,而且常常排在设备 JSON 之前,取第一个会把埋点当成设备信息。所以 5 个调用点各带自己的判据:

调用点 prefer
getStatus / getInfo / list_devices _has_device_entries(有 index + name
_get_adb_address 能解析出 host/port
_get_app_state dict 且 state 是 str

本地验证

.venv/Scripts/python.exe -m pytest tests -q
691 passed, 3 skipped, 151 subtests passed in 9.29s          (dev 基线是 682,+9 为本 PR 新增)

.venv/Scripts/python.exe -m ruff check app/utils/emulator/mumu.py   # All checks passed

新增 tests/tools/test_mumu_json_parse.py 9 条(纯解析逻辑,按 tests/AGENTS.md 属于该提交的纯逻辑测试)。样本用的是 Sentry 事件里的真实污染形态:

  • 尾部 [*** LOG ERROR #0001 ***] ... {bad_weak_ptr}
  • 头部 add record:{"_track_id":...,"event":"$SignUp",...}

这些样本在改动前确实是炸的,且报错与 Sentry 上一字不差:

尾部 C++ 日志: json.loads -> Extra data: line 5 column 1 (char 150)     ← 对应 6G
头部埋点:     json.loads -> Expecting value: line 1 column 1 (char 0)   ← 对应 1M
两者都有:     json.loads -> Expecting value: line 1 column 1 (char 0)

其中一条专门断言「埋点排在前面也不能被当成设备信息返回」。

没有做真机手测:本地这台 MuMu 不会往 stdout 写埋点,复现不了污染。解析是纯函数、由上面 9 条覆盖;但真机上 getInfo 拿到的输出格式如果和我构造的样本有出入,欢迎指出。

请审阅

@qiyinxi app/utils/emulator 是你维护的。确认后请你自行合并,我不代合。

Sourcery 总结

允许 MuMu 命令解析从混入遥测数据和原生日志的标准输出中恢复有效的模拟器数据。

错误修复:

  • 使 MuMu 设备、ADB 和应用状态解析能够适应命令输出中混入的遥测数据和原生日志,同时仍选择目标 JSON 负载。

增强功能:

  • 添加共享的污染输出 JSON 解码功能,并支持针对负载的选择条件和回退行为。

测试:

  • 添加针对前置遥测数据、尾随日志、负载选择、回退行为以及无效或空输出的专项测试。
Original summary in English

Sourcery 总结

提高 MuMu 命令输出的解析容错性,确保混入日志时仍能读取模拟器信息。

Bug 修复:

  • 使 MuMu 模拟器、ADB 和应用状态解析能够从混入遥测数据或原生日志的命令输出中恢复有效的 JSON 信息。

增强功能:

  • 新增可识别并选择目标 JSON 负载的通用污染输出解析能力,避免将遥测数据误判为设备信息。

测试:

  • 新增针对前置遥测、尾随日志、负载选择、回退行为及无效输出的解析测试。
Original summary in English

Summary by Sourcery

提高 MuMu 命令输出解析的容错性,确保混入日志时仍能恢复有效的模拟器信息。

Bug Fixes:

  • 修复 MuMu 命令输出混入遥测数据或原生日志时无法读取设备、ADB 和应用状态信息的问题。

Enhancements:

  • 新增可从污染输出中识别并选择目标 JSON 负载的通用解析能力,避免将遥测数据误判为设备信息。

Tests:

  • 新增覆盖前置遥测、尾随日志、负载选择、回退行为及无效输出的 MuMu JSON 解析测试。
Original summary in English

Summary by Sourcery

提高 MuMu 命令输出解析的容错性,确保混入日志时仍能恢复有效的模拟器信息。

Bug Fixes:

  • 修复 MuMu 命令输出混入遥测数据或原生日志时无法读取设备、ADB 和应用状态信息的问题。

Enhancements:

  • 新增可从污染输出中识别并选择目标 JSON 负载的通用解析能力,避免将遥测数据误判为设备信息。

Tests:

  • 新增覆盖前置遥测、尾随日志、负载选择、回退行为及无效输出的 MuMu JSON 解析测试。

get_device_info 用 if_merge_std=True 跑 MuMuManager,MuMu 自己的埋点
(add record:{...}) 与 C++ 日志 ([*** LOG ERROR ***] ... {bad_weak_ptr})
因此和设备 JSON 混在同一份 stdout 里。5 处 json.loads 都要求整段是纯 JSON,
多一行日志就整条失败——而那份设备 JSON 本身是完整可用的。

新增 _decode_polluted_json:扫出输出里所有顶层 JSON 值,由 prefer 判据挑出
期望的那一份。不能简单取第一个——埋点本身也是合法 JSON 且常排在设备 JSON 之前。

Closes AUTO-MAS-Project#620

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@qiyinxi qiyinxi added bug Something isn't working Sentry daily Sentry daily issues labels Sep 8, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @qiyinxi, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 4 days and 3 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Sep 8, 2026

Copy link
Copy Markdown

审查者指南

该 PR 通过提取所有顶层 JSON 值,并选择与每个调用方预期架构匹配的候选值,使 MuMu 命令解析能够适应 stdout 中包含多个无关日志或遥测片段的情况。该行为已应用于设备、ADB 和应用状态解析,并使用具有代表性的污染输出样本添加了回归测试。

受污染 MuMu JSON 解析的时序图

sequenceDiagram
    participant Caller
    participant MumuManager
    participant MuMu
    Caller->>MumuManager: getInfo(idx)
    MumuManager->>MuMu: get_device_info(idx)
    MuMu-->>MumuManager: telemetry + device JSON + logs
    MumuManager->>MumuManager: _decode_polluted_json(data, _has_device_entries)
    MumuManager-->>Caller: device information
Loading

从受污染输出中选择 JSON 的流程图

flowchart TD
    A[MuMu stdout contains logs and JSON fragments] --> B[_decode_polluted_json]
    B --> C[Scan top-level JSON values]
    C --> D{prefer predicate matches?}
    D -->|Yes| E[Return matching candidate]
    D -->|No| F{Any candidate decoded?}
    F -->|Yes| G[Return first candidate]
    F -->|No| H[Raise JSONDecodeError]
    E --> I[Caller-specific parsing]
    G --> I
Loading

文件级变更

变更 详细信息 文件
添加从被遥测或原生日志污染的 MuMu 输出中宽容提取顶层 JSON 值的功能。
  • 使用 JSONDecoder.raw_decode 扫描 stdout,而不是要求整个字符串都是 JSON。
  • 优先选择符合预期设备、ADB 地址或应用状态结构的候选值;如果没有匹配项则回退到第一个候选值,如果没有任何候选值可解析则抛出 JSONDecodeError。
  • 在 MuMu 的全部五个解析调用点使用宽容解码器。
app/utils/emulator/mumu.py
为受污染的 MuMu 命令输出添加针对性的回归测试覆盖。
  • 覆盖前置遥测、尾随 C++ 日志、两者同时存在、干净及单设备负载、回退行为,以及无 JSON 时的错误。
  • 验证在前置遥测对象之后正确选择设备负载。
tests/tools/test_mumu_json_parse.py
更新仓库版本元数据。
  • 作为该拉取请求的一部分修改版本资源。
res/version.json

可能相关的问题


提示和命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 根据审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以回复审查评论并使用 @sourcery-ai issue,以根据该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title,以随时生成或重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文的任意位置写入 @sourcery-ai summary,即可在指定位置随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary,以随时生成或重新生成摘要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时生成或重新生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论且不想再看到它们,这会很有用。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你想从新的审查开始,这尤其有用——别忘了评论 @sourcery-ai review 来触发新的审查!

自定义使用体验

访问你的控制面板以:

  • 启用或禁用审查功能,例如 Sourcery 生成的拉取请求摘要、审查者指南等。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

The PR makes MuMu command parsing resilient to stdout containing multiple unrelated log or telemetry fragments by extracting all top-level JSON values and selecting the candidate matching each caller’s expected schema. It applies this behavior across device, ADB, and app-state parsing and adds regression tests using representative polluted-output samples.

Sequence diagram for polluted MuMu JSON parsing

sequenceDiagram
    participant Caller
    participant MumuManager
    participant MuMu
    Caller->>MumuManager: getInfo(idx)
    MumuManager->>MuMu: get_device_info(idx)
    MuMu-->>MumuManager: telemetry + device JSON + logs
    MumuManager->>MumuManager: _decode_polluted_json(data, _has_device_entries)
    MumuManager-->>Caller: device information
Loading

Flow diagram for selecting JSON from polluted output

flowchart TD
    A[MuMu stdout contains logs and JSON fragments] --> B[_decode_polluted_json]
    B --> C[Scan top-level JSON values]
    C --> D{prefer predicate matches?}
    D -->|Yes| E[Return matching candidate]
    D -->|No| F{Any candidate decoded?}
    F -->|Yes| G[Return first candidate]
    F -->|No| H[Raise JSONDecodeError]
    E --> I[Caller-specific parsing]
    G --> I
Loading

File-Level Changes

Change Details Files
Add tolerant extraction of top-level JSON values from MuMu output contaminated by telemetry or native logs.
  • Scan stdout with JSONDecoder.raw_decode instead of requiring the entire string to be JSON.
  • Prefer candidates matching the expected device, ADB address, or app-state shape, with first-candidate fallback and JSONDecodeError when none parse.
  • Use the tolerant decoder at all five MuMu parsing call sites.
app/utils/emulator/mumu.py
Add focused regression coverage for polluted MuMu command output.
  • Cover leading telemetry, trailing C++ logs, both together, clean and single-device payloads, fallback behavior, and no-JSON errors.
  • Verify device payload selection over a preceding telemetry object.
tests/tools/test_mumu_json_parse.py
Update the repository version metadata.
  • Modify the version resource as part of the pull request.
res/version.json

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sourcery assessment

Approved.

…260908

# Conflicts:
#	CHANGELOG.md
#	res/version.json
@ClozyA
ClozyA merged commit db0ab3e into AUTO-MAS-Project:dev Sep 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working Sentry daily Sentry daily issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants