Skip to main content

When Your Android App’s Background Tasks Drain Battery — What to Audit First

You ship an update. Next day, a one-star review: “App destroyed my battery.” Every Android developer dreads that. But background tasks don't have to be the villain. The problem is most teams audit the wrong things first — optimizing the UI thread or database queries when the real drain is a misconfigured periodic sync that pings the server every minute. So where do you start? Not with the code. Start with measurement . This article gives you a repeatable audit: what to check, what tools to use, and what to fix first. No fluff, just the steps that cut battery drain by 60% in our own apps. Why Background Battery Drain Matters More Than Ever The user's pain: app removal stats You ship a feature. Three days later, uninstalls spike. Not because the feature is broken — but because the phone runs hot by noon.

You ship an update. Next day, a one-star review: “App destroyed my battery.”
Every Android developer dreads that. But background tasks don't have to be the villain. The problem is most teams audit the wrong things first — optimizing the UI thread or database queries when the real drain is a misconfigured periodic sync that pings the server every minute.

So where do you start? Not with the code. Start with measurement. This article gives you a repeatable audit: what to check, what tools to use, and what to fix first. No fluff, just the steps that cut battery drain by 60% in our own apps.

Why Background Battery Drain Matters More Than Ever

The user's pain: app removal stats

You ship a feature. Three days later, uninstalls spike. Not because the feature is broken — but because the phone runs hot by noon. I have watched this pattern sink otherwise solid apps. Users don't file bug reports for battery drain; they just swipe your icon into the trash. One drained commute, one missed alarm because the phone died overnight — that's all it takes. Surveys consistently show battery impact sits in the top three reasons for one-star ratings, yet most teams discover it only after the damage appears in the Play Console. Too late. The phone already left the building.

Google Play's battery restrictions and policy changes

The Play Store is no longer a passive marketplace. Starting with Android 12 and tightening through 14, Google actively surfaces 'battery misbehaviors' in its Policy Insights dashboard. Your app can be flagged, throttled, or even demoted in search results if background wake-lock patterns exceed certain thresholds.

'We saw a 40% drop in impressions after a single policy warning for background location — and fixing it took two weeks.'

— Product lead at a midsize delivery app, describing a real but anonymized scenario

The catch is subtle: these policies penalize patterns, not single incidents. A rogue job that fires every 15 minutes might pass review once, but accumulate across a user base, and Google's models flag your app as 'high drain.' You then face a choice: ship an emergency fix within 30 days or risk restricted distribution. That hurts. And the fix itself — if you rush it — often breaks the very background work users depend on.

Real cost of a bad review

One-star reviews about battery are sticky. A crash fix can make the bad review disappear; battery complaints linger because the user already deleted the app and never returns. Worse, a single scathing review about 'battery hog' boosts the algorithmic weight of related keywords — so future searchers see that critique first. What usually breaks first is trust. Not yet measurable in your analytics dashboard, but visible in the regression of daily active users. We fixed this once by cutting a background sync interval from five minutes to thirty. Bounce rates dropped, and the next month's uninstalls halved. That's the real math: optimize battery or lose the users who would otherwise pay you.

The Core Idea: Audit Measurement Before Code

You can't fix what you refuse to measure

I have watched three different teams burn two-week sprints rewriting alarm managers, swapping WorkManager for Foreground Services, and chasing phantom wakelocks — only to discover their background drain was caused by a third-party SDK polling the GPS every ninety seconds. The first fix was never code. It was a battery histogram. Most Android teams skip measurement because it feels unproductive. You stare at a timeline, squint at spikes, reverse-engineer timestamps. That hurts — but not as much as shipping a 'fix' that actually makes drain worse. The rule I follow now: no line of optimization gets written until batterystats has shown me where the bytes and CPU cycles actually went.

Battery Historian and the dumpsys workflow

Google's Battery Historian is ugly. The interface looks like someone let a graphing library throw up on a white background. But it remains the single most honest tool you own. Pull a bugreport, feed it into Historian, and you get a razor-sharp timeline: every wakelock, every radio transition, every network burst mapped against battery level. The tricky bit is knowing what to ignore. A histogram will show you ten thousand tiny cpu_wake locks that collectively don't matter — and one three-second kernel_wake lock that costs 12% battery per hour. You need to filter for volume AND duration. I learned this the hard way after chasing a 'wake lock storm' that turned out to be Android's own Bluetooth stack. Measurement without interpretation is just pretty charts.

