Skip to content

memory

Structured memory diagnostics for a connected device.

  • get_app_memory_summary / get_app_memory_detailsdumpsys meminfo -s|-a <target>, parsed via the shared adb_automation_mcp.meminfo helpers.
  • get_system_memory_summary — bare dumpsys meminfo: RAM totals + top PSS consumers.
  • get_memory_historydumpsys procstats --hours <h> <package>: the "Process summary" min/avg/max PSS/USS/RSS bands.
  • capture_heap_dumpam dumpheap + adb pull into ADB_AUTOMATION_LOCAL_ROOT/heapdumps/, device temp file cleaned.
  • set_heap_watch / clear_heap_watcham set-watch-heap <pkg> <bytes> / am clear-watch-heap <pkg>: auto-collect a heap dump when a process's PSS crosses a threshold.
  • get_memory_mapscat /proc/<pid>/smaps_rollup: the kernel's per-process Rss/Pss + clean/dirty split + swap aggregates (a fixed compact model, not a generic /proc reader).

adb_automation_mcp.modules.memory.tools

Module-level, statically-introspectable tool functions for the memory module.

Kept as plain top-level functions, never closures, so that documentation tooling and the registry meta-test can both introspect them directly.

capture_heap_dump(ctx: Context, serial: str, package: str, local_path: str, force_gc: bool = False, native: bool = False, user_id: int | None = None, timeout_s: float = 120.0) -> HeapDumpResult async

Capture a heap dump and save it to the host: adb shell am dumpheap then adb pull.

Dumps the managed heap (or the native heap with native=true) of a running process to a device temp file, pulls it into <ADB_AUTOMATION_LOCAL_ROOT>/heapdumps/, and deletes the temp file (on success and on failure). Categorized write because it forces the target process to pause and serialize its heap. The .hprof is not embedded in the response — only its path and size.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required
package str

The process to dump — a package name or a numeric PID as a string. Must be running and debuggable/profileable.

required
local_path str

Destination path relative to the server's local_root heapdumps/ directory, e.g. "app.hprof" or "run1/app.hprof". Must resolve inside local_root.

required
force_gc bool

Pass -g to force a GC before dumping (smaller, cleaner managed heap).

False
native bool

Pass -n to dump the native heap instead of the managed one.

False
user_id int | None

Dump the process for a specific Android user (--user). Omit for the current user.

None
timeout_s float

How long to wait for the dump to finish, 5-600 seconds (default 120). A large heap on a slow device can take a while.

120.0

Returns:

Type Description
HeapDumpResult

The serial and package; local_path (the absolute host path the .hprof was written to); native / force_gc / user_id echoed; and size_bytes (the saved file size, or null if it couldn't be stat'd).

Error handling

A blank package, a negative user_id, or an out-of-range timeout_s raises INVALID_ARGUMENT. No configured local_root, or a local_path escaping it, raises POLICY_DENIED. An unknown serial raises DEVICE_NOT_FOUND. A package that isn't running raises PACKAGE_NOT_RUNNING; one that can't be dumped (not debuggable/ profileable) raises PERMISSION_DENIED. A failed pull raises REMOTE_FILE_NOT_FOUND / BACKEND_ERROR. The device temp file is cleaned up in every case.

Example

Called with serial="emulator-5554", package="com.android.systemui", local_path="systemui.hprof", force_gc=true. A typical response:

