androidengineers.Book a session

Battery & Network Optimization

Battery Historian & Energy Profiler

article20 minMedium

Battery Historian is Google's web-based tool for visualizing Android battery usage data. The Energy Profiler in Android Studio provides in-session energy estimates. Together they tell you exactly which of your app's activities are consuming battery.

Android Studio Energy Profiler

Access: Run → Profile App → select "Energy" tab.

The Energy Profiler shows:

  • CPU usage — correlated with your code activity
  • Network activity — radio wake events
  • Location usage — GPS/network location requests
  • Wake lock state — when your app holds the CPU awake

Reading the profiler:

Timeline ──────────────────────────────────
CPU      ░░░░████░░░░░░░████████░░░░░
Network  ░░░░████░░░░░░░░░░░░░░░░░░░
Location ░░░░░░░░░░░████████░░░░░░░░
Wake lock ████░░░░░░░░░░░████░░░░░░░
Energy    Low────────────High────────

Long Network bars paired with short CPU usage indicates background network polling — expensive and avoidable.

Battery Historian Setup

Battery Historian runs in Docker:

# Install Docker, then:
docker run -d -p 9999:9999 gcr.io/android-battery-historian/stable:3.1 --port 9999

# Or use the web version at: https://bathist.ef.lc/

Capturing Battery Stats

# Step 1: Reset stats to get a clean baseline
adb shell dumpsys batterystats --reset

# Step 2: Disable charging (or use adb to simulate)
adb shell dumpsys battery unplug

# Step 3: Run your app / usage scenario (10–30 minutes)

# Step 4: Export battery report
adb bugreport > /tmp/bugreport.zip

What to Look For in Battery Historian

Wakelock abuse:

KEY NAMES: wakelock_in
Pattern: Frequent short wakelocks = polling loops
Fix: Move to push (FCM) or WorkManager with constraints

Mobile radio activity:

KEY NAMES: mobile_radio, data_conn
Pattern: Frequent ON/OFF toggles = un-batched network
Fix: Batch requests; use OkHttp caching

GPS/location:

KEY NAMES: gps, scan_wifi
Pattern: GPS active when app is background = location leak
Fix: Remove updates in onStop; use geofencing for background

Identifying Battery Drains Programmatically

// Check if your app is in App Standby "Restricted" bucket
val usageStatsManager = getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val isRestricted = usageStatsManager.appStandbyBucket == UsageStatsManager.STANDBY_BUCKET_RESTRICTED

// Check battery optimization exemption status
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
val isIgnoringBatteryOptimization = powerManager.isIgnoringBatteryOptimizations(packageName)

Wakelocks: Audit and Fix

// ❌ PowerManager WakeLock not released — device stays awake
val wl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp:sync")
wl.acquire()
// ... work that might throw, leaving wl unreleased

// ✅ Always use try/finally; or use timeout
wl.acquire(60_000)  // auto-release after 60 seconds maximum
try {
    doSync()
} finally {
    if (wl.isHeld) wl.release()
}

Battery Stats adb Shortcut

# Quick wakelocks summary without full bugreport
adb shell dumpsys batterystats | grep "Wakelock"

# Network usage by app
adb shell dumpsys netstats detail

# Top battery consumers
adb shell dumpsys batterystats --charged | grep "Estimated power use"

Common Battery Offenders

OffenderHow to spotFix
Unreleased WakeLockBattery Historian wakelock row never drops to 0acquire(timeout) + finally { release() }
Background pollingRapid network spikes while screen offReplace with FCM push
GPS in backgroundLocation row active when no user visible featureRemove location updates in onStop
Excessive JobScheduler jobsMany short job events in historianBatch into fewer, longer jobs
Unregistered sensor listenerCPU row consistently active in backgroundUnregister in onStop

YOUR LEARNING JOURNEY

0 of 177 available lessons completed

Progress saved in this browser. No account needed.
Battery Historian & Energy Profiler | Android System Design | Android Engineers