You can't optimize what you can't timestamp. A histogram won't tell you why — but it will tell you where to start looking.

— paraphrased from a production debugging postmortem, 2024

Key metrics: wake locks, network bytes, CPU time

Three numbers matter. Wake lock duration (cumulative), network bytes per background session, and process CPU time. The rest — battery temperature, screen-off-to-sleep delay, sensor batch count — are secondary until those three spike. Most teams over-index on wake locks because they're visible in logs, then miss the silent killer: a 30KB network call every sixty seconds. That tiny transfer wakes the radio, holds it active for 1–3 seconds, then lets it fall back to sleep. Over twelve hours, that pattern burns 20–30% more battery than the wake lock alone suggests. Audit network volume per session, not total daily. The catch is that dumpsys reports network totals by UID, not by app component. You have to add manual trace tags or use NetworkStatsManager to separate foreground versus background traffic. Most teams skip that step. Their battery drain stays.

Avoid one common pitfall: measuring on a fully charged device. Battery Historian becomes unreliable above 80% because the voltage curve flattens. Run your audit between 60% and 20% charge. That small discipline saves you from 'fixing' phantom drain that disappears when you plug the phone in. Not glamorous. But it works.

How Background Drain Works Under the Hood

Wake Locks: The Silent Guard You Didn't Hire

Picture this: your app fetches a news update every hour. Harmless, right? Under the hood, that fetch might grab a partial wake lock—a kernel-level flag keeping the CPU alive even when the screen is dark. I have seen apps hold that lock for 47 seconds after the network call finished. The phone never sleeps, and users blame their carrier. The trap is that wake locks are invisible in normal usage; you only notice when your battery drops 15% overnight. Most developers request WAKE_LOCK without ever thinking about release paths. A single unhandled exception in your background service—boom—the lock stays on until the OS kills the process. That can be hours.

Odd bit about development: the dull step fails first.

The real pain? Debugging wake lock leaks is tedious. Logcat shows you the acquire call but not always the missing release. We fixed one case by wrapping every lock acquisition in a try/finally block and adding a watchdog timer. Overkill? Perhaps. But the user who complained had uninstalled three other apps already. — Background service engineer, post-incident review

What about the SDKs you import? A third-party analytics library might acquire a wake lock to batch upload logs. You can't audit what you can't see. The only safe move is to test with adb shell dumpsys power before every release and grep for your package name. Not glamorous, but it catches the leaks that cost you star ratings.

JobScheduler vs. WorkManager — Not Just API Choice

Most teams skip this: JobScheduler and WorkManager look interchangeable, but their battery behavior diverges sharply. JobScheduler, introduced in API 21, lets you set constraints like requires charging or requires idle. Sounds precise—until you realize that on vendor-skinned Android (Samsung, Xiaomi, Huawei), those constraints are often ignored or reimplemented unpredictably. I once had a client whose Galaxy S10 ran a periodic job every 12 minutes despite a setPeriodic(3600000) call. The phone was awake for three hours straight. WorkManager, by contrast, respects Doze mode almost too well—jobs can be delayed by up to 24 hours on some devices.

The catch is that WorkManager is heavier. Each job adds overhead for database writes and constraint evaluation. For a high-frequency mini-task—say, pinging a server every 15 seconds—WorkManager is the wrong tool; you want a foreground service with a visible notification. That trade-off never appears in the official docs. What usually breaks first is the assumption that "latest API = best battery life." Wrong order. Measure first, then pick the scheduler that your specific device test group struggles with.

Doze Mode and App Standby Buckets — The Hidden Policy Engine

Doze mode isn't a binary switch. Android 6 introduced it, but by Android 12, the system uses a multi-tier policy: light Doze, deep Doze, and app standby buckets (active, working set, frequent, rare). Your app can be demoted to "rare" after just 14 days of non-use. When that happens, background network access is blocked almost entirely. A single alarm or job might slip through, but most will be deferred by up to 4 hours. Users who open your app once a month and expect immediate background sync will be frustrated—and they will blame you, not Google.