{
  "status": "success",
  "message": "Captured managed heap dump of com.android.systemui from emulator-5554 to /data/out/heapdumps/systemui.hprof.",
  "data": {
    "serial": "emulator-5554",
    "package": "com.android.systemui",
    "local_path": "/data/out/heapdumps/systemui.hprof",
    "native": false,
    "force_gc": true,
    "user_id": null,
    "size_bytes": 64329246,
    "success": true
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
@category("write")
async def capture_heap_dump(
    ctx: Context,
    serial: str,
    package: str,
    local_path: str,
    force_gc: bool = False,
    native: bool = False,
    user_id: int | None = None,
    timeout_s: float = 120.0,
) -> HeapDumpResult:
    """Capture a heap dump and save it to the host: `adb shell am dumpheap`
    then `adb pull`.

    Dumps the managed heap (or the native heap with native=true) of a
    running process to a device temp file, pulls it into
    `<ADB_AUTOMATION_LOCAL_ROOT>/heapdumps/`, and deletes the temp file
    (on success and on failure). Categorized `write` because it forces the
    target process to pause and serialize its heap. The .hprof is not
    embedded in the response — only its path and size.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        package: The process to dump — a package name or a numeric PID as a
            string. Must be running and debuggable/profileable.
        local_path: Destination path relative to the server's local_root
            `heapdumps/` directory, e.g. "app.hprof" or "run1/app.hprof".
            Must resolve inside local_root.
        force_gc: Pass `-g` to force a GC before dumping (smaller, cleaner
            managed heap).
        native: Pass `-n` to dump the native heap instead of the managed one.
        user_id: Dump the process for a specific Android user (`--user`).
            Omit for the current user.
        timeout_s: How long to wait for the dump to finish, 5-600 seconds
            (default 120). A large heap on a slow device can take a while.

    Returns:
        The serial and package; local_path (the absolute host path the
        .hprof was written to); native / force_gc / user_id echoed; and
        size_bytes (the saved file size, or null if it couldn't be stat'd).

    Error handling:
        A blank package, a negative user_id, or an out-of-range timeout_s
        raises INVALID_ARGUMENT. No configured local_root, or a local_path
        escaping it, raises POLICY_DENIED. An unknown serial raises
        DEVICE_NOT_FOUND. A package that isn't running raises
        PACKAGE_NOT_RUNNING; one that can't be dumped (not debuggable/
        profileable) raises PERMISSION_DENIED. A failed pull raises
        REMOTE_FILE_NOT_FOUND / BACKEND_ERROR. The device temp file is
        cleaned up in every case.

    Example:
        Called with serial="emulator-5554", package="com.android.systemui",
        local_path="systemui.hprof", force_gc=true. A typical response:

        ```json
        {
          "status": "success",
          "message": "Captured managed heap dump of com.android.systemui from emulator-5554 to /data/out/heapdumps/systemui.hprof.",
          "data": {
            "serial": "emulator-5554",
            "package": "com.android.systemui",
            "local_path": "/data/out/heapdumps/systemui.hprof",
            "native": false,
            "force_gc": true,
            "user_id": null,
            "size_bytes": 64329246,
            "success": true
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.capture_heap_dump(
        serial,
        package,
        local_path,
        force_gc=force_gc,
        native=native,
        user_id=user_id,
        timeout_s=timeout_s,
    )

clear_heap_watch(ctx: Context, serial: str, package: str) -> ClearHeapWatchResult async

Clear a previously configured heap watch: adb shell am clear-watch-heap.

Undoes set_heap_watch for a package. Idempotent — clearing when nothing is watched is a successful no-op.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required
package str

The package whose heap watch to clear, e.g. "com.example.app".

required

Returns:

Type Description
ClearHeapWatchResult

The serial, package, and cleared (always true on success).

Error handling

A blank package raises INVALID_ARGUMENT before anything runs. An unknown serial or unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A permission rejection raises PERMISSION_DENIED; any other failure raises BACKEND_ERROR.

Example

Called with serial="emulator-5554", package="com.example.app". A typical response:

{
  "status": "success",
  "message": "Cleared the heap watch for com.example.app on emulator-5554.",
  "data": {"serial": "emulator-5554", "package": "com.example.app", "cleared": true},
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
@category("write")
async def clear_heap_watch(ctx: Context, serial: str, package: str) -> ClearHeapWatchResult:
    """Clear a previously configured heap watch: `adb shell am
    clear-watch-heap`.

    Undoes set_heap_watch for a package. Idempotent — clearing when nothing
    is watched is a successful no-op.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        package: The package whose heap watch to clear, e.g.
            "com.example.app".

    Returns:
        The serial, package, and cleared (always true on success).

    Error handling:
        A blank package raises INVALID_ARGUMENT before anything runs. An
        unknown serial or unresponsive adb binary raises
        DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A permission rejection raises
        PERMISSION_DENIED; any other failure raises BACKEND_ERROR.

    Example:
        Called with serial="emulator-5554", package="com.example.app". A
        typical response:

        ```json
        {
          "status": "success",
          "message": "Cleared the heap watch for com.example.app on emulator-5554.",
          "data": {"serial": "emulator-5554", "package": "com.example.app", "cleared": true},
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.clear_heap_watch(serial, package)

get_app_memory_details(ctx: Context, serial: str, target: str) -> AppMemoryDetails async

Detailed memory breakdown for one app: adb shell dumpsys meminfo -a.

Returns the App Summary totals plus the per-mapping table (categories: "Native Heap", "Dalvik Heap", ".so mmap", ... "TOTAL"), the "Objects" section (view / binder / parcel / WebView counts) and the "SQL" section. Sections vary by Android version, so objects and sql come back as maps and are empty when absent. The raw dump text is never exposed.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required
target str

A package name or a numeric PID as a string.

required

Returns:

Type Description
AppMemoryDetails

The serial / target / pid / process_name; the App Summary total fields; categories (a list of per-mapping rows with pss/private/ shared/rss/heap columns in KB, columns a build omits are null); objects (name -> count); and sql (name -> value).

Error handling

Same as get_app_memory_summary: INVALID_ARGUMENT for a blank target, PACKAGE_NOT_RUNNING when nothing is running, and MEMORY_INFO_UNAVAILABLE when no memory sections are recognizable; DEVICE_NOT_FOUND / PERMISSION_DENIED / BACKEND_ERROR otherwise.

Example

Called with serial="emulator-5554", target="com.android.systemui". A typical (trimmed) response:

{
  "status": "success",
  "message": "com.android.systemui on emulator-5554: 16 memory categories, 12 object counts.",
  "data": {
    "serial": "emulator-5554",
    "target": "com.android.systemui",
    "pid": 1224,
    "process_name": "com.android.systemui",
    "total_pss_kb": 104328,
    "total_rss_kb": 264948,
    "total_swap_kb": 8,
    "categories": [
      {"name": "Native Heap", "pss_total_kb": 21824, "private_dirty_kb": 21748, "rss_total_kb": 25540}
    ],
    "objects": {"views": 855, "activities": 0, "local_binders": 374},
    "sql": {"memory_used": 0, "malloc_size": 0}
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
@category("read")
async def get_app_memory_details(ctx: Context, serial: str, target: str) -> AppMemoryDetails:
    """Detailed memory breakdown for one app: `adb shell dumpsys meminfo -a`.

    Returns the App Summary totals plus the per-mapping table (categories:
    "Native Heap", "Dalvik Heap", ".so mmap", ... "TOTAL"), the "Objects"
    section (view / binder / parcel / WebView counts) and the "SQL" section.
    Sections vary by Android version, so objects and sql come back as maps
    and are empty when absent. The raw dump text is never exposed.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        target: A package name or a numeric PID as a string.

    Returns:
        The serial / target / pid / process_name; the App Summary total
        fields; categories (a list of per-mapping rows with pss/private/
        shared/rss/heap columns in KB, columns a build omits are null);
        objects (name -> count); and sql (name -> value).

    Error handling:
        Same as get_app_memory_summary: INVALID_ARGUMENT for a blank
        target, PACKAGE_NOT_RUNNING when nothing is running, and
        MEMORY_INFO_UNAVAILABLE when no memory sections are recognizable;
        DEVICE_NOT_FOUND / PERMISSION_DENIED / BACKEND_ERROR otherwise.

    Example:
        Called with serial="emulator-5554", target="com.android.systemui".
        A typical (trimmed) response:

        ```json
        {
          "status": "success",
          "message": "com.android.systemui on emulator-5554: 16 memory categories, 12 object counts.",
          "data": {
            "serial": "emulator-5554",
            "target": "com.android.systemui",
            "pid": 1224,
            "process_name": "com.android.systemui",
            "total_pss_kb": 104328,
            "total_rss_kb": 264948,
            "total_swap_kb": 8,
            "categories": [
              {"name": "Native Heap", "pss_total_kb": 21824, "private_dirty_kb": 21748, "rss_total_kb": 25540}
            ],
            "objects": {"views": 855, "activities": 0, "local_binders": 374},
            "sql": {"memory_used": 0, "malloc_size": 0}
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.get_app_memory_details(serial, target)

get_app_memory_summary(ctx: Context, serial: str, target: str) -> AppMemorySummary async

Compact memory snapshot for one app/process: adb shell dumpsys meminfo -s.

Parses only the stable "App Summary" totals (Java/Native heap, Code, Stack, Graphics, Private Other, System, and TOTAL PSS/RSS/SWAP), all in kilobytes. For the full per-mapping / object / SQL breakdown use get_app_memory_details.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required
target str

A package name (e.g. "com.android.systemui") or a numeric PID as a string.

required

Returns:

Type Description
AppMemorySummary

The serial and target queried; pid / process_name from meminfo's header; and the App Summary Pss category fields plus total_pss_kb / total_rss_kb / total_swap_kb. Any field the build didn't emit is null.

Error handling

A blank target raises INVALID_ARGUMENT before anything runs. An unknown serial or unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A target with no running process ("No process found for: ...") raises PACKAGE_NOT_RUNNING. Output with no recognizable header or TOTAL line raises MEMORY_INFO_UNAVAILABLE. A permission rejection raises PERMISSION_DENIED; any other non-zero exit raises BACKEND_ERROR.

Example

Called with serial="emulator-5554", target="com.android.systemui". A typical response:

{
  "status": "success",
  "message": "com.android.systemui on emulator-5554: 104328 KB total PSS.",
  "data": {
    "serial": "emulator-5554",
    "target": "com.android.systemui",
    "pid": 1224,
    "process_name": "com.android.systemui",
    "java_heap_pss_kb": 25324,
    "native_heap_pss_kb": 21748,
    "code_pss_kb": 37816,
    "stack_pss_kb": 1656,
    "graphics_pss_kb": 0,
    "private_other_pss_kb": 4280,
    "system_pss_kb": 13504,
    "total_pss_kb": 104328,
    "total_rss_kb": 264948,
    "total_swap_kb": 8
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@category("read")
async def get_app_memory_summary(ctx: Context, serial: str, target: str) -> AppMemorySummary:
    """Compact memory snapshot for one app/process: `adb shell dumpsys meminfo -s`.

    Parses only the stable "App Summary" totals (Java/Native heap, Code,
    Stack, Graphics, Private Other, System, and TOTAL PSS/RSS/SWAP), all in
    kilobytes. For the full per-mapping / object / SQL breakdown use
    get_app_memory_details.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        target: A package name (e.g. "com.android.systemui") or a numeric
            PID as a string.

    Returns:
        The serial and target queried; pid / process_name from meminfo's
        header; and the App Summary Pss category fields plus total_pss_kb /
        total_rss_kb / total_swap_kb. Any field the build didn't emit is null.

    Error handling:
        A blank target raises INVALID_ARGUMENT before anything runs. An
        unknown serial or unresponsive adb binary raises
        DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A target with no running process
        ("No process found for: ...") raises PACKAGE_NOT_RUNNING. Output
        with no recognizable header or TOTAL line raises
        MEMORY_INFO_UNAVAILABLE. A permission rejection raises
        PERMISSION_DENIED; any other non-zero exit raises BACKEND_ERROR.

    Example:
        Called with serial="emulator-5554", target="com.android.systemui".
        A typical response:

        ```json
        {
          "status": "success",
          "message": "com.android.systemui on emulator-5554: 104328 KB total PSS.",
          "data": {
            "serial": "emulator-5554",
            "target": "com.android.systemui",
            "pid": 1224,
            "process_name": "com.android.systemui",
            "java_heap_pss_kb": 25324,
            "native_heap_pss_kb": 21748,
            "code_pss_kb": 37816,
            "stack_pss_kb": 1656,
            "graphics_pss_kb": 0,
            "private_other_pss_kb": 4280,
            "system_pss_kb": 13504,
            "total_pss_kb": 104328,
            "total_rss_kb": 264948,
            "total_swap_kb": 8
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.get_app_memory_summary(serial, target)

get_memory_history(ctx: Context, serial: str, package: str, hours: int = 3) -> MemoryHistory async

Historical memory bands for a package: adb shell dumpsys procstats --hours <hours> <package>.

Reads procstats' "Process summary" min/avg/max PSS/USS/RSS bands per process state ("TOTAL", "Top", "Persistent", ...) accumulated over the requested window. procstats samples lazily, so a package that hasn't been sampled in the window returns has_history=false — a normal result, not an error.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required
package str

The package to look up, e.g. "com.example.app".

required
hours int

The look-back window, 1-72 hours (default 3).

3

Returns:

Type Description
MemoryHistory

The serial / package / hours; has_history; window_start (procstats' aggregation start time); and bands — one entry per process state, each with percent, samples, and pss/uss/rss min/avg/max in kilobytes (fields procstats didn't report are null).

Error handling

A blank package or an hours value outside 1-72 raises INVALID_ARGUMENT before anything runs. An unknown serial or unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A permission rejection raises PERMISSION_DENIED; any other non-zero exit raises BACKEND_ERROR. No accumulated history is has_history=false, not an error.

Example

Called with serial="emulator-5554", package="com.android.systemui", hours=3. A typical response:

{
  "status": "success",
  "message": "com.android.systemui on emulator-5554: 2 memory band(s) over the last 3h.",
  "data": {
    "serial": "emulator-5554",
    "package": "com.android.systemui",
    "hours": 3,
    "has_history": true,
    "window_start": "2026-09-07 07:48:12",
    "bands": [
      {
        "state": "TOTAL",
        "percent": 100.0,
        "samples": 8,
        "pss_min_kb": 0,
        "pss_avg_kb": 63488,
        "pss_max_kb": 105472,
        "uss_min_kb": 0,
        "uss_avg_kb": 55296,
        "uss_max_kb": 92160,
        "rss_min_kb": 268288,
        "rss_avg_kb": 264192,
        "rss_max_kb": 268288
      }
    ]
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@category("read")
async def get_memory_history(
    ctx: Context, serial: str, package: str, hours: int = 3
) -> MemoryHistory:
    """Historical memory bands for a package: `adb shell dumpsys procstats
    --hours <hours> <package>`.

    Reads procstats' "Process summary" min/avg/max PSS/USS/RSS bands per
    process state ("TOTAL", "Top", "Persistent", ...) accumulated over the
    requested window. procstats samples lazily, so a package that hasn't
    been sampled in the window returns has_history=false — a normal result,
    not an error.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        package: The package to look up, e.g. "com.example.app".
        hours: The look-back window, 1-72 hours (default 3).

    Returns:
        The serial / package / hours; has_history; window_start (procstats'
        aggregation start time); and bands — one entry per process state,
        each with percent, samples, and pss/uss/rss min/avg/max in
        kilobytes (fields procstats didn't report are null).

    Error handling:
        A blank package or an hours value outside 1-72 raises
        INVALID_ARGUMENT before anything runs. An unknown serial or
        unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A
        permission rejection raises PERMISSION_DENIED; any other non-zero
        exit raises BACKEND_ERROR. No accumulated history is
        has_history=false, not an error.

    Example:
        Called with serial="emulator-5554", package="com.android.systemui",
        hours=3. A typical response:

        ```json
        {
          "status": "success",
          "message": "com.android.systemui on emulator-5554: 2 memory band(s) over the last 3h.",
          "data": {
            "serial": "emulator-5554",
            "package": "com.android.systemui",
            "hours": 3,
            "has_history": true,
            "window_start": "2026-09-07 07:48:12",
            "bands": [
              {
                "state": "TOTAL",
                "percent": 100.0,
                "samples": 8,
                "pss_min_kb": 0,
                "pss_avg_kb": 63488,
                "pss_max_kb": 105472,
                "uss_min_kb": 0,
                "uss_avg_kb": 55296,
                "uss_max_kb": 92160,
                "rss_min_kb": 268288,
                "rss_avg_kb": 264192,
                "rss_max_kb": 268288
              }
            ]
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.get_memory_history(serial, package, hours=hours)

get_memory_maps(ctx: Context, serial: str, pid: int) -> MemoryMaps async

Get a process's memory-map aggregates: adb shell cat /proc/<pid>/smaps_rollup.

Returns the kernel's own rollup totals for a process — Rss/Pss, the shared/private clean/dirty split, and swap — all in kilobytes. This is a fixed compact model, not a generic /proc reader. Access may be restricted to root by SELinux on some builds.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required
pid int

The process id to inspect (a positive integer — see processes.get_process_id / list_processes).

required

Returns:

Type Description
MemoryMaps

The serial and pid, plus rss_kb / pss_kb / pss_dirty_kb / pss_anon_kb / pss_file_kb / pss_shmem_kb / shared_clean_kb / shared_dirty_kb / private_clean_kb / private_dirty_kb / referenced_kb / anonymous_kb / swap_kb / swap_pss_kb / locked_kb. Any field the kernel didn't emit is null.

Error handling

A non-positive pid raises INVALID_ARGUMENT. An unknown serial or unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. smaps_rollup being unreadable (SELinux/root) raises PERMISSION_DENIED; the pid not being a running process raises REMOTE_FILE_NOT_FOUND; output with no recognizable fields raises MEMORY_INFO_UNAVAILABLE.

Example

Called with serial="emulator-5554", pid=1224. A typical (trimmed) response:

{
  "status": "success",
  "message": "pid 1224 on emulator-5554: 127651 KB PSS.",
  "data": {
    "serial": "emulator-5554",
    "pid": 1224,
    "rss_kb": 290988,
    "pss_kb": 127651,
    "private_dirty_kb": 69252,
    "shared_clean_kb": 143216,
    "swap_kb": 8
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
@category("read")
async def get_memory_maps(ctx: Context, serial: str, pid: int) -> MemoryMaps:
    """Get a process's memory-map aggregates: `adb shell cat
    /proc/<pid>/smaps_rollup`.

    Returns the kernel's own rollup totals for a process — Rss/Pss, the
    shared/private clean/dirty split, and swap — all in kilobytes. This is a
    fixed compact model, not a generic /proc reader. Access may be
    restricted to root by SELinux on some builds.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        pid: The process id to inspect (a positive integer — see
            processes.get_process_id / list_processes).

    Returns:
        The serial and pid, plus rss_kb / pss_kb / pss_dirty_kb /
        pss_anon_kb / pss_file_kb / pss_shmem_kb / shared_clean_kb /
        shared_dirty_kb / private_clean_kb / private_dirty_kb /
        referenced_kb / anonymous_kb / swap_kb / swap_pss_kb / locked_kb.
        Any field the kernel didn't emit is null.

    Error handling:
        A non-positive pid raises INVALID_ARGUMENT. An unknown serial or
        unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE.
        smaps_rollup being unreadable (SELinux/root) raises
        PERMISSION_DENIED; the pid not being a running process raises
        REMOTE_FILE_NOT_FOUND; output with no recognizable fields raises
        MEMORY_INFO_UNAVAILABLE.

    Example:
        Called with serial="emulator-5554", pid=1224. A typical (trimmed)
        response:

        ```json
        {
          "status": "success",
          "message": "pid 1224 on emulator-5554: 127651 KB PSS.",
          "data": {
            "serial": "emulator-5554",
            "pid": 1224,
            "rss_kb": 290988,
            "pss_kb": 127651,
            "private_dirty_kb": 69252,
            "shared_clean_kb": 143216,
            "swap_kb": 8
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.get_memory_maps(serial, pid)

get_system_memory_summary(ctx: Context, serial: str) -> SystemMemorySummary async

System-wide memory totals and top consumers: adb shell dumpsys meminfo.

Reads the RAM totals block (Total / Free / Used / Lost RAM, ZRAM / swap) and the "Total PSS by process" list, bounded to the top entries. Everything else in the (large) dump is ignored.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required

Returns:

Type Description
SystemMemorySummary

The serial; total_ram_kb / free_ram_kb / used_ram_kb / lost_ram_kb; zram_physical_used_kb / zram_in_swap_kb / zram_total_swap_kb; status (the "(status normal)" word); and top_processes (name, pid, user, pss_kb), newest-heaviest first, capped. Fields the dump didn't carry are null.

Error handling

An unknown serial or unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. Output with no recognizable RAM totals raises MEMORY_INFO_UNAVAILABLE. A permission rejection raises PERMISSION_DENIED; any other non-zero exit raises BACKEND_ERROR.

Example

Called with serial="emulator-5554". A typical (trimmed) response:

{
  "status": "success",
  "message": "emulator-5554: 4007632 KB total RAM, 2516255 KB free, 15 top procs.",
  "data": {
    "serial": "emulator-5554",
    "total_ram_kb": 4007632,
    "free_ram_kb": 2516255,
    "used_ram_kb": 1406266,
    "lost_ram_kb": 95527,
    "zram_physical_used_kb": 15404,
    "zram_in_swap_kb": 19880,
    "zram_total_swap_kb": 3005720,
    "status": "status normal",
    "top_processes": [
      {"name": "system", "pid": 729, "user": null, "pss_kb": 266973}
    ]
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
@category("read")
async def get_system_memory_summary(ctx: Context, serial: str) -> SystemMemorySummary:
    """System-wide memory totals and top consumers: `adb shell dumpsys meminfo`.

    Reads the RAM totals block (Total / Free / Used / Lost RAM, ZRAM /
    swap) and the "Total PSS by process" list, bounded to the top entries.
    Everything else in the (large) dump is ignored.

    Args:
        serial: The target device's adb serial (see list_connected_devices).

    Returns:
        The serial; total_ram_kb / free_ram_kb / used_ram_kb / lost_ram_kb;
        zram_physical_used_kb / zram_in_swap_kb / zram_total_swap_kb; status
        (the "(status normal)" word); and top_processes (name, pid, user,
        pss_kb), newest-heaviest first, capped. Fields the dump didn't carry
        are null.

    Error handling:
        An unknown serial or unresponsive adb binary raises
        DEVICE_NOT_FOUND/ADB_UNAVAILABLE. Output with no recognizable RAM
        totals raises MEMORY_INFO_UNAVAILABLE. A permission rejection raises
        PERMISSION_DENIED; any other non-zero exit raises BACKEND_ERROR.

    Example:
        Called with serial="emulator-5554". A typical (trimmed) response:

        ```json
        {
          "status": "success",
          "message": "emulator-5554: 4007632 KB total RAM, 2516255 KB free, 15 top procs.",
          "data": {
            "serial": "emulator-5554",
            "total_ram_kb": 4007632,
            "free_ram_kb": 2516255,
            "used_ram_kb": 1406266,
            "lost_ram_kb": 95527,
            "zram_physical_used_kb": 15404,
            "zram_in_swap_kb": 19880,
            "zram_total_swap_kb": 3005720,
            "status": "status normal",
            "top_processes": [
              {"name": "system", "pid": 729, "user": null, "pss_kb": 266973}
            ]
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.get_system_memory_summary(serial)

set_heap_watch(ctx: Context, serial: str, package: str, threshold_bytes: int) -> HeapWatchResult async

Auto-collect a heap dump when a process gets large: adb shell am set-watch-heap.

Tells ActivityManager to watch package's PSS and, once it reaches threshold_bytes, collect a heap dump on the device for later retrieval. Use clear_heap_watch to stop watching. am doesn't validate the package, so an unknown one isn't an error. Support varies by Android version.

Parameters:

Name Type Description Default
serial str

The target device's adb serial (see list_connected_devices).

required
package str

The package/process to watch, e.g. "com.example.app".

required
threshold_bytes int

PSS threshold in bytes (must be positive), e.g. 268435456 for 256 MB.

required

Returns:

Type Description
HeapWatchResult

The serial, package, threshold_bytes, and watching (always true on success).

Error handling

A blank package or a non-positive threshold_bytes raises INVALID_ARGUMENT before anything runs. An unknown serial or unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A permission rejection raises PERMISSION_DENIED; a build that doesn't support the command raises BACKEND_ERROR.

Example

Called with serial="emulator-5554", package="com.example.app", threshold_bytes=268435456. A typical response:

{
  "status": "success",
  "message": "Watching com.example.app on emulator-5554; a heap dump triggers at 268435456 bytes PSS.",
  "data": {
    "serial": "emulator-5554",
    "package": "com.example.app",
    "threshold_bytes": 268435456,
    "watching": true
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/memory/tools.py
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
@category("write")
async def set_heap_watch(
    ctx: Context, serial: str, package: str, threshold_bytes: int
) -> HeapWatchResult:
    """Auto-collect a heap dump when a process gets large: `adb shell am
    set-watch-heap`.

    Tells ActivityManager to watch package's PSS and, once it reaches
    threshold_bytes, collect a heap dump on the device for later
    retrieval. Use clear_heap_watch to stop watching. `am` doesn't validate
    the package, so an unknown one isn't an error. Support varies by
    Android version.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        package: The package/process to watch, e.g. "com.example.app".
        threshold_bytes: PSS threshold in bytes (must be positive), e.g.
            268435456 for 256 MB.

    Returns:
        The serial, package, threshold_bytes, and watching (always true on
        success).

    Error handling:
        A blank package or a non-positive threshold_bytes raises
        INVALID_ARGUMENT before anything runs. An unknown serial or
        unresponsive adb binary raises DEVICE_NOT_FOUND/ADB_UNAVAILABLE. A
        permission rejection raises PERMISSION_DENIED; a build that doesn't
        support the command raises BACKEND_ERROR.

    Example:
        Called with serial="emulator-5554", package="com.example.app",
        threshold_bytes=268435456. A typical response:

        ```json
        {
          "status": "success",
          "message": "Watching com.example.app on emulator-5554; a heap dump triggers at 268435456 bytes PSS.",
          "data": {
            "serial": "emulator-5554",
            "package": "com.example.app",
            "threshold_bytes": 268435456,
            "watching": true
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    memory = cast(MemoryService, services["memory"])
    return await memory.set_heap_watch(serial, package, threshold_bytes)