Skip to content

binder

Binder IPC call statistics (adb shell dumpsys binder_calls_stats and ... --reset). get_binder_call_stats returns the sampling interval, the "Summary:" totals, a bounded list of the top per-UID callers, and the "Exceptions thrown" tally — never the raw per-call rows. Binder-call-stats collection is often off by default; when it is, collecting is false and the totals are zero (a normal state). reset_binder_call_stats zeroes the counters before a measured flow.

adb_automation_mcp.modules.binder.tools

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

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

get_binder_call_stats(ctx: Context, serial: str, limit: int = 20) -> BinderCallStats async

Get Binder IPC call statistics: adb shell dumpsys binder_calls_stats.

Returns the sampling interval, the "Summary:" totals (total CPU time, call count, average per-call CPU), a bounded list of the top per-UID callers, and the "Exceptions thrown" tally. The large raw per-call rows are never returned. Binder-call-stats collection is often off by default — when it is, collecting is false and the totals are zero (a normal state, not an error); reset_binder_call_stats and drive a workload first.

Parameters:

Name Type Description Default
serial str

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

required
limit int

Maximum number of top-caller rows to return, 1-200 (default 20).

20

Returns:

Type Description
BinderCallStats

The serial; collecting (whether stats are accumulating); start_time; sampling_interval_ms; total_cpu_time_micros; calls_count; avg_call_cpu_time_micros (null when the dump said "NaN"); top_callers (who / cpu_time_micros / percent_of_total / recorded_call_count / call_count); and exceptions (class_name / count).

Error handling

A limit outside 1-200 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. Empty / not-collecting stats are returned as data, not raised.

Example

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

{
  "status": "success",
  "message": "emulator-5554: 722 binder calls, 201512us CPU, 2 top callers.",
  "data": {
    "serial": "emulator-5554",
    "collecting": true,
    "start_time": "2026-09-07 07:48:14",
    "sampling_interval_ms": 1000,
    "total_cpu_time_micros": 201512,
    "calls_count": 722,
    "avg_call_cpu_time_micros": 279,
    "top_callers": [
      {"who": "com.android.systemui/10141", "cpu_time_micros": 123456, "percent_of_total": 61.2, "recorded_call_count": 40, "call_count": 512}
    ],
    "exceptions": [{"class_name": "java.lang.SecurityException", "count": 3}]
  },
  "error": null
}
Source code in src/adb_automation_mcp/modules/binder/tools.py
21
22
23
24
25
26
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
@category("read")
async def get_binder_call_stats(ctx: Context, serial: str, limit: int = 20) -> BinderCallStats:
    """Get Binder IPC call statistics: `adb shell dumpsys binder_calls_stats`.

    Returns the sampling interval, the "Summary:" totals (total CPU time,
    call count, average per-call CPU), a bounded list of the top per-UID
    callers, and the "Exceptions thrown" tally. The large raw per-call rows
    are never returned. Binder-call-stats collection is often off by default
    — when it is, collecting is false and the totals are zero (a normal
    state, not an error); reset_binder_call_stats and drive a workload
    first.

    Args:
        serial: The target device's adb serial (see list_connected_devices).
        limit: Maximum number of top-caller rows to return, 1-200
            (default 20).

    Returns:
        The serial; collecting (whether stats are accumulating);
        start_time; sampling_interval_ms; total_cpu_time_micros;
        calls_count; avg_call_cpu_time_micros (null when the dump said
        "NaN"); top_callers (who / cpu_time_micros / percent_of_total /
        recorded_call_count / call_count); and exceptions (class_name /
        count).

    Error handling:
        A limit outside 1-200 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.
        Empty / not-collecting stats are returned as data, not raised.

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

        ```json
        {
          "status": "success",
          "message": "emulator-5554: 722 binder calls, 201512us CPU, 2 top callers.",
          "data": {
            "serial": "emulator-5554",
            "collecting": true,
            "start_time": "2026-09-07 07:48:14",
            "sampling_interval_ms": 1000,
            "total_cpu_time_micros": 201512,
            "calls_count": 722,
            "avg_call_cpu_time_micros": 279,
            "top_callers": [
              {"who": "com.android.systemui/10141", "cpu_time_micros": 123456, "percent_of_total": 61.2, "recorded_call_count": 40, "call_count": 512}
            ],
            "exceptions": [{"class_name": "java.lang.SecurityException", "count": 3}]
          },
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    binder = cast(BinderService, services["binder"])
    return await binder.get_binder_call_stats(serial, limit=limit)

reset_binder_call_stats(ctx: Context, serial: str) -> ResetBinderCallStatsResult async

Reset Binder IPC call statistics: adb shell dumpsys binder_calls_stats --reset.

Zeroes the Binder-call-stats counters so a subsequent get_binder_call_stats measures only the flow you run in between. Categorized write as a measurement-state mutation (it does not change device behavior).

Parameters:

Name Type Description Default
serial str

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

required

Returns:

Type Description
ResetBinderCallStatsResult

The serial and reset (always true when this returns without error).

Error handling

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.

Example

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

{
  "status": "success",
  "message": "Reset binder call stats on emulator-5554.",
  "data": {"serial": "emulator-5554", "reset": true},
  "error": null
}
Source code in src/adb_automation_mcp/modules/binder/tools.py
 82
 83
 84
 85
 86
 87
 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
@category("write")
async def reset_binder_call_stats(ctx: Context, serial: str) -> ResetBinderCallStatsResult:
    """Reset Binder IPC call statistics: `adb shell dumpsys
    binder_calls_stats --reset`.

    Zeroes the Binder-call-stats counters so a subsequent
    get_binder_call_stats measures only the flow you run in between.
    Categorized `write` as a measurement-state mutation (it does not change
    device behavior).

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

    Returns:
        The serial and reset (always true when this returns without error).

    Error handling:
        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.

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

        ```json
        {
          "status": "success",
          "message": "Reset binder call stats on emulator-5554.",
          "data": {"serial": "emulator-5554", "reset": true},
          "error": null
        }
        ```
    """
    services = cast("dict[str, object]", ctx.lifespan_context["services"])
    binder = cast(BinderService, services["binder"])
    return await binder.reset_binder_call_stats(serial)