dsh-mobilecode 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/lib/index.js +35 -18
- package/lib/list-rows.js +4 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -202,7 +202,9 @@ classified adb boundary (argv-based, quoted, replay-safe):
|
|
|
202
202
|
- `device_backtrace` — a thread/crash dump without a debugger: sends SIGQUIT
|
|
203
203
|
(`kill -3`), waits for ART to write the trace, reads the newest `/data/anr`
|
|
204
204
|
entry, and falls back to the logcat crash buffer when `/data/anr` is unreadable
|
|
205
|
-
(`engine: "anr-trace" | "logcat-crash"`).
|
|
205
|
+
(`engine: "anr-trace" | "logcat-crash"`). SIGQUIT refusal (system-uid or
|
|
206
|
+
non-debuggable process) degrades to the crash buffer with an explanatory note
|
|
207
|
+
instead of failing. Pass `package_name` or `pid`.
|
|
206
208
|
|
|
207
209
|
**Conversation surface (v0.7.0)** — the transcript integration ported from
|
|
208
210
|
dsh-android's UI/UX:
|
package/lib/index.js
CHANGED
|
@@ -531,6 +531,10 @@ function makeRoutes(engine, config, stream) {
|
|
|
531
531
|
const argv = DEVICE_ACTIONS[action]
|
|
532
532
|
if (argv === undefined) { writeJson(res, 400, { code: 'unknown_action', error: `unknown device action "${action}"` }); return }
|
|
533
533
|
if (!StreamAccess.SERIAL_PATTERN.test(serial)) { writeJson(res, 400, { code: 'bad_request', error: 'device must be an adb device serial' }); return }
|
|
534
|
+
if (serial !== stream.host.streamedSerial) {
|
|
535
|
+
const online = await stream.host.listDevices()
|
|
536
|
+
if (!online.some((device) => device.serial === serial)) { writeJson(res, 409, { code: 'device_not_found', error: `device ${serial} is not online` }); return }
|
|
537
|
+
}
|
|
534
538
|
try {
|
|
535
539
|
await DeviceBuild.adbRun(serial, ['shell', ...argv])
|
|
536
540
|
writeJson(res, 200, { ok: true, action, device: serial })
|
|
@@ -1647,7 +1651,8 @@ function deviceBacktraceTool() {
|
|
|
1647
1651
|
name: 'device_backtrace',
|
|
1648
1652
|
description: 'Capture a native/ANR thread backtrace or crash log for an app on the device. Sends SIGQUIT (kill -3) to the process, ' +
|
|
1649
1653
|
'waits for the ART runtime to write the thread dump, then reads the newest /data/anr entry. When /data/anr is unrunnable it falls ' +
|
|
1650
|
-
'back to the logcat crash buffer and says so (engine field: "anr-trace" | "logcat-crash").
|
|
1654
|
+
'back to the logcat crash buffer and says so (engine field: "anr-trace" | "logcat-crash"). SIGQUIT refusal (system-uid or ' +
|
|
1655
|
+
'non-debuggable process) degrades to the crash buffer with an explanatory note instead of failing. Pass package_name or pid.',
|
|
1651
1656
|
parameters: {
|
|
1652
1657
|
serial: { type: 'string', description: 'Android device serial. Omit to use the first attached device.' },
|
|
1653
1658
|
package_name: { type: 'string', description: 'Package of the process to trace (e.g. com.simspoof.app).' },
|
|
@@ -1695,22 +1700,32 @@ function deviceBacktraceTool() {
|
|
|
1695
1700
|
if (pid === undefined) {
|
|
1696
1701
|
throw new Error(`device_backtrace could not resolve a running process for ${packageName ? `"${packageName}"` : 'the request'} on ${serial} — pass a package_name of a running app, or an explicit pid.`)
|
|
1697
1702
|
}
|
|
1698
|
-
// SIGQUIT: the ART runtime writes the thread dump to /data/anr/.
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
})
|
|
1703
|
+
// SIGQUIT: the ART runtime writes the thread dump to /data/anr/. The adb
|
|
1704
|
+
// shell user cannot signal system-uid / non-debuggable processes on
|
|
1705
|
+
// enforcing builds (EPERM) — degrade honestly instead of throwing.
|
|
1706
|
+
let sigquit = true
|
|
1707
|
+
try {
|
|
1708
|
+
await DeviceBuild.adbRun(serial, ['shell', 'kill', '-3', String(pid)])
|
|
1709
|
+
} catch {
|
|
1710
|
+
sigquit = false
|
|
1711
|
+
}
|
|
1712
|
+
let newest
|
|
1713
|
+
if (sigquit) {
|
|
1714
|
+
await new Promise((resolve) => setTimeout(resolve, 1200))
|
|
1715
|
+
const listing = await DeviceBuild.adbRun(serial, ['shell', 'ls', '-t', '/data/anr']).catch(() => undefined)
|
|
1716
|
+
newest = (listing ?? '').split(/\r?\n/).map((line) => line.trim()).filter((line) => line !== '' && !line.includes(' '))[0]
|
|
1717
|
+
if (newest !== undefined) {
|
|
1718
|
+
const content = await DeviceBuild.adbRun(serial, ['shell', 'cat', DeviceBuild.shQuoteDevice(`/data/anr/${newest}`)], { timeoutMs: 30_000 }).catch(() => undefined)
|
|
1719
|
+
if (content !== undefined && content.trim() !== '') {
|
|
1720
|
+
return DeviceBuild.jsonSafe({
|
|
1721
|
+
serial,
|
|
1722
|
+
engine: 'anr-trace',
|
|
1723
|
+
...(packageName ? { package_name: packageName } : {}),
|
|
1724
|
+
pid,
|
|
1725
|
+
trace_path: `/data/anr/${newest}`,
|
|
1726
|
+
lines: content.split(/\r?\n/).slice(-250),
|
|
1727
|
+
})
|
|
1728
|
+
}
|
|
1714
1729
|
}
|
|
1715
1730
|
}
|
|
1716
1731
|
// Fallback: the logcat crash buffer (FATAL/AndroidRuntime lines), filtered by package when known.
|
|
@@ -1724,7 +1739,9 @@ function deviceBacktraceTool() {
|
|
|
1724
1739
|
engine: 'logcat-crash',
|
|
1725
1740
|
...(packageName ? { package_name: packageName } : {}),
|
|
1726
1741
|
pid,
|
|
1727
|
-
note:
|
|
1742
|
+
note: sigquit
|
|
1743
|
+
? `SIGQUIT sent to pid ${pid}; /data/anr was ${newest === undefined ? 'empty/unreadable' : `read but produced no content for ${newest}`}; the logcat crash buffer has no matching FATAL lines now. The app may not have crashed — check device_log for the main buffer.`
|
|
1744
|
+
: `SIGQUIT refused for pid ${pid} — the adb shell user cannot signal this process (system uid or non-debuggable app on an enforcing build), so no fresh thread dump exists; the logcat crash buffer has no matching FATAL lines either. Target a debuggable app for a live dump, or use an adb-rooted device.`,
|
|
1728
1745
|
lines: [],
|
|
1729
1746
|
})
|
|
1730
1747
|
}
|
package/lib/list-rows.js
CHANGED
|
@@ -140,6 +140,10 @@ export function parseCounters(label) {
|
|
|
140
140
|
const rawKey = match[3].trim()
|
|
141
141
|
if (rawKey === "") continue
|
|
142
142
|
const key = normalizeCountKey(rawKey)
|
|
143
|
+
// A counter key must contain a letter: serial-ish strings like
|
|
144
|
+
// "sdk_gphone64_x86_64" backtrack to punctuation-only keys ("_") that are
|
|
145
|
+
// never real counters.
|
|
146
|
+
if (!/\p{L}/u.test(key)) continue
|
|
143
147
|
if (seen.has(key)) continue
|
|
144
148
|
seen.add(key)
|
|
145
149
|
counters.push({ key, value: number * multiplier, raw: match[0].trim() })
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mobilecode",
|
|
3
|
-
"description": "MobileCode for the dsh web GUI: detect iOS/Android projects, run preview servers, and drive the simulator/emulator from the session —
|
|
4
|
-
"version": "0.7.
|
|
3
|
+
"description": "MobileCode for the dsh web GUI: detect iOS/Android projects, run preview servers, and drive the simulator/emulator from the session — 28 agent tools (device_run, device_screen, device_ui_tree, device_ui_rows, device_tap_row, device_tap_element, device_wait_for, device_scroll_to, device_input, device_intent, device_connect, device_pair_qr, device_perf, device_meminfo, device_backtrace, device_app_info, device_install, device_uninstall, device_reboot, device_log, live screen stream, multimodal screenshots) with one classified adb boundary and a Wi-Fi connect/pair QR flow in the Connection settings tab. Hot-pluggable — mounted via the profile bundle list + cordis.patch.yml, no dsh source changes.",
|
|
4
|
+
"version": "0.7.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.22.0",
|
|
7
7
|
"engines": {
|