Skip to content

feat: add Android native perf profiling#757

Open
thymikee wants to merge 7 commits into
mainfrom
fix/android-native-perf
Open

feat: add Android native perf profiling#757
thymikee wants to merge 7 commits into
mainfrom
fix/android-native-perf

Conversation

@thymikee

Copy link
Copy Markdown
Member

Summary

Adds Android native profiling collectors under the consolidated perf family for #694.

  • Adds perf cpu profile start|stop|report --kind simpleperf and perf trace start|stop --kind perfetto across command contracts, CLI grammar, daemon routing/projection, typed client metadata, MCP-facing input, and compact output.
  • Adds Android collector seams for package/PID resolution, bounded adb simpleperf/perfetto execution, artifact pulling, Simpleperf JSON reports, and actionable unavailable/permission hints.
  • Keeps output agent-friendly: artifact paths and compact summaries only, no raw trace/profile dumps.

Refs #696
Refs #694

Touched files: 24.

Validation

Worker validation passed:

  • Focused perf/CLI/client/daemon tests.
  • pnpm check:quick.
  • pnpm build.
  • pnpm check:unit outside sandbox: 247 unit files, 2332 unit tests, 8 smoke tests.
  • pnpm format.
  • git diff --check.

Android emulator E2E:

  • Emulator: emulator-5554, Pixel 9 Pro XL API 37.
  • App/package: com.justforfun.neoncity.
  • Session: perf-e2e-696.
  • Baseline perf metrics and perf frames succeeded with compact JSON.
  • Perfetto start/stop succeeded and pulled /private/tmp/agent-device-696-app.perfetto-trace at 5,392,410 bytes.
  • Simpleperf reached the device binary but the emulator denied perf_event_open; the command returned the intended actionable hint to use a debuggable/profileable app or system image that permits profiling.

SkillGym case was added but not runnable in the sandbox because external runner approval was denied.

This PR is Android-only. iOS native profiling remains separate.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://callstack.github.io/agent-device/pr-preview/pr-757/

Built to branch gh-pages at 2026-06-11 15:25 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 1.2 MB 1.2 MB +15.6 kB
JS gzip 400.1 kB 404.5 kB +4.4 kB
npm tarball 519.3 kB 523.1 kB +3.8 kB
npm unpacked 1.7 MB 1.8 MB +15.6 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 28.5 ms 28.7 ms +0.2 ms
CLI --help 44.6 ms 45.2 ms +0.6 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/session.js +13.5 kB +3.8 kB
dist/src/args.js +970 B +253 B
dist/src/8173.js +779 B +236 B
dist/src/1352.js +320 B +87 B

Copy link
Copy Markdown
Member Author

Code review

Verdict: significant issues — solid scaffolding and bounded outputs, but lifecycle gaps (default stop path, double-start, artifact integrity on stop) need fixing before merge.

Findings

  1. Majorsrc/daemon/handlers/session-native-perf.ts:156,192 + :218-233: stop without --out passes the session's absolute active.outPath as fallbackFileName into pathJoinSessionArtifact, producing a mangled nested path like <sessionDir>/2026-06-11T...-/home/user/.../cpu.perf.data instead of reusing the outPath that start advertised. Should be if (!requestedPath) return active.outPath. The daemon test always passes --out on stop, so this path is untested and masked.

  2. Majorsrc/daemon/handlers/session-native-perf.ts:127-136,179-188: start never checks for an already-running session.nativePerf.android session. A second perf cpu profile start (or a perf trace start while simpleperf runs — the single android slot is shared across both kinds) silently overwrites the stored session, orphaning the previous on-device process for up to the 60-minute cap and leaking its remote artifact with no way to stop or pull it.

  3. Majorsrc/platforms/android/perf-native.ts:386-392 + :204-212: stop sends SIGINT, waits at most 2 s, sends SIGTERM, and returns — adb pull then races the profiler still flushing perf.data/the perfetto trace. Simpleperf's post-SIGINT write easily exceeds 2 s for non-trivial profiles, yielding a truncated artifact reported as a successful stop with a valid size.

  4. Minorsrc/platforms/android/perf-native.ts:294-306,402-421: no device-side cleanup — remotePath is never rm'd after pull, and the stderr temp file is only removed on the failure branch, so every successful start leaks an .err file in /data/local/tmp.

  5. Minor — daemon restart or session close mid-profile loses the in-memory nativePerf state with no kill/cleanup hook, orphaning the device profiler (mitigated by the 3600 s hard cap, but worth a cleanup hook on session delete).

  6. Minorsrc/platforms/android/perf-native.ts:12,408-410: adb pull reuses the 30 s ANDROID_NATIVE_PROFILE_TIMEOUT_MS; long runs can produce hundreds of MB, and stop then fails after the profiler was already killed.

  7. Minorsrc/platforms/android/perf-native.ts:318 vs :260-262: perfetto --background-wait is only available on Android 12+ while the unavailable-hint promises "Android 10+"; on 10/11 the flag fails with a confusing error rather than the actionable hint.

  8. Minor (tests) — the perfetto collector path has zero unit coverage (only the iOS-rejection case is tested), and there are no tests for double-start or stop-without---out (which would have caught findings 1–2).

Verified clean

Command injection — composed shell strings consistently use shellQuote, remotePath is built from a sanitized package name, and the unquoted pidof <package> argv matches existing repo convention. Output boundedness — report entries capped at 50, compact projections, report JSON kept on disk.

Overall

The seams (injectable executor, compact projections, actionable hints) are well designed and quoting discipline is good, but session lifecycle is the weak spot — the default stop path bug, the unguarded double-start, and the 2-second flush window are real correctness risks agents will hit in normal use. Note also high merge-conflict risk with #755/#756/#759 on the shared perf contract/CLI grammar files (see the cross-PR note on #755) — these should land sequentially with deliberate reconciliation.


Generated by Claude Code

@thymikee thymikee force-pushed the fix/android-native-perf branch 2 times, most recently from 1346b29 to 5928d03 Compare June 11, 2026 13:25
@thymikee thymikee force-pushed the fix/android-native-perf branch from 5928d03 to 5795c94 Compare June 11, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant