ScreenSync MCP guide

Testing Android Battery Drain and Doze with Claude Code and MCP

Master Android battery drain and Doze mode testing on physical devices using Claude Code and ScreenSync MCP. Automate ADB power commands and wake lock audits without root.

Testing Android Battery Drain and Doze with Claude Code and MCP

Testing Android battery drain, background execution limits, and Doze mode transitions on physical devices represents one of the most demanding challenges in modern mobile software engineering. While functional unit tests and continuous integration UI suites verify that user flows render without crashing, they routinely fail to capture the catastrophic energy regressions that destroy user retention in production. According to Android vitals benchmarks established by Google Play, excessive background wake locks—defined as holding a partial wake lock for more than one hour in a single battery session—and excessive background Wi-Fi or cellular network scanning place an application in the bottom quartile of store health, directly throttling organic discovery and triggering uninstalls. Yet, historically, mobile engineering teams have treated power profiling as a tedious manual laboratory exercise requiring specialized hardware multimeters or artificial bench rigs. Traditional in-process test runners like Espresso keep the device screen and CPU permanently awake across the test run, while virtual Android Studio emulators run on synthetic, idealized power subsystems that cannot emulate cellular radio power state machines, Bluetooth Low Energy discovery curves, or genuine hardware thermal throttling. By pairing autonomous terminal-based AI coding agents like Claude Code with the Model Context Protocol through ScreenSync MCP, developers can finally bridge the chasm between automated continuous integration and authentic hardware power management, executing deterministic Doze mode transitions, App Standby bucket sweeps, and wake lock forensics on real physical Android hardware without root privileges.

Key Takeaways

  • Deterministic Battery State Manipulation: Claude Code programmatically simulates battery disconnection (dumpsys battery unplug), adjusts simulated charge percentages, and forces Android power management daemons into discharging states over ADB while maintaining active communication.
  • Doze Mode State Machine Traversal: Automate transitions across Light Doze and Deep Doze states (dumpsys deviceidle force-idle and step) to verify background job deferral, maintenance window execution, and network cutoffs on real hardware.
  • Physical Hardware Grounding vs Synthetic Emulators: Physical Android devices capture true radio tail states (RRC connection teardown), hardware sensor polling draw, and OEM aggressive task management that virtual emulators cannot replicate.
  • Zero-Root MediaProjection Telemetry: ScreenSync MCP captures high-fidelity visual frames at approximately 94 milliseconds median latency over the local network via Android's native MediaProjection API, consuming zero ADB bandwidth and requiring no root access.
  • Automated BatteryStats & WakeLock Forensics: Claude Code collects, parses, and asserts against dumpsys batterystats reports, pinpointing stuck partial wake locks and runaway background threads before code merges to production.
  • Unified 226-Tool MCP Ecosystem: ScreenSync MCP combines 29 mobile and desktop tools (12 control_*, 3 os_*, and 14 capture/telemetry tools) with 197 browser tools to orchestrate full-stack testing from mobile app behavior to cloud developer dashboards.

Why Traditional Mobile Test Frameworks Fail at Battery and Power Profiling

Traditional mobile test frameworks fail at battery and power profiling because instrumentation runners require active USB power connections and keep device displays illuminated throughout execution, preventing Android power daemons from engaging low-power states. Furthermore, in-process runners execute within the application sandbox, leaving them structurally unable to manipulate OS-level power services or monitor kernel wake locks.

To understand why automated mobile battery profiling has historically been so difficult to integrate into continuous integration pipelines, software architects must examine how conventional mobile testing frameworks interact with the Android operating system. When a QA engineer runs an automated test suite using Espresso, UIAutomator, or Appium, the physical device or emulator is connected to the continuous integration runner via a USB cable. By default, the USB port supplies 5 volts of electrical current, continuously charging the mobile device's lithium-ion battery.

Under standard Android framework behavior, when the device's BatteryManager reports BATTERY_STATUS_CHARGING or BATTERY_PLUGGED_USB, the operating system's internal power management daemon (deviceidle service) completely disables Doze mode. The operating system assumes that because unlimited wall or host power is available, background execution constraints, network batching, and job deferrals should not be enforced. As a result, tests running under standard USB instrumentation cannot evaluate whether background workers correctly survive power cuts or properly batch their network payloads.

Furthermore, frameworks like Espresso operate under an "in-process" execution model. The test runner compiles into a secondary APK that executes inside the target application's runtime process (com.example.myapp) via the Android InstrumentationRegistry. Espresso communicates with the application's main thread looper (Looper.getMainLooper()), actively idling until UI animations, Coroutine jobs, and asynchronous message queues finish processing. This execution pattern introduces two fatal flaws for power testing:

  1. Artificial WakeLock Keep-Alive: The instrumentation harness itself holds the application process in the foreground, acquiring implicit wake locks that prevent the Android Linux kernel from entering low-power suspend states (suspend-to-RAM).
  2. Sandbox Isolation: Because Espresso is confined to the application sandbox, it has zero visibility into operating system subsystems. It cannot inspect system-wide wake locks, cannot query the radio interface layer (RIL) to observe cellular modem power states, and cannot invoke administrative shell tools like dumpsys without throwing security exceptions.

Cloud device testing farms (such as BrowserStack or Sauce Labs) exacerbate these limitations. Most cloud providers host virtualized Android emulators running on x86 server racks, or attach physical devices to continuous USB power banks with customized vendor ROMs that disable sleep modes to maintain continuous video streaming over WebRTC. If an engineer attempts to simulate an unplugged state on a remote cloud farm, the remote video stream frequently freezes, or the cloud harness forcibly resets the connection because it detects the device going into standby sleep.

ScreenSync MCP resolves this dilemma by running outside the Android device process boundary. Operating as a Model Context Protocol server over a clean local stdio transport, Claude Code interacts with the Android device from your host machine. ScreenSync MCP leaves the application under test completely untouched while using ADB commands over local Wi-Fi or USB to programmatically unplug the battery, advance Doze state machines, and extract authoritative system performance logs.

Power Profiling Dimension In-Process Espresso / Instrumentation Standalone Appium / Cloud Device Farms Android Studio Emulators (x86) ScreenSync MCP + Claude Code (Real Device)
Doze Mode Simulation Impossible; USB connection and in-process loopers force active state Flaky; cloud streaming agents break when device enters deep idle sleep Highly artificial; synthetic power curves fail to simulate hardware draw Deterministic; drives dumpsys deviceidle states via ADB shell
Battery Disconnection Unsupported; requires physical unplugging which drops ADB connection Unsupported; cloud farm devices are permanently hardwired to USB power Simulated via AVD manager, but lacks authentic hardware power rail feedback Native; executes dumpsys battery unplug over Wi-Fi or USB without drop
WakeLock Forensics Zero visibility into system-level kernel wake locks or battery stats Limited; requires pulling raw logs post-run without semantic AI triage Inaccurate; emulator CPU clock emulation skews wake lock duration metrics Real-time; Claude Code parses dumpsys batterystats and isolates leaks
Radio Power States (RRC) Blind; cannot observe cellular modem state transitions (IDLE to DCH) Blind; cloud devices operate exclusively on virtual Ethernet or Wi-Fi bridges Non-existent; emulated network bridges do not simulate radio power tails Grounded; captures real physical cellular and Wi-Fi modem current behavior
Display Stream Overhead Not applicable; requires separate screenshot capture tools High CPU overhead (15-30%) due to cloud WebRTC screen encoding Moderate CPU overhead from host GPU virtualization pipeline Minimal; hardware-accelerated MediaProjection over LAN (~94 ms latency)
Autonomous Healing Static assertion scripts fail immediately upon unexpected modal dialogs Requires complex retry scripting and hardcoded sleep statements Requires manual developer intervention during execution halts Native; Claude Code reads UI hierarchy and adjusts test path dynamically

Android Power Architecture: Doze Mode, App Standby Buckets, and WakeLock Mechanics

Android power architecture controls energy consumption through two distinct operating system mechanisms: Doze mode, which places the entire operating system into coordinated deep sleep when stationary and unplugged, and App Standby Buckets, which restrict background execution quotas based on user engagement frequency. Both systems strictly govern wake locks and network access.

To design comprehensive automated tests with Claude Code, software engineers must understand the underlying state machines and operating system contracts governing Android power management. Since Android 6.0 Marshmallow, with further expansions in Android 7.0 Nougat (Doze on the Go) through Android 14 and 15, the operating system aggressively restricts background CPU execution, network access, and system alarms.

1. The Doze Mode State Machine: Light vs. Deep Doze

Doze reduces battery consumption by deferring background CPU and network activity when the user leaves the device unplugged, stationary, and with the screen turned off. Android implements Doze as a two-phase state machine:

Light Doze (Doze on the Go)

Introduced in Android 7.0, Light Doze activates when the screen is turned off and the device is running on battery, even if the user is walking or carrying the device in their pocket:

  • The device transitions through: ACTIVE -> INACTIVE -> IDLE_PENDING -> IDLE -> WAITING_FOR_NETWORK -> MAINTENANCE.
  • Restrictions Applied: Network access for background applications is cut off. Any background sync jobs or WorkManager tasks are deferred until a periodic maintenance window.
  • Maintenance Windows: The operating system opens brief maintenance windows (initially every 10–15 minutes) where deferred network jobs run, after which the device returns to Light Doze.

Deep Doze

Activates when the device is completely stationary (detected via the Significant Motion Sensor, or SMS) on battery with the screen turned off:

  • The device transitions through: ACTIVE -> INACTIVE -> SENSING -> LOCATING -> IDLE_PENDING -> IDLE -> IDLE_MAINTENANCE.
  • Severe Restrictions Applied:
    • All network access is blocked for standard apps.
    • The system ignores all wake locks (PowerManager.WakeLock). Even if an application holds a partial wake lock, the CPU ignores it and suspends.
    • Standard AlarmManager alarms (including setExact()) are deferred to the next maintenance window. Only setExactAndAllowWhileIdle() or alarms scheduled with setAlarmClock() fire.
    • Wi-Fi and Bluetooth BLE background scanning are terminated.
    • System sync adapters and JobScheduler / WorkManager workers are paused.
    • Maintenance windows progressively widen using exponential backoff: from 15 minutes, to 30 minutes, 1 hour, 2 hours, up to a maximum interval of 6 hours.

2. App Standby Buckets

Introduced in Android 9.0 Pie (API level 28), App Standby Buckets evaluate how recently and frequently an application is used, grouping apps into five operational tiers:

  1. Active (Bucket 10): The application is currently in the foreground, has a running foreground service (with an active persistent notification), or is being actively interacted with by the user. No restrictions applied.
  2. Working Set (Bucket 20): The application is used often, typically daily. Jobs and alarms are permitted with minor deferral delays.
  3. Frequent (Bucket 30): The application is used regularly, but not every day. Jobs are deferred up to several hours; standard alarms are throttled; high-priority push messages (via Firebase Cloud Messaging) are capped at 10 per day.
  4. Rare (Bucket 40): The application is rarely used. Network access is severely restricted; jobs are deferred for up to 24 hours; high-priority push messages are capped at 5 per day.
  5. Restricted (Bucket 45): Added in modern Android releases for apps that trigger excessive background drain. The application cannot execute jobs, cannot trigger network requests, and receives zero high-priority push messages until opened.
Android Power State / Bucket System Trigger Condition Network Access Restriction WakeLock Behavior JobScheduler & WorkManager Execution ADB Emulation Command
Active State Screen on, app in foreground or active foreground service Full unrestricted network access Wake locks honored without timeout restrictions Jobs execute immediately subject to constraints adb shell dumpsys battery reset
Light Doze Screen off, running on battery, device moving or stationary Blocked for background apps; permitted during maintenance Partial wake locks honored; background processing permitted Deferred until periodic Light Doze maintenance window adb shell dumpsys deviceidle step light
Deep Doze Screen off, running on battery, stationary for extended period Completely blocked; opened only during exponential maintenance System ignores all partial wake locks; CPU enters deep sleep Completely deferred until Deep Doze maintenance window adb shell dumpsys deviceidle force-idle deep
App Standby: Active (10) User currently interacting with app or recent foreground launch Unrestricted network bandwidth and socket communication Normal wake lock execution Standard execution scheduling adb shell am set-standby-bucket <pkg> active
App Standby: Working Set (20) App launched within last few hours or used daily Unrestricted network during active execution Normal wake lock execution Minor batching; jobs run within short window adb shell am set-standby-bucket <pkg> working_set
App Standby: Frequent (30) App used every few days; occasional user interaction Network allowed only during window or user engagement Wake locks throttled if held continuously Jobs deferred up to several hours; FCM capped at 10/day adb shell am set-standby-bucket <pkg> frequent
App Standby: Rare (40) App used infrequently; multiple days since last launch Severely restricted network; batch windows only Wake locks heavily throttled Jobs deferred up to 24 hours; FCM capped at 5/day adb shell am set-standby-bucket <pkg> rare
App Standby: Restricted (45) High battery consumption detected by OS or user battery saver Network completely blocked until user launches app Wake locks denied completely in background Jobs blocked completely until next user foreground interaction adb shell am set-standby-bucket <pkg> restricted

3. Defensive Kotlin Background Worker Implementation

To survive these power transitions without leaking battery or losing critical transactional data, production Android applications must utilize modern WorkManager APIs with explicit battery and network constraints, defensive wake lock release timeouts, and broadcast listeners that respond gracefully when the charger is unplugged:

package com.example.screensync.power

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.PowerManager
import android.util.Log
import androidx.work.*
import java.util.concurrent.TimeUnit

class BatteryResilientSyncWorker(
    appContext: Context,
    workerParams: WorkerParameters
) : CoroutineWorker(appContext, workerParams) {

    companion object {
        private const val TAG = "BatteryResilientWorker"
        private const val WAKELOCK_TAG = "com.example.screensync:SyncWakeLock"
        private const val WAKELOCK_TIMEOUT_MS = 45_000L // Safety timeout to prevent leaks

        fun scheduleSync(context: Context) {
            // Define strict constraints to respect Doze mode and low battery states
            val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.CONNECTED)
                .setRequiresBatteryNotLow(true) // Pauses execution when battery drops below 15%
                .setRequiresCharging(false)     // Can run on battery, but respects idle restrictions
                .setRequiresDeviceIdle(false)   // Must not block deep Doze entry
                .build()

            val syncRequest = PeriodicWorkRequestBuilder<BatteryResilientSyncWorker>(
                repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.HOURS,
                flexTimeInterval = 15, flexTimeIntervalTimeUnit = TimeUnit.MINUTES
            )
                .setConstraints(constraints)
                .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
                .addTag("telemetry_sync")
                .build()

            WorkManager.getInstance(context).enqueueUniquePeriodicWork(
                "TelemetrySyncWork",
                ExistingPeriodicWorkPolicy.KEEP,
                syncRequest
            )
            Log.i(TAG, "Battery-resilient sync task enqueued successfully.")
        }
    }

    override suspend fun doWork(): Result {
        val powerManager = applicationContext.getSystemService(Context.POWER_SERVICE) as PowerManager
        val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG)

        return try {
            // Acquire wake lock with a hard timeout to guarantee it cannot leak
            wakeLock.acquire(WAKELOCK_TIMEOUT_MS)
            Log.d(TAG, "Acquired partial wake lock with safety timeout: ${wakeLock.isHeld}")

            // Execute batched network synchronization
            val success = performPayloadUpload()
            if (success) {
                Result.success()
            } else {
                Result.retry()
            }
        } catch (e: Exception) {
            Log.e(TAG, "Background sync failed during power transition", e)
            Result.retry()
        } finally {
            // Guarantee wake lock release even if worker is stopped or cancelled by Doze
            if (wakeLock.isHeld) {
                wakeLock.release()
                Log.d(TAG, "Safely released partial wake lock.")
            }
        }
    }

    private suspend fun performPayloadUpload(): Boolean {
        // Implementation of batched telemetry upload
        return true
    }
}

When building background operations, engineering teams must verify that tasks do not violate power budgets. For complex scheduled tasks that survive Doze mode maintenance windows, see our complete guide on testing Android WorkManager with Claude Code and MCP. To verify that network retries employ exponential backoff without radio spamming, explore our companion walkthrough on testing Android network resilience with Claude Code and MCP.

Bridging Claude Code to Android Power Subsystems via ScreenSync MCP

ScreenSync MCP bridges Claude Code to Android power subsystems through an architectural design that decouples visual frame verification from command execution. While native MediaProjection streams display frames over Wi-Fi without ADB overhead, Claude Code issues low-level power commands over ADB to unplug batteries, advance Doze states, and triage wake lock telemetry.

The core reason ScreenSync MCP enables high-precision battery and power profiling where other tools fail lies in its tripartite architecture:

Architectural Plane Communication Channel Transport & Performance Role During Battery & Power Testing
Cognitive Agent Plane Local stdio Process Pipe Sub-millisecond JSON-RPC Claude Code reads developer prompts, formulates test matrices, executes shell commands, and analyzes logcat logs
Visual Verification Plane Local Wi-Fi / LAN Sockets Native MediaProjection (~94 ms median) Streams real-time display frames (Android 7.0+, zero root, zero ADB overhead) to assert UI low-battery warnings
Hardware & Power Control Plane Physical USB or Wireless Debugging ADB Daemon Socket Manipulates Android battery and deviceidle services, extracts accessibility nodes, and triggers gestures

1. Why MediaProjection Over Local LAN Protects Power Test Accuracy

In conventional automated testing setups, capturing the device screen requires invoking adb exec-out screencap -p or streaming raw frames over the USB ADB transport. This introduces significant measurement distortion. Executing continuous ADB screencap commands consumes between 15% and 25% of the mobile device's CPU capacity. The Android CPU governors respond to this load by boosting clock frequencies (scaling_cur_freq), generating artificial heat and inflating battery consumption metrics by 300% to 500%.

ScreenSync MCP eliminates this problem. The ScreenSync MCP Android application (package com.screensync.mcp, available free on Google Play for devices running Android 7.0 or later) captures screen frames using Android's native MediaProjection API following user consent. The application utilizes the device's hardware-accelerated video pipeline and streams video frames directly across your local Wi-Fi network to the desktop hub on port 3000 at a median latency of approximately 94 milliseconds. Because display streaming bypasses the ADB pipe entirely, the ADB connection remains 100% idle until Claude Code issues an explicit inspection or input command.

2. High-Fidelity UI Node Inspection via get_ui_hierarchy

When an application encounters a simulated low-battery state or Doze mode maintenance window, Claude Code does not have to guess what is happening by scanning pixels. By invoking get_ui_hierarchy, Claude Code retrieves the complete structural XML accessibility tree of the foreground window:

<node index="0" package="com.example.screensync.power" class="android.widget.FrameLayout">
  <node index="0" class="android.widget.LinearLayout" resource-id="com.example.screensync:id/banner_power_saver">
    <node index="0" class="android.widget.TextView" resource-id="com.example.screensync:id/txt_warning_title" 
          text="Low Battery Mode Active (15%)" />
    <node index="1" class="android.widget.TextView" resource-id="com.example.screensync:id/txt_warning_desc" 
          text="Background syncing has been paused to preserve power." />
    <node index="2" class="android.widget.Button" resource-id="com.example.screensync:id/btn_force_sync" 
          text="Sync Now (Override)" clickable="true" />
  </node>
</node>

Claude Code parses node bounds, text values, and resource IDs directly. To learn more about how structural node parsing prevents model hallucination during visual evaluation, review our deep dive on how AI agents use Android UI trees not screenshots.

3. The 226-Tool Ecosystem Advantage

ScreenSync MCP provides 226 MCP tools:

  • 29 Phone & Desktop Tools: Featuring 12 mobile device control tools (control_tap, control_swipe, control_type, control_key, control_open_url, control_launch_app), 3 desktop OS tools (os_mouse_click, os_type, os_hotkey), and 14 capture and telemetry tools (get_latest_screenshot, get_ui_hierarchy, get_logcat, record_screen, get_device_status).
  • 197 Browser Tools: The web_* suite operates through an authenticated Chrome or Edge browser extension (Manifest V3). In enterprise mobile testing scenarios where mobile app energy logs are exported to cloud observability dashboards (such as Datadog, Grafana, or Firebase Console), Claude Code can triage mobile device behavior and verify cloud metrics in the same test pass. For a comprehensive inventory of all available tools, explore our complete Android MCP tool reference deep dive.

Step-by-Step Setup: Workstation Hub, Physical Device, and Claude Code Harness

Setting up an automated power testing harness requires launching the ScreenSync MCP Node.js hub on port 3000, registering the stdio MCP server in Claude Code, and connecting an authentic Android 7.0+ device over Wi-Fi debugging. This configuration allows automated battery unplugging and Doze stepping without physical cable intervention.

Engineering teams can establish this testing environment across Windows, macOS, or Linux through five sequential steps:

Step 1: Verify Hardware and Environment Prerequisites

Before initializing the testing harness, ensure your workstation and test device satisfy the following baseline requirements:

  1. Host Workstation: Windows 10/11, macOS, or Linux running Node.js 18 or higher. Ensure that Android SDK Platform-Tools (adb) is installed and available in your system PATH.
  2. Authentic Android Device: A physical smartphone or tablet running Android 7.0 (API level 24) or later. The device must be connected to the same local Wi-Fi network as your host workstation.
  3. Application Build: A debug or staging APK of your application installed on the device.

Step 2: Download and Launch the Desktop Hub

Download the ScreenSync MCP hub distribution from the official website and extract the zip archive to a local folder on your workstation. Run the startup script matching your operating system:

# On Windows (PowerShell or Command Prompt)
cd C:\tools\screensync-hub
.\start-hub.bat

# On macOS or Linux (Terminal)
cd ~/tools/screensync-hub
chmod +x start-hub.sh
./start-hub.sh

The desktop hub initializes an HTTP server on port 3000 to receive local MediaProjection video streams and prepares the stdio Model Context Protocol interface. The terminal displays your secure bearer token (SCREEN_SYNC_TOKEN). For detailed configuration instructions, visit the official ScreenSync MCP setup guide.

Step 3: Register ScreenSync MCP with Claude Code

To connect Claude Code to the desktop hub, register the MCP server in your terminal using the CLI command below, replacing the path with the exact folder where you unpacked the hub zip:

claude mcp add screensync node "/path/to/screensync-hub/screensync-hub.js"

For developers operating inside Claude Desktop, edit your claude_desktop_config.json configuration file (accessible via Settings > Developer > Edit Config):

{
  "mcpServers": {
    "screensync": {
      "command": "node",
      "args": ["/path/to/screensync-hub/screensync-hub.js"],
      "env": {
        "SCREEN_SYNC_TOKEN": "your_authenticated_token_here"
      }
    }
  }
}

(Note: ScreenSync MCP integrates with local stdio MCP clients including Claude Code, Claude Desktop, Cursor, and VS Code agent mode. ChatGPT's web app requires remote HTTPS endpoints and does not support local stdio servers).

Step 4: Install the Android App and Authorize MediaProjection

  1. Download and install the free ScreenSync MCP Android application from Google Play (package com.screensync.mcp).
  2. Launch the application. The app automatically scans your local subnet via mDNS to discover the running desktop hub. If your local network restricts mDNS broadcasts, scan the pairing QR code displayed in the hub console.
  3. Tap Start Projection and confirm Android's native MediaProjection permission dialog. Display capture begins streaming immediately over your local Wi-Fi to the hub on port 3000.
  4. Note that all video frames stream locally from your phone to the hub on your own network and are never sent to EpsolDev servers. However, screenshots explicitly requested by an AI agent during testing are transmitted to that agent's model provider for visual inference.

Step 5: Configure Wireless Debugging for Cable-Free Power Testing

To test battery drain and Doze mode accurately, the physical device must not receive power from a USB cable. On Android 11+ devices:

  1. Open Settings > Developer Options > enable Wireless Debugging.
  2. Tap Pair device with pairing code. Note the IP address, pairing port, and 6-digit pairing code.
  3. In your host terminal, execute:
    adb pair 192.168.1.150:42351 123456
  4. Once paired, connect ADB to the wireless debugging port:
    adb connect 192.168.1.150:39845
  5. Confirm active connectivity by running adb devices. You can now unplug the physical USB cable completely. The device is now running purely on its internal battery while remaining 100% controllable by Claude Code over your local network.

Practical Autonomous QA Workflows: Simulating Battery Drain and Doze Transitions

Practical autonomous QA workflows execute deterministic power scenarios by resetting batterystats, simulating charger disconnection via ADB, stepping through Doze states, and evaluating app resilience. Claude Code verifies whether background sync halts during idle sleep and resumes correctly during scheduled maintenance windows.

Workflow 1: Simulating Battery Disconnection and Critical Power Warnings

When an Android smartphone drops below 15% battery, applications should throttle non-essential network synchronization, disable high-framerate animations, and notify users without blocking interactive tasks.

Developer Prompt:
"Claude, launch com.example.screensync.power on our wireless Android test device. First, reset batterystats and simulate unplugging the battery charger. Next, set the battery level to 12% and trigger battery saver mode. Assert that our app displays the 'Low Battery Mode Active' banner, and verify that our background telemetry sync is paused."

Step 1: Reset and Unplug Battery

Claude Code issues the simulated unplug command over ADB:

# Force operating system into battery discharge state
adb shell dumpsys battery unplug

# Set battery percentage to 12%
adb shell dumpsys battery set level 12

# Set battery status to Discharging (3)
adb shell dumpsys battery set status 3

Step 2: Assert UI State via Accessibility Hierarchy

Claude Code invokes control_launch_app with package com.example.screensync.power, followed by get_ui_hierarchy. It parses the returned XML tree to verify the warning banner:

<node text="Low Battery Mode Active (12%)" resource-id="com.example.screensync:id/txt_warning_title" visible="true" />

Step 3: Visual Confirmation via MediaProjection

Claude Code calls get_latest_screenshot to confirm that the banner renders with the correct amber warning color and does not overlap interactive form buttons.

Workflow 2: Stepping into Light Doze and Verifying Job Deferral

This workflow verifies that when the device enters Light Doze, non-essential background sync jobs defer their execution until a maintenance window occurs.

Developer Prompt:
"Claude, simulate the phone screen turning off and the device entering Light Doze. Verify that our app's periodic sync worker does not execute while in Light Doze, but runs successfully once we trigger a maintenance window."

Step 1: Turn Off Screen and Enter Light Doze

Claude Code issues key event 26 (Power) to lock the screen, then steps the device idle daemon into Light Doze:

# Turn off screen
adb shell input keyevent 26

# Force device idle state machine into light idle
adb shell dumpsys deviceidle force-idle light

Step 2: Inspect Active Doze State

Claude Code queries the device idle daemon to verify that the state has shifted to IDLE:

adb shell dumpsys deviceidle get light
# Output returns: IDLE

Step 3: Monitor Logcat for Deferred Jobs

Claude Code invokes get_logcat with filter JobScheduler|BatteryResilientWorker. It verifies that the Android JobScheduler holds the task in queue:

JobScheduler: Job com.example.screensync.power/.BatteryResilientSyncWorker deferred: Device in Light Doze

Step 4: Step to Maintenance Window

Claude Code steps the idle daemon to trigger the scheduled maintenance window:

adb shell dumpsys deviceidle step light
# Device enters IDLE_MAINTENANCE

Claude Code calls get_logcat again and confirms that performPayloadUpload() executes successfully during the maintenance window before the system returns to IDLE.

Workflow 3: Forcing Deep Doze and Validating WakeLock Invalidation

This test validates that deep Doze mode correctly halts partial wake locks and suspends standard alarms.

Developer Prompt:
"Claude, force the device into Deep Doze mode. Verify that our app's partial wake lock is ignored by the OS kernel, and confirm that our high-priority push notification handler correctly wakes the device."

Step 1: Unplug and Force Deep Doze

Claude Code forces the device through the Deep Doze state machine directly into deep idle:

adb shell dumpsys battery unplug
adb shell dumpsys deviceidle force-idle deep

To confirm deep idle status:

adb shell dumpsys deviceidle get deep
# Output returns: IDLE

Step 2: Audit Kernel WakeLocks via Batterystats

Claude Code checks active wake lock holders:

adb shell dumpsys power | grep -A 5 "Wake Locks: size="

The output confirms that the system has suspended all partial wake locks held by third-party applications, preventing CPU drain.

Step 3: Trigger High-Priority FCM Push Notification

To verify that urgent alerts still penetrate Deep Doze, Claude Code dispatches a high-priority push notification payload via adb broadcast or server trigger. For an in-depth breakdown of push token verification and notification channels, see our guide on testing Android push notifications with Claude Code and MCP. Claude Code observes that the push wake lock temporarily promotes the app to execute urgent processing.

Workflow 4: App Standby Bucket Sweeps and WakeLock Leak Forensics

In this advanced workflow, Claude Code moves the application into the restricted App Standby bucket, executes simulated background tasks, and triages battery statistics to identify energy leaks.

Developer Prompt:
"Claude, place com.example.screensync.power into the 'restricted' standby bucket. Reset batterystats, wait 60 seconds, and generate an energy report. Flag any unreleased wake locks or excessive CPU wakeups."

Step 1: Apply Standby Bucket

Claude Code sets the application's standby bucket directly:

adb shell am set-standby-bucket com.example.screensync.power restricted

To verify the assigned bucket:

adb shell am get-standby-bucket com.example.screensync.power
# Output returns: 45 (RESTRICTED)

Step 2: Reset and Capture BatteryStats

Claude Code clears historical battery statistics and initiates the observation window:

# Clear battery statistics
adb shell dumpsys batterystats --reset

# Wait 60 seconds while monitoring device telemetry
# Dump package-specific battery statistics
adb shell dumpsys batterystats --charged com.example.screensync.power

Step 3: Semantic Parsing of Battery Output

Claude Code inspects the generated report for critical energy metrics:

  • Wake lock total time: Must not exceed scheduled execution duration. If wake lock time equals 60,000 ms over a 60-second test window, Claude Code flags a stuck wake lock leak.
  • Job execution count: In the restricted bucket, job count must be 0.
  • Foreground service time: Verifies whether services properly shut down upon task completion.
  • Cellular & Wi-Fi radio active time: Asserts that modem radio was not kept awake in high-power tail states.

For continuous performance profiling including frame drops and GPU Choreographer bottlenecks, explore our guide on automated Android performance profiling with AI. If an app is killed by the system during extreme memory or battery pressure, consult our companion walkthrough on testing Android process death with Claude Code and MCP.

Common Pitfalls, OEM Quirks, and Troubleshooting Power Tests

Common pitfalls in Android power testing include forgetting to reset simulated battery states, neglecting OEM-specific aggressive battery management daemons, and failing to account for wireless debugging battery consumption. Resolving these issues requires automated tear-down scripts, disabling vendor optimizations, and baseline differential measurements.

When automating power testing with Claude Code on physical Android hardware, engineering teams frequently encounter four technical hurdles:

1. Forgetting to Reset Simulated Battery and Doze States

A frequent issue occurs when an automated test script terminates prematurely or encounters an unhandled exception after calling dumpsys battery unplug or dumpsys deviceidle force-idle. Because simulated battery states are stored in memory within the Android BatteryService, the physical smartphone remains in a fake discharging mode indefinitely—even while plugged back into a physical wall charger.

Remediation: Always configure Claude Code to include a mandatory tear-down phase in your test automation prompts, executing:

# Restore genuine hardware battery monitoring
adb shell dumpsys battery reset

# Re-enable standard device idle transitions
adb shell dumpsys deviceidle unforce

2. OEM Task Killers on Samsung One UI, Xiaomi HyperOS, and OnePlus OxygenOS

While standard Android Open Source Project (AOSP) builds adhere strictly to Google's Doze and App Standby bucket specifications, hardware manufacturers implement proprietary battery management daemons that override standard Android contracts. For example, Samsung's One UI includes "Deep sleeping apps" policy, Xiaomi's HyperOS enforces "MIUI Battery Saver", and Huawei incorporates "PowerGenie". These vendor daemons aggressively kill background processes and cancel scheduled WorkManager workers regardless of whether the app adheres to standard Android constraints.

Remediation: When testing on physical OEM hardware, verify whether OEM power optimizations are active for your package:

# Whitelist application from standard battery optimizations
adb shell dumpsys deviceidle whitelist +com.example.screensync.power

# On Samsung devices, verify app is not in deep sleep
adb shell dumpsys package com.example.screensync.power | grep -i "user-state"

3. Wireless Debugging Radio Overhead in Power Baselines

While wireless debugging allows the physical device to run without a USB cable, keeping the Wi-Fi radio continuously listening on the ADB TCP socket prevents the physical Wi-Fi chipset from entering deep 802.11 power-save polling mode (PS-Poll). This introduces a small, constant baseline power draw (typically 15–30 mA).

Remediation: When conducting absolute micro-ampere battery drain audits, use differential baseline testing. Instruct Claude Code to record a 10-minute baseline battery drain with only the OS and wireless debugging active. Then, execute your 10-minute app workflow under the identical wireless configuration and subtract the baseline. This yields an accurate measurement of your application's incremental energy footprint.

4. WakeLock Leaks Across Activity Recreations

A subtle architectural bug occurs when an Activity or Service acquires a partial wake lock in onCreate() or onStartCommand() but fails to release it if the user rotates the device or if the OS destroys the activity during configuration changes.

Remediation: Always enforce timeout safeguards when acquiring wake locks (wakeLock.acquire(45000L)). Furthermore, configure Claude Code to execute device orientation toggles (control_type or adb shell settings put system user_rotation 1) during wake lock workflows, verifying via dumpsys power that wake lock reference counts return to zero upon completion. To verify whether your workstation and physical device are properly configured for full-device automation, explore can Claude Code test Android apps on real mobile devices.

Security, Safety, and Network Data Flow Architecture

ScreenSync MCP isolates all screen capture data to the local area network, streaming frames directly from the mobile device to the local desktop hub over port 3000 without external cloud relays. Explicit screenshots requested by Claude Code are routed solely to the user-selected model provider for visual inference.

Executing automated testing on physical devices with AI agents demands rigorous security and privacy safeguards:

1. Local Network Frame Isolation

Unlike cloud device farms where mobile display feeds are routed through third-party servers and remote WebRTC brokers, ScreenSync MCP establishes a direct peer-to-peer connection across your local Wi-Fi or USB reverse port forwarding socket (adb reverse tcp:3000 tcp:3000). Screen frames captured via MediaProjection stream directly to your local workstation hub. Video frames are never transmitted to EpsolDev servers or external cloud relays.

2. Model Provider Transmission Transparency

Developers must remain aware of how visual data is processed when using AI coding agents:

  • Real-time video mirror frames remain strictly on your local network between the mobile device and the local hub.
  • When an AI agent (such as Claude Code) invokes get_latest_screenshot to evaluate UI layout rendering or confirm low-battery warning dialogs, that single visual frame is transmitted to that specific agent's model provider (e.g., Anthropic) for vision processing.
  • To protect proprietary assets and sensitive customer data, ensure test environments use staging accounts with synthetic data rather than production user credentials.

3. Non-Root Operational Boundary

ScreenSync MCP requires zero device rooting. All device control tools operate through standard Android Debug Bridge protocols over authenticated developer connections, while screen capture relies entirely on Android's sanctioned MediaProjection framework with explicit runtime user consent.

4. Hardware Safety Checklist for Prolonged Battery Tests

When executing autonomous Doze mode or extended battery discharge cycles:

  • Thermal Monitoring: Monitor battery temperature via adb shell dumpsys battery | grep temperature. Normal operating temperatures range between 25°C and 40°C (reported in tenths of a degree Celsius, e.g., 285 represents 28.5°C). Halt testing if temperature exceeds 45°C.
  • Deep Discharge Prevention: Never allow lithium-ion test devices to discharge below 5% battery during continuous automated sweeps, as deep discharge degrades battery health over time.
  • Overnight Safety: When executing long-running Doze backoff tests, ensure devices rest on fire-safe, non-insulated surfaces with adequate ambient ventilation.

Conclusion & Next Steps

Testing Android battery drain, background execution limits, and Doze mode transitions on physical hardware is essential for delivering robust, energy-efficient applications that maintain top-tier Google Play Vitals. By orchestrating Android Debug Bridge power commands with Claude Code through ScreenSync MCP, mobile engineering teams can transition from brittle manual testing to deterministic, fully autonomous power profiling.

ScreenSync MCP provides the ScreenSync MCP Android app, ScreenSync MCP hub, and ScreenSync MCP browser extension to developers and engineering teams worldwide. To get started with automated mobile device testing:

  1. Download the free ScreenSync MCP Android application from Google Play (com.screensync.mcp) at Get it on Google Play.
  2. Download the desktop hub from the official ScreenSync MCP homepage.
  3. Follow our step-by-step documentation to configure your development workstation.
  4. Explore our architectural overview of Android MCP servers to compare local stdio transports against remote device bridges.
FAQ

Questions, answered

How does Claude Code simulate unplugging the battery charger on a connected Android phone?

Claude Code executes Android Debug Bridge shell commands through the ScreenSync MCP hub. Calling adb shell dumpsys battery unplug forces the operating system into a discharging state, allowing developers to test low-battery callbacks, background throttling, and Doze mode transitions while keeping the host connection intact.

Does ScreenSync MCP require root permissions to inspect battery drain or force Doze mode?

No, ScreenSync MCP requires no root access. Screen capture operates through Android's native MediaProjection API after user consent, while device control and battery state commands execute via standard Android Debug Bridge shell interfaces over USB or authenticated local wireless debugging.

Why is testing battery drain on real physical devices superior to Android Studio emulators?

Android Studio emulators use synthetic, idealized power subsystems that cannot emulate cellular radio power transitions, Bluetooth low-energy hardware states, or genuine thermal throttling. Real physical Android devices reveal authentic battery consumption, radio tail states, and manufacturer-specific aggressive background process management.

How do App Standby Buckets affect background tasks during automated tests?

Android classifies applications into App Standby Buckets ranging from Active to Restricted based on user engagement. Higher restrictions defer JobScheduler and WorkManager tasks, throttle network access, and restrict high-priority Firebase Cloud Messaging quotas, which Claude Code can trigger deterministically via adb shell am set-standby-bucket.

Can Claude Code identify stuck wake locks in my application automatically?

Yes, Claude Code can inspect runtime wake locks by executing adb shell dumpsys batterystats and parsing get_logcat output. The agent flags partial wake locks held continuously beyond expected thresholds, identifying the exact thread or service preventing the Android kernel from entering deep sleep.

Will running wireless debugging affect my battery drain measurements?

Wireless debugging keeps the device Wi-Fi radio powered, creating a slight baseline power draw. To isolate application energy usage, engineers execute baseline differential tests, comparing device idle standby current against active background sync runs while Claude Code coordinates tests over local network sockets.

How does Doze mode interact with high-priority push notifications and WorkManager?

During deep Doze, Android suspends network access and standard alarms, deferring standard WorkManager jobs until periodic maintenance windows. Only high-priority push notifications break through Doze mode to grant temporary network and execution allowances, which Claude Code verifies end-to-end on real hardware.

Are battery telemetry logs or screen frames sent to EpsolDev servers during testing?

No, all video frames and device telemetry stream strictly across your local area network between your Android phone and desktop hub on port 3000. Frame data is never transmitted to EpsolDev servers, while explicit visual snapshots requested by an agent go to that agent's model provider.

Written by

ScreenSync MCP team

The ScreenSync MCP team at EpsolDev builds the Android app, the desktop MCP hub and the browser extension that let AI agents see and control a real phone. These guides come out of that work.