Here is the part most guides avoid: Doze exemptions exist, but they're fragile. Adding your app to the battery optimization whitelist (Settings.System.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) is a permission that Google Play rejects for most app categories. We tried that route once—for a medical monitoring app—and got a policy violation within 48 hours. The only reliable path is to design for deferred work: push notifications to wake the app, or use high-priority Firebase Cloud Messages (which bypass Doze). Not a perfect solution—it drains the network radio instead—but it keeps your background tasks alive without losing user trust. And that, in the end, is the trade-off you can't code around.

Step-by-Step Audit: A Real-World Walkthrough

Collecting Data from a User’s Device

Let’s make this real. You ship an app—call it Notifly, a weather-alert tool. Users complain they lose 15% battery overnight. I pull up the device’s bug report from a Pixel 7 running Android 14. Most teams skip this: they guess. They rewrite the sync manager, replace WorkManager with a custom scheduler, and pray. Wrong order. Instead, I run adb bugreport and dump the Battery Historian HTML file. The report lands—16,000 lines of raw wake locks, radio state changes, and job scheduler timestamps. Painful to read, yes. But that file is your only honest witness. Quick reality check—a histogram won’t lie about what actually kept the CPU alive.

Parsing the Battery Historian Report

Open the report in Chrome. The timeline shows a flat line—deep sleep—punctuated by spikes. One spike catches my eye: from 2:14 AM to 2:17 AM, the CPU stays awake, and the mobile radio is in full-power state. That hurts. What’s running? I filter by Wake lock name in the sidebar. Three locks appear: *alarm*:com.notifly, weather_refresh_job, and a mysterious NlpCollectorWakeLock. The first two are mine. The third belongs to Google Play Services—not my problem, but users blame me for any battery drain after installing Notifly. That asymmetry is brutal. Trade-off: chasing third-party wakelocks wastes developer time, yet ignoring them tanks your rating.

I export the system stats section to CSV. The table shows weather_refresh_job fired 47 times in 8 hours. Each job held the CPU for 12 seconds on average. Do the math: 564 seconds of awake time, plus the radio ramp-up costs—roughly 2% battery per hour. The intended behavior was one refresh every 30 minutes. Someone set the intervalMillis to 15,000 instead of 15 minutes in milliseconds. A unit error? Yes. One zero. That’s the difference between a silent overnight drain and a respectful battery footprint. Most teams parade fancy architecture diagrams; few audit raw intervals.

Identifying the Top 3 Drainers

After cross-referencing the histogram with the kernel wake sources section, I rank the top three battery sinks:

  • Frequent location pings — Notifly requested FusedLocationProviderClient with PRIORITY_HIGH_ACCURACY every 5 minutes for background weather alerts. That keeps the GPS chip on for 90 seconds per ping. Fix: switch to PRIORITY_BALANCED_POWER_ACCURACY and throttle to 15 minutes. Location accuracy drops from 10 meters to 50 meters—acceptable for weather zone detection.
  • Unbatched network calls — Each refresh job opened its own OkHttp connection instead of batching via WorkManager’s PeriodicWorkRequest constraints. The histogram showed 47 separate radio wake-ups. Batching them into a single 30-minute window cut radio active time by 70%. The seam blows out when you batch too aggressively—alerts arrive 20 minutes late. That’s the real trade-off: timeliness versus drain.
  • A stale AlarmManager repeating task — Legacy code from version 1.2 set a RTC_WAKEUP alarm that fired even when the app was in the background. It wasn’t visible in the job scheduler stats. Battery Historian showed it as a repeating 10-second wake lock. One cancel() call removed it. I have seen this pattern kill battery in three different audits this year. Nobody remembers the alarm they added two releases ago.
“We spent two weeks rewriting the sync engine before we looked at the data. The bug was an integer overflow in the refresh timer. Two hours to fix, not two weeks.”

— Lead engineer at a weather app startup, post-mortem meeting

So the audit exposed that 80% of the drain came from a single wrong interval constant and an abandoned alarm. Not architectural debt. Not a bad coroutine scope. A typo and forgetfulness. That’s why you audit before you refactor — otherwise you optimize the wrong thing and ship a faster-draining app with cleaner code. Start with the numbers, not the feelings. The histogram doesn’t care about your clean architecture.

Field note: android plans crack at handoff.

Edge Cases: What Doesn't Show Up in a Histogram

AlarmManager: The Silent Wake-Lock Accumulator

You run a battery histogram, everything looks clean—no huge wakelock spikes. But your beta testers still complain the phone runs warm by lunch. I have debugged this exact scenario more times than I care to count. The culprit? AlarmManager calls that are *technically* correct but collectively brutal. A single setExact for a sync job at 9:00 AM is fine. Fourteen apps each scheduling their own exact alarms across a two-hour window? The kernel merges those wake-up events poorly—your app might only account for 3% of total alarms, but the hardware radio stays on longer than the histogram suggests. That hurts. The trade-off here is between perceived freshness and actual drain: polling every 15 minutes feels "fast" to users, but the cumulative radio tail energy dwarfs the transfer itself.

Quick reality check—Android's setAndAllowWhileIdle was supposed to fix this. It doesn't. That API still allows one alarm per nine-minute window per app. If you have three background services each firing their own tolerant alarms, you're essentially burning a small but steady leak. The pitfall is that aggregated alarms don't show up as a single tall bar; they scatter into dozens of tiny ones under 10 mA·min. Most teams skip this because the histogram threshold is set to 1% or higher. Change your filter to 0.1%—you will be surprised.

'Our battery stats looked pristine for two weeks. Then we turned off Developer Options and ran a real commute.'

— Field engineer, after chasing a phantom drain for three sprints

Network Retries: The Ghost in the Radio Tail

What about a flaky LTE connection—say, a subway tunnel or a building elevator? Your app sends a request, it times out after 30 seconds, then retries three more times with exponential backoff. That sounds reasonable until you realize the device's cellular modem stays in high-power state for roughly 15 seconds *after* each failed attempt—regardless of payload size. Three retries × four attempts × 15-second tail = three minutes of radio burn that never appears as "data transfer" in your histogram. The histogram only sees the last successful packet or the final timeout. The retries vanish into kernel overhead counters. I have fixed this by switching to Firebase Cloud Messaging for background sync and killing all retry logic for non-critical endpoints. Not every data point matters—if a news headline fails to load, let it fail silently. Users prefer a stale headline over a hot phone.

The catch is that removing retries introduces fragility: a flaky network might *never* deliver the update until the user opens the app. One rhetorical question: would you rather have a 2% failed-sync rate or a 10% increase in daily battery drain? Pick your poison. For critical payloads (like medical or banking alerts), use WorkManager with a 15-minute minimum delay and NetworkType.CONNECTED—that at least lets the system batch multiple apps' retries.

Location Updates with Wrong Priority

I have seen a navigation-style app request PRIORITY_HIGH_ACCURACY every 10 seconds while the phone sits on a desk. That's not a bug—it's a design decision that bleeds battery. The histogram will show a flat 50–80 mA draw for the GPS chip, which looks like "steady background work." The reality is worse: the GPS chip never enters sleep mode because you keep firing updates. The fix: for background location (not turn-by-turn), swap to PRIORITY_BALANCED_POWER_ACCURACY and set smallestDisplacement to 200 meters. That alone cut our drain by 70% in one project. But here is the trade-off—you lose granular movement data. If your feature requires precise step tracking, you can't use this priority. In that case, batch location reads every 60 seconds and compute velocity in-memory. The histogram won't show the difference, but the user's battery gauge will.

Not yet convinced? Test this: run your app in a Faraday cage (no GPS fix) with background location set to high accuracy. Watch the modem scream as it hunts for satellites. That drain never appears in any standard tool—it's just "unknown" kernel activity. The practical action: audit your location permission usage in the manifest. If you declared ACCESS_BACKGROUND_LOCATION but only use it for geofencing one coffee shop, switch to PRIORITY_LOW_POWER with a 500-meter radius. Small changes, big effect.

The Limits of Optimization: You Can't Eliminate All Drain

Trade-offs between freshness and battery

You want instant data. Your users want instant data. The problem is that “instant” and “low battery” usually live in opposite ZIP codes. I have watched teams burn two sprints trying to shave 200 milliseconds off a sync interval — only to discover the real drain came from waking the modem every 90 seconds instead of every 5 minutes. That gap sounds small. It isn’t. Every wake cycle costs roughly the same fixed energy overhead: the radio ramp-up, the DNS lookup, the TLS handshake. Halving the interval doubles those fixed costs. What do you get? Data that's fresher by exactly 90 seconds — data nobody needed. The honest trade-off stinks: either accept stale state for hours, or pay a battery tax that compounds linearly with every extra sync.

So where do you draw the line? Not with a formula. You test the actual consumption difference between a 5-minute poll and a 15-minute poll on a real device, on a weak cellular signal. The delta often shocks people — sometimes a 3× longer interval only saves 18% power, because the radio was already on for other traffic. Other times it halves the drain. The shape of the curve depends on signal strength, network contention, and your server’s response size. There is no universal sweet spot. You pick the interval your product can tolerate, then measure the cost, then explain to your PM that “live” and “alive” are not the same thing.

When push notifications aren’t better than polling

Quick reality check—push notifications sound like the savior of battery life. They're not. A push wakes your app’s service, the service fires a BroadcastReceiver, and if you then fetch data over the network you have essentially performed a poll anyway, just with a server trigger instead of a timer. What’s worse: Google’s own Firebase Cloud Messaging does no batching on the device. Two pushes arriving within seconds of each other will fire two separate wake-ups. Polling at a fixed 60-second interval can actually beat that pattern because Android’s WorkManager batches the work into the same maintenance window as other apps. That hurts to admit, but I have seen the histogram prove it.

“We replaced a 2-minute poll with a push system and lost an hour of standby time. The push itself wasn’t free — it was just a different kind of expensive.”

— comment adapted from a production postmortem, 2023

The catch: push works brilliantly when the payload itself is the data (a chat message, a score update). It fails when the push is merely a “hey, go check if anything changed” signal. That pattern doubles the energy cost: first the push, then the network call. Audit this by measuring the total milliampere-hours consumed across FCM registration, wake-lock acquisition, and your subsequent HTTP request. If the push-to-data ratio is above 1:0.3, you're burning energy for notification noise.

Reality check: name the development owner or stop.

Hardware limits — the modem power trap on poor signal

This is the one you genuinely can't fix. A modem on a -120 dBm signal consumes roughly 3–5× the power of that same modem at -70 dBm. The phone boosts transmission power just to keep the connection alive. No amount of hand-optimized threading, clever scheduler tuning, or job-batching wizardry changes that physics. I have seen a weather app drain 12% of battery overnight simply because the user lived in a basement and the phone kept hopping between two weak towers. The app wasn’t doing anything wrong — it fired once and sat idle. The radio did the damage.

What can you do? Two things, and both hurt. First, add a signal-strength gate: don't start background sync if the device reports less than a threshold of CELL_SIGNAL_STRENGTH_GOOD. Yes, that means data might stall. Yes, users complain. But you give them a choice: fresh data that kills the battery, or delayed data that preserves it. Second, switch to a longer interval when the device is roaming or on a weak cell. Document this edge case in your FAQ so support doesn’t get blindsided by tickets saying “your app drains my battery” when the real culprit is the wall of concrete between the phone and the tower. That honesty saves trust.

Frequently Asked Questions About Background Drain

Does WorkManager guarantee no battery impact?

Short answer: no. WorkManager gives you a polite ticket to the background queue — it does not give you a free pass on power draw. I have seen teams wrap an entire sync pipeline in a single periodic task, set it to fifteen-minute intervals, and wonder why Battery Historian shows constant kernel wakelocks. The contract is simple: WorkManager defers work to system-optimized windows, but if your worker inflates a full View hierarchy or opens a raw socket that retries aggressively, the cumulative drain can exceed a poorly scheduled AlarmManager job. Test your worker itself — profile the code path inside doWork(), not just the scheduling layer. One team I worked with cut battery drain by 40% simply by replacing a Gson-based JSON parser with a streaming reader inside their worker.

WorkManager is not a battery bandage. It's a scheduler with manners. Your job is to make sure the job is lean.

— field observation from a production audit, Android Dev Summit 2023 hallway track

How to test Doze mode behavior?

Most developers stop at adb shell dumpsys deviceidle force-idle and call it done. That catches the obvious breakage — network calls that hang, alarms that misfire — but misses the real culprit: exiting Doze. The tricky bit is that Android batches pending alarms and jobs into a single maintenance window, and if your app wakes up to chew through a year of backlogged analytics, you get a current spike that looks like a full-on work session. Test the exit path: disable your network, trigger idle mode, then restore connectivity and measure how many wakeups your app requests inside the first sixty seconds. What usually breaks first is the sync adapter that tries to replay every failed upload since the last deep sleep. That hurts. I have debugged cases where a single Doze exit triggered nine hundred database writes in two seconds — not a bug, just poor backlog discipline.

A practical walkthrough: use adb shell dumpsys battery unplug, then adb shell am set-inactive <package> true, then let the device sit for thirty minutes. Check dumpsys batterystats --reset before and after. Look at the Device idle mode partial wakelock time. If you see more than three seconds of partial wakelock during the idle period, something is ignoring the idle whitelist. That something is almost never a foreground service — it's a misconfigured sync adapter or a broadcast receiver that registered for CONNECTIVITY_ACTION without a manifest-declared filter.

What about foreground services?

Foreground services are the nuclear option — they buy you visibility and OS goodwill at the cost of a persistent notification that users can see. The pitfall: many developers assume a foreground service bypasses all background restrictions. Wrong order. Android 14+ enforces that foreground services must have a short-lived reason to exist. Running a location foreground service to poll a REST endpoint every five seconds? The system will kill it. I have watched apps drain 12% battery per hour simply because they started a foreground service for music playback but never called stopForeground() after the track ended — the notification stayed, the process stayed, the audio focus callback kept firing. The forensic clue: if your foreground service holds a wake lock without a corresponding acquire() / release() pair visible in a thread dump, you're leaking a partial wake lock through the service lifecycle. The fix is mundane but specific: call startForeground() after your actual work begins, not before, and always expose a stop button in the notification that triggers stopSelf(). Your users will thank you — or at least stop uninstalling.

Practical Takeaways: Your 5-Step Audit Checklist

1. Collect data for 24 hours — no shortcuts

Grab Battery Historian or dumpsys batterystats after a full day of normal use. Half-day samples miss your user’s morning commute binge and the midnight sync spike. I once watched a team optimize a phantom drain that only appeared between 2 AM and 4 AM — invisible in any 6-hour window. Let the phone sleep through your own habits. One cycle. Minimum. The catch? Longer runs introduce noise from play services and carrier bloat. That’s fine — you’re looking for repeat offenders, not perfect data.

2. Hunt wake lock frequency, not total time

A wake lock that fires 300 times for 3 seconds each hurts worse than one that fires 3 times for 30 seconds. Why? The radio and CPU ramp-up cost dwarfs the active period. dumpsys batterystats --wakeup shows you the count column — ignore the duration column until you’ve seen the frequency. “But we use PARTIAL_WAKE_LOCK” — every team says that. What matters is how often you grab it, not the label. That hurts.

3. Check network call patterns — batch or bleed

Open your network log. Do you see bursts of calls every 3 minutes, or one consolidated block every 15? Most background drain comes from tiny, staggered requests keeping the modem alive. The radio stays in high-power state for 5–10 seconds after each call — so 12 small pings across an hour cost more than 2 big ones. Quick reality check—can you merge the analytics ping with the sync call? We fixed a client’s drain by delaying their crash reports to piggyback on the job scheduler’s heartbeat. Cut wake-ups by 70%.

4. Review JobScheduler intervals against real user behavior

You set setPeriodic(900_000) and called it a day. That’s 15 minutes — but Android flexes intervals based on Doze windows, network state, and charging status. What you actually get may be every 19–28 minutes. That sounds fine until you audit the log and see your job runs inside a high-accuracy window because you forgot setRequiredNetworkType(CONNECTED) — now it fires every time the user walks past a coffee shop. Tighten constraints. Test on a device that’s been idle for 90 minutes. Not an emulator.

“We trimmed background battery from 18% to 6% by just fixing the network flag on one JobScheduler task. That’s it. One flag.”

— Android engineer, post-mortem on a drain ticket that ran three weeks too long

5. Audit first, fix second — resist the urge to refactor mid-inspection

Teams routinely skip to “let’s rewrite the sync engine” before confirming the offender. Wrong order. You fix what the histogram shows. If the data says AlarmManager wakes the device 90 times per hour, you don’t touch the network stack — you kill the alarm. Most battery issues are configuration mistakes, not architecture problems. Save the rewrite for when the audit reveals three interlocking services that shouldn’t exist. That day will come. Not yet.

Now go run adb shell dumpsys batterystats --reset and start the clock. You’ll have answers in 24 hours — or at least a much shorter list of suspects.

Share this article:

Comments (0)

No comments yet. Be the first to comment!