Battery profiling
Skill almasumdev/awesome-mobile-performance-agent-skills/.github/skills/battery/battery-profiling
Agent skills for profiling and optimizing mobile app performance (startup, memory, frame-rate, network).
npx -y skills add almasumdev/awesome-mobile-performance-agent-skills --skill battery-profilingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Attribute battery drain to CPU, radio, GPS, display, and background work using Android Battery Historian and Xcode Energy Log / Instruments Energy gauge.
SKILL.md
5.9 KB, as published. Nobody here has run it
Battery Profiling
Instructions
Battery drain is always attributable — CPU, radio wakeups, GPS, screen brightness, or unreleased wakelocks. This skill shows how to capture a reliable energy trace and how to read it.
1. What to Measure
- mAh per hour in a representative workload (idle, active feed, video).
- CPU time (user + kernel).
- Radio time (Wi-Fi on, cellular on, data transfer).
- Wakelocks / assertions count and duration.
- GPS / sensor active time.
- Screen on-time at which brightness.
Budgets (rule of thumb):
| State | Foreground (%/h) | Background (%/h) |
|---|---|---|
| Idle | < 3 | < 0.5 |
| Browsing | < 8 | — |
| Video | < 15 | — |
2. Android — Battery Historian
-
adb shell dumpsys batterystats --reset -
Unplug the device. Use the app for 10–20 minutes.
-
adb bugreport bugreport.zip -
Open Battery Historian or run locally via Docker:
docker run -p 9999:9999 bhaavan/battery-historian -
Upload
bugreport.zip. Inspect:- Wakelocks — per-app held wakelocks. Any partial wakelock > 30 s is suspect.
- Kernel wakeups — modem, Wi-Fi, alarm. Reduce with JobScheduler / WorkManager constraints.
- Process CPU — top processes while screen-off.
- Doze transitions — confirm the app respects Doze (no network during idle maintenance windows).
3. Android — On-Device Energy Profiler
Android Studio Profiler → Energy row on API 26+. Shows a unit-less high/medium/low indicator with a breakdown:
- CPU
- Network (radio-on cost + transfer cost)
- Location (GPS on)
Click a bar to see wakelock, alarm, and job events with stack traces — correlates code to energy cost.
4. iOS — Instruments Energy Log + Xcode Gauges
Xcode debugger gauge panel shows live Energy Impact. For reproducible measurements:
-
Product → Profile → Energy Log template (requires a physical device, ideally unplugged — use wireless debugging).
-
Record for 2–5 minutes under the scenario.
-
Track views:
- Energy Usage — high/low bars per second.
- CPU Activity — user vs kernel.
- Networking — bytes in/out and connection lifetime.
- Location — GPS/Wi-Fi scan activity.
- Display Brightness, Bluetooth, etc.
-
Generate a diagnostic
.logarchive:xcrun simctl spawn booted log collect
MetricKit in production:
class Delegate: NSObject, MXMetricManagerSubscriber {
func didReceive(_ payloads: [MXMetricPayload]) {
for p in payloads {
let cpu = p.cpuMetrics.cumulativeCPUTime
let cells = p.cellularConditionMetrics
// ship to telemetry
}
}
}
5. Common Drain Sources
| Symptom | Likely cause | Fix |
|---|---|---|
| High radio time even when idle | Chatty polling, small requests every 5–30 s | Batch, lengthen interval, use silent push. |
| Sustained wakelock | PARTIAL_WAKE_LOCK held across network retry loops | Use WorkManager with NetworkType.CONNECTED; drop explicit lock. |
| High CPU while screen off | Infinite timers, MQTT reconnect storm | Exponential backoff, FCM push instead of polling. |
| GPS active for minutes | "Always" location permission, foreground tracking bugs | Use significant-change / geofence APIs; stop when not needed. |
| Bluetooth always scanning | BLE scan without filters | Use ScanFilter + SCAN_MODE_LOW_POWER. |
| iOS "high energy" from WebView | Animated GIFs, complex CSS, autoplay video | Pause WebView on disappear; freeze animations. |
6. Guardrails in Code
Kotlin — prefer coroutines with cancellation and network constraints:
val req = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(false)
.build()
).build()
WorkManager.getInstance(ctx).enqueue(req)
Swift — use BGProcessingTaskRequest with requiresExternalPower/requiresNetworkConnectivity:
let req = BGProcessingTaskRequest(identifier: "com.app.sync")
req.requiresNetworkConnectivity = true
req.requiresExternalPower = false
try BGTaskScheduler.shared.submit(req)
7. Compare Before/After
Always compare two runs with the same workload, same starting battery level, same network conditions. Tools:
- Android Automator +
monkeyfor reproducible workloads. - XCUITest +
XCTApplicationLaunchMetric/custom metrics for iOS.
Checklist
- Energy baseline captured with an identical, scripted workload.
- Battery Historian shows no unexpected wakelock > 30 s.
- Energy Log / MetricKit
MXCPUMetricshows CPU time within budget. - No radio-on polling on the background path; push or batched sync only.
- GPS / BLE scanning uses filtered, low-power APIs.
- Background work uses WorkManager / BGTaskScheduler with constraints.
- Regression dashboard fed by MetricKit payloads in production.