1 /*
2  * Copyright (C) 2006-2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.am;
18 
19 import android.app.ActivityManager;
20 import android.app.job.JobProtoEnums;
21 import android.bluetooth.BluetoothActivityEnergyInfo;
22 import android.content.Context;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.PackageManager;
25 import android.net.wifi.WifiActivityEnergyInfo;
26 import android.os.BatteryStats;
27 import android.os.BatteryStatsInternal;
28 import android.os.Binder;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Parcel;
32 import android.os.ParcelFileDescriptor;
33 import android.os.ParcelFormatException;
34 import android.os.PowerManager.ServiceType;
35 import android.os.PowerManagerInternal;
36 import android.os.PowerSaveState;
37 import android.os.Process;
38 import android.os.ServiceManager;
39 import android.os.SystemClock;
40 import android.os.UserHandle;
41 import android.os.UserManagerInternal;
42 import android.os.WorkSource;
43 import android.os.connectivity.CellularBatteryStats;
44 import android.os.connectivity.GpsBatteryStats;
45 import android.os.connectivity.WifiBatteryStats;
46 import android.os.health.HealthStatsParceler;
47 import android.os.health.HealthStatsWriter;
48 import android.os.health.UidHealthStats;
49 import android.telephony.DataConnectionRealTimeInfo;
50 import android.telephony.ModemActivityInfo;
51 import android.telephony.SignalStrength;
52 import android.telephony.TelephonyManager;
53 import android.util.Slog;
54 import android.util.StatsLog;
55 
56 import com.android.internal.app.IBatteryStats;
57 import com.android.internal.os.BatteryStatsHelper;
58 import com.android.internal.os.BatteryStatsImpl;
59 import com.android.internal.os.PowerProfile;
60 import com.android.internal.os.RpmStats;
61 import com.android.internal.util.DumpUtils;
62 import com.android.server.LocalServices;
63 
64 import java.io.File;
65 import java.io.FileDescriptor;
66 import java.io.IOException;
67 import java.io.PrintWriter;
68 import java.nio.ByteBuffer;
69 import java.nio.CharBuffer;
70 import java.nio.charset.CharsetDecoder;
71 import java.nio.charset.CodingErrorAction;
72 import java.nio.charset.StandardCharsets;
73 import java.util.Arrays;
74 import java.util.List;
75 import java.util.concurrent.ExecutionException;
76 import java.util.concurrent.Future;
77 
78 /**
79  * All information we are collecting about things that can happen that impact
80  * battery life.
81  */
82 public final class BatteryStatsService extends IBatteryStats.Stub
83         implements PowerManagerInternal.LowPowerModeListener,
84         BatteryStatsImpl.PlatformIdleStateCallback {
85     static final String TAG = "BatteryStatsService";
86     static final boolean DBG = false;
87 
88     private static IBatteryStats sService;
89 
90     final BatteryStatsImpl mStats;
91     private final BatteryStatsImpl.UserInfoProvider mUserManagerUserInfoProvider;
92     private final Context mContext;
93     private final BatteryExternalStatsWorker mWorker;
94 
getLowPowerStats(RpmStats rpmStats)95     private native void getLowPowerStats(RpmStats rpmStats);
getPlatformLowPowerStats(ByteBuffer outBuffer)96     private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
getSubsystemLowPowerStats(ByteBuffer outBuffer)97     private native int getSubsystemLowPowerStats(ByteBuffer outBuffer);
98     private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
99                     .newDecoder()
100                     .onMalformedInput(CodingErrorAction.REPLACE)
101                     .onUnmappableCharacter(CodingErrorAction.REPLACE)
102                     .replaceWith("?");
103     private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE);
104     private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
105     private static final int MAX_LOW_POWER_STATS_SIZE = 2048;
106 
107     /**
108      * Replaces the information in the given rpmStats with up-to-date information.
109      */
110     @Override
fillLowPowerStats(RpmStats rpmStats)111     public void fillLowPowerStats(RpmStats rpmStats) {
112         if (DBG) Slog.d(TAG, "begin getLowPowerStats");
113         try {
114             getLowPowerStats(rpmStats);
115         } finally {
116             if (DBG) Slog.d(TAG, "end getLowPowerStats");
117         }
118     }
119 
120     @Override
getPlatformLowPowerStats()121     public String getPlatformLowPowerStats() {
122         if (DBG) Slog.d(TAG, "begin getPlatformLowPowerStats");
123         try {
124             mUtf8BufferStat.clear();
125             mUtf16BufferStat.clear();
126             mDecoderStat.reset();
127             int bytesWritten = getPlatformLowPowerStats(mUtf8BufferStat);
128             if (bytesWritten < 0) {
129                 return null;
130             } else if (bytesWritten == 0) {
131                 return "Empty";
132             }
133             mUtf8BufferStat.limit(bytesWritten);
134             mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
135             mUtf16BufferStat.flip();
136             return mUtf16BufferStat.toString();
137         } finally {
138             if (DBG) Slog.d(TAG, "end getPlatformLowPowerStats");
139         }
140     }
141 
142     @Override
getSubsystemLowPowerStats()143     public String getSubsystemLowPowerStats() {
144         if (DBG) Slog.d(TAG, "begin getSubsystemLowPowerStats");
145         try {
146             mUtf8BufferStat.clear();
147             mUtf16BufferStat.clear();
148             mDecoderStat.reset();
149             int bytesWritten = getSubsystemLowPowerStats(mUtf8BufferStat);
150             if (bytesWritten < 0) {
151                 return null;
152             } else if (bytesWritten == 0) {
153                 return "Empty";
154             }
155             mUtf8BufferStat.limit(bytesWritten);
156             mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
157             mUtf16BufferStat.flip();
158             return mUtf16BufferStat.toString();
159         } finally {
160             if (DBG) Slog.d(TAG, "end getSubsystemLowPowerStats");
161         }
162     }
163 
BatteryStatsService(Context context, File systemDir, Handler handler)164     BatteryStatsService(Context context, File systemDir, Handler handler) {
165         // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
166         mContext = context;
167         mUserManagerUserInfoProvider = new BatteryStatsImpl.UserInfoProvider() {
168             private UserManagerInternal umi;
169             @Override
170             public int[] getUserIds() {
171                 if (umi == null) {
172                     umi = LocalServices.getService(UserManagerInternal.class);
173                 }
174                 return (umi != null) ? umi.getUserIds() : null;
175             }
176         };
177         mStats = new BatteryStatsImpl(systemDir, handler, this, mUserManagerUserInfoProvider);
178         mWorker = new BatteryExternalStatsWorker(context, mStats);
179         mStats.setExternalStatsSyncLocked(mWorker);
180         mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
181                 com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
182         mStats.setPowerProfileLocked(new PowerProfile(context));
183     }
184 
publish()185     public void publish() {
186         LocalServices.addService(BatteryStatsInternal.class, new LocalService());
187         ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
188     }
189 
systemServicesReady()190     public void systemServicesReady() {
191         mStats.systemServicesReady(mContext);
192     }
193 
194     private final class LocalService extends BatteryStatsInternal {
195         @Override
getWifiIfaces()196         public String[] getWifiIfaces() {
197             return mStats.getWifiIfaces().clone();
198         }
199 
200         @Override
getMobileIfaces()201         public String[] getMobileIfaces() {
202             return mStats.getMobileIfaces().clone();
203         }
204 
205         @Override
noteJobsDeferred(int uid, int numDeferred, long sinceLast)206         public void noteJobsDeferred(int uid, int numDeferred, long sinceLast) {
207             if (DBG) Slog.d(TAG, "Jobs deferred " + uid + ": " + numDeferred + " " + sinceLast);
208             BatteryStatsService.this.noteJobsDeferred(uid, numDeferred, sinceLast);
209         }
210     }
211 
awaitUninterruptibly(Future<?> future)212     private static void awaitUninterruptibly(Future<?> future) {
213         while (true) {
214             try {
215                 future.get();
216                 return;
217             } catch (ExecutionException e) {
218                 return;
219             } catch (InterruptedException e) {
220                 // Keep looping
221             }
222         }
223     }
224 
syncStats(String reason, int flags)225     private void syncStats(String reason, int flags) {
226         awaitUninterruptibly(mWorker.scheduleSync(reason, flags));
227     }
228 
229     /**
230      * At the time when the constructor runs, the power manager has not yet been
231      * initialized.  So we initialize the low power observer later.
232      */
initPowerManagement()233     public void initPowerManagement() {
234         final PowerManagerInternal powerMgr = LocalServices.getService(PowerManagerInternal.class);
235         powerMgr.registerLowPowerModeObserver(this);
236         synchronized (mStats) {
237             mStats.notePowerSaveModeLocked(
238                     powerMgr.getLowPowerState(ServiceType.BATTERY_STATS)
239                             .batterySaverEnabled);
240         }
241         (new WakeupReasonThread()).start();
242     }
243 
shutdown()244     public void shutdown() {
245         Slog.w("BatteryStats", "Writing battery stats before shutdown...");
246 
247         syncStats("shutdown", BatteryExternalStatsWorker.UPDATE_ALL);
248 
249         synchronized (mStats) {
250             mStats.shutdownLocked();
251         }
252 
253         // Shutdown the thread we made.
254         mWorker.shutdown();
255     }
256 
getService()257     public static IBatteryStats getService() {
258         if (sService != null) {
259             return sService;
260         }
261         IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME);
262         sService = asInterface(b);
263         return sService;
264     }
265 
266     @Override
getServiceType()267     public int getServiceType() {
268         return ServiceType.BATTERY_STATS;
269     }
270 
271     @Override
onLowPowerModeChanged(PowerSaveState result)272     public void onLowPowerModeChanged(PowerSaveState result) {
273         synchronized (mStats) {
274             mStats.notePowerSaveModeLocked(result.batterySaverEnabled);
275         }
276     }
277 
278     /**
279      * @return the current statistics object, which may be modified
280      * to reflect events that affect battery usage.  You must lock the
281      * stats object before doing anything with it.
282      */
getActiveStatistics()283     public BatteryStatsImpl getActiveStatistics() {
284         return mStats;
285     }
286 
287     /**
288      * Schedules a write to disk to occur. This will cause the BatteryStatsImpl
289      * object to update with the latest info, then write to disk.
290      */
scheduleWriteToDisk()291     public void scheduleWriteToDisk() {
292         mWorker.scheduleWrite();
293     }
294 
295     // These are for direct use by the activity manager...
296 
297     /**
298      * Remove a UID from the BatteryStats and BatteryStats' external dependencies.
299      */
removeUid(int uid)300     void removeUid(int uid) {
301         synchronized (mStats) {
302             mStats.removeUidStatsLocked(uid);
303         }
304     }
305 
onCleanupUser(int userId)306     void onCleanupUser(int userId) {
307         synchronized (mStats) {
308             mStats.onCleanupUserLocked(userId);
309         }
310     }
311 
onUserRemoved(int userId)312     void onUserRemoved(int userId) {
313         synchronized (mStats) {
314             mStats.onUserRemovedLocked(userId);
315         }
316     }
317 
addIsolatedUid(int isolatedUid, int appUid)318     void addIsolatedUid(int isolatedUid, int appUid) {
319         synchronized (mStats) {
320             mStats.addIsolatedUidLocked(isolatedUid, appUid);
321         }
322     }
323 
removeIsolatedUid(int isolatedUid, int appUid)324     void removeIsolatedUid(int isolatedUid, int appUid) {
325         synchronized (mStats) {
326             mStats.scheduleRemoveIsolatedUidLocked(isolatedUid, appUid);
327         }
328     }
329 
noteProcessStart(String name, int uid)330     void noteProcessStart(String name, int uid) {
331         synchronized (mStats) {
332             mStats.noteProcessStartLocked(name, uid);
333             StatsLog.write(StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
334                     StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__STARTED);
335         }
336     }
337 
noteProcessCrash(String name, int uid)338     void noteProcessCrash(String name, int uid) {
339         synchronized (mStats) {
340             mStats.noteProcessCrashLocked(name, uid);
341             StatsLog.write(StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
342                     StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__CRASHED);
343         }
344     }
345 
noteProcessAnr(String name, int uid)346     void noteProcessAnr(String name, int uid) {
347         synchronized (mStats) {
348             mStats.noteProcessAnrLocked(name, uid);
349         }
350     }
351 
noteProcessFinish(String name, int uid)352     void noteProcessFinish(String name, int uid) {
353         synchronized (mStats) {
354             mStats.noteProcessFinishLocked(name, uid);
355             StatsLog.write(StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED, uid, name,
356                     StatsLog.PROCESS_LIFE_CYCLE_STATE_CHANGED__STATE__FINISHED);
357         }
358     }
359 
360     /** @param state Process state from ActivityManager.java. */
noteUidProcessState(int uid, int state)361     void noteUidProcessState(int uid, int state) {
362         synchronized (mStats) {
363             StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid,
364                     ActivityManager.processStateAmToProto(state));
365 
366             mStats.noteUidProcessStateLocked(uid, state);
367         }
368     }
369 
370     // Public interface...
371 
getStatistics()372     public byte[] getStatistics() {
373         mContext.enforceCallingPermission(
374                 android.Manifest.permission.BATTERY_STATS, null);
375         //Slog.i("foo", "SENDING BATTERY INFO:");
376         //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
377         Parcel out = Parcel.obtain();
378         syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL);
379         synchronized (mStats) {
380             mStats.writeToParcel(out, 0);
381         }
382         byte[] data = out.marshall();
383         out.recycle();
384         return data;
385     }
386 
getStatisticsStream()387     public ParcelFileDescriptor getStatisticsStream() {
388         mContext.enforceCallingPermission(
389                 android.Manifest.permission.BATTERY_STATS, null);
390         //Slog.i("foo", "SENDING BATTERY INFO:");
391         //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
392         Parcel out = Parcel.obtain();
393         syncStats("get-stats", BatteryExternalStatsWorker.UPDATE_ALL);
394         synchronized (mStats) {
395             mStats.writeToParcel(out, 0);
396         }
397         byte[] data = out.marshall();
398         out.recycle();
399         try {
400             return ParcelFileDescriptor.fromData(data, "battery-stats");
401         } catch (IOException e) {
402             Slog.w(TAG, "Unable to create shared memory", e);
403             return null;
404         }
405     }
406 
isCharging()407     public boolean isCharging() {
408         synchronized (mStats) {
409             return mStats.isCharging();
410         }
411     }
412 
computeBatteryTimeRemaining()413     public long computeBatteryTimeRemaining() {
414         synchronized (mStats) {
415             long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
416             return time >= 0 ? (time/1000) : time;
417         }
418     }
419 
computeChargeTimeRemaining()420     public long computeChargeTimeRemaining() {
421         synchronized (mStats) {
422             long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
423             return time >= 0 ? (time/1000) : time;
424         }
425     }
426 
noteEvent(int code, String name, int uid)427     public void noteEvent(int code, String name, int uid) {
428         enforceCallingPermission();
429         synchronized (mStats) {
430             mStats.noteEventLocked(code, name, uid);
431         }
432     }
433 
noteSyncStart(String name, int uid)434     public void noteSyncStart(String name, int uid) {
435         enforceCallingPermission();
436         synchronized (mStats) {
437             mStats.noteSyncStartLocked(name, uid);
438             StatsLog.write_non_chained(StatsLog.SYNC_STATE_CHANGED, uid, null, name,
439                     StatsLog.SYNC_STATE_CHANGED__STATE__ON);
440         }
441     }
442 
noteSyncFinish(String name, int uid)443     public void noteSyncFinish(String name, int uid) {
444         enforceCallingPermission();
445         synchronized (mStats) {
446             mStats.noteSyncFinishLocked(name, uid);
447             StatsLog.write_non_chained(StatsLog.SYNC_STATE_CHANGED, uid, null, name,
448                     StatsLog.SYNC_STATE_CHANGED__STATE__OFF);
449         }
450     }
451 
noteJobStart(String name, int uid)452     public void noteJobStart(String name, int uid) {
453         enforceCallingPermission();
454         synchronized (mStats) {
455             mStats.noteJobStartLocked(name, uid);
456             StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED, uid, null,
457                     name, StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__STARTED,
458                     JobProtoEnums.STOP_REASON_UNKNOWN);
459         }
460     }
461 
noteJobFinish(String name, int uid, int stopReason)462     public void noteJobFinish(String name, int uid, int stopReason) {
463         enforceCallingPermission();
464         synchronized (mStats) {
465             mStats.noteJobFinishLocked(name, uid, stopReason);
466             StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED, uid, null,
467                     name, StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__FINISHED,
468                     stopReason);
469         }
470     }
471 
noteJobsDeferred(int uid, int numDeferred, long sinceLast)472     void noteJobsDeferred(int uid, int numDeferred, long sinceLast) {
473         // No need to enforce calling permission, as it is called from an internal interface
474         synchronized (mStats) {
475             mStats.noteJobsDeferredLocked(uid, numDeferred, sinceLast);
476         }
477     }
478 
noteWakupAlarm(String name, int uid, WorkSource workSource, String tag)479     public void noteWakupAlarm(String name, int uid, WorkSource workSource, String tag) {
480         enforceCallingPermission();
481         synchronized (mStats) {
482             mStats.noteWakupAlarmLocked(name, uid, workSource, tag);
483         }
484     }
485 
noteAlarmStart(String name, WorkSource workSource, int uid)486     public void noteAlarmStart(String name, WorkSource workSource, int uid) {
487         enforceCallingPermission();
488         synchronized (mStats) {
489             mStats.noteAlarmStartLocked(name, workSource, uid);
490         }
491     }
492 
noteAlarmFinish(String name, WorkSource workSource, int uid)493     public void noteAlarmFinish(String name, WorkSource workSource, int uid) {
494         enforceCallingPermission();
495         synchronized (mStats) {
496             mStats.noteAlarmFinishLocked(name, workSource, uid);
497         }
498     }
499 
noteStartWakelock(int uid, int pid, String name, String historyName, int type, boolean unimportantForLogging)500     public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
501             boolean unimportantForLogging) {
502         enforceCallingPermission();
503         synchronized (mStats) {
504             mStats.noteStartWakeLocked(uid, pid, null, name, historyName, type,
505                     unimportantForLogging, SystemClock.elapsedRealtime(),
506                     SystemClock.uptimeMillis());
507         }
508     }
509 
noteStopWakelock(int uid, int pid, String name, String historyName, int type)510     public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) {
511         enforceCallingPermission();
512         synchronized (mStats) {
513             mStats.noteStopWakeLocked(uid, pid, null, name, historyName, type,
514                     SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
515         }
516     }
517 
noteStartWakelockFromSource(WorkSource ws, int pid, String name, String historyName, int type, boolean unimportantForLogging)518     public void noteStartWakelockFromSource(WorkSource ws, int pid, String name,
519             String historyName, int type, boolean unimportantForLogging) {
520         enforceCallingPermission();
521         synchronized (mStats) {
522             mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
523                     type, unimportantForLogging);
524         }
525     }
526 
noteChangeWakelockFromSource(WorkSource ws, int pid, String name, String historyName, int type, WorkSource newWs, int newPid, String newName, String newHistoryName, int newType, boolean newUnimportantForLogging)527     public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name,
528             String historyName, int type, WorkSource newWs, int newPid, String newName,
529             String newHistoryName, int newType, boolean newUnimportantForLogging) {
530         enforceCallingPermission();
531         synchronized (mStats) {
532             mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
533                     newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
534         }
535     }
536 
noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName, int type)537     public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName,
538             int type) {
539         enforceCallingPermission();
540         synchronized (mStats) {
541             mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type);
542         }
543     }
544 
545     @Override
noteLongPartialWakelockStart(String name, String historyName, int uid)546     public void noteLongPartialWakelockStart(String name, String historyName, int uid) {
547         enforceCallingPermission();
548         synchronized (mStats) {
549             mStats.noteLongPartialWakelockStart(name, historyName, uid);
550         }
551     }
552 
553     @Override
noteLongPartialWakelockStartFromSource(String name, String historyName, WorkSource workSource)554     public void noteLongPartialWakelockStartFromSource(String name, String historyName,
555             WorkSource workSource) {
556         enforceCallingPermission();
557         synchronized (mStats) {
558             mStats.noteLongPartialWakelockStartFromSource(name, historyName, workSource);
559         }
560     }
561 
562     @Override
noteLongPartialWakelockFinish(String name, String historyName, int uid)563     public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
564         enforceCallingPermission();
565         synchronized (mStats) {
566             mStats.noteLongPartialWakelockFinish(name, historyName, uid);
567         }
568     }
569 
570     @Override
noteLongPartialWakelockFinishFromSource(String name, String historyName, WorkSource workSource)571     public void noteLongPartialWakelockFinishFromSource(String name, String historyName,
572             WorkSource workSource) {
573         enforceCallingPermission();
574         synchronized (mStats) {
575             mStats.noteLongPartialWakelockFinishFromSource(name, historyName, workSource);
576         }
577     }
578 
noteStartSensor(int uid, int sensor)579     public void noteStartSensor(int uid, int sensor) {
580         enforceCallingPermission();
581         synchronized (mStats) {
582             mStats.noteStartSensorLocked(uid, sensor);
583             StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, uid, null, sensor,
584                     StatsLog.SENSOR_STATE_CHANGED__STATE__ON);
585         }
586     }
587 
noteStopSensor(int uid, int sensor)588     public void noteStopSensor(int uid, int sensor) {
589         enforceCallingPermission();
590         synchronized (mStats) {
591             mStats.noteStopSensorLocked(uid, sensor);
592             StatsLog.write_non_chained(StatsLog.SENSOR_STATE_CHANGED, uid, null,
593                     sensor, StatsLog.SENSOR_STATE_CHANGED__STATE__OFF);
594         }
595     }
596 
noteVibratorOn(int uid, long durationMillis)597     public void noteVibratorOn(int uid, long durationMillis) {
598         enforceCallingPermission();
599         synchronized (mStats) {
600             mStats.noteVibratorOnLocked(uid, durationMillis);
601         }
602     }
603 
noteVibratorOff(int uid)604     public void noteVibratorOff(int uid) {
605         enforceCallingPermission();
606         synchronized (mStats) {
607             mStats.noteVibratorOffLocked(uid);
608         }
609     }
610 
611     @Override
noteGpsChanged(WorkSource oldWs, WorkSource newWs)612     public void noteGpsChanged(WorkSource oldWs, WorkSource newWs) {
613         enforceCallingPermission();
614         synchronized (mStats) {
615             mStats.noteGpsChangedLocked(oldWs, newWs);
616         }
617     }
618 
noteGpsSignalQuality(int signalLevel)619     public void noteGpsSignalQuality(int signalLevel) {
620         synchronized (mStats) {
621             mStats.noteGpsSignalQualityLocked(signalLevel);
622         }
623     }
624 
noteScreenState(int state)625     public void noteScreenState(int state) {
626         enforceCallingPermission();
627         if (DBG) Slog.d(TAG, "begin noteScreenState");
628         synchronized (mStats) {
629             StatsLog.write(StatsLog.SCREEN_STATE_CHANGED, state);
630 
631             mStats.noteScreenStateLocked(state);
632         }
633         if (DBG) Slog.d(TAG, "end noteScreenState");
634     }
635 
noteScreenBrightness(int brightness)636     public void noteScreenBrightness(int brightness) {
637         enforceCallingPermission();
638         synchronized (mStats) {
639             StatsLog.write(StatsLog.SCREEN_BRIGHTNESS_CHANGED, brightness);
640             mStats.noteScreenBrightnessLocked(brightness);
641         }
642     }
643 
noteUserActivity(int uid, int event)644     public void noteUserActivity(int uid, int event) {
645         enforceCallingPermission();
646         synchronized (mStats) {
647             mStats.noteUserActivityLocked(uid, event);
648         }
649     }
650 
noteWakeUp(String reason, int reasonUid)651     public void noteWakeUp(String reason, int reasonUid) {
652         enforceCallingPermission();
653         synchronized (mStats) {
654             mStats.noteWakeUpLocked(reason, reasonUid);
655         }
656     }
657 
noteInteractive(boolean interactive)658     public void noteInteractive(boolean interactive) {
659         enforceCallingPermission();
660         synchronized (mStats) {
661             mStats.noteInteractiveLocked(interactive);
662         }
663     }
664 
noteConnectivityChanged(int type, String extra)665     public void noteConnectivityChanged(int type, String extra) {
666         enforceCallingPermission();
667         synchronized (mStats) {
668             mStats.noteConnectivityChangedLocked(type, extra);
669         }
670     }
671 
noteMobileRadioPowerState(int powerState, long timestampNs, int uid)672     public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
673         enforceCallingPermission();
674         final boolean update;
675         synchronized (mStats) {
676             update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid);
677         }
678 
679         if (update) {
680             mWorker.scheduleSync("modem-data", BatteryExternalStatsWorker.UPDATE_RADIO);
681         }
682     }
683 
notePhoneOn()684     public void notePhoneOn() {
685         enforceCallingPermission();
686         synchronized (mStats) {
687             mStats.notePhoneOnLocked();
688         }
689     }
690 
notePhoneOff()691     public void notePhoneOff() {
692         enforceCallingPermission();
693         synchronized (mStats) {
694             mStats.notePhoneOffLocked();
695         }
696     }
697 
notePhoneSignalStrength(SignalStrength signalStrength)698     public void notePhoneSignalStrength(SignalStrength signalStrength) {
699         enforceCallingPermission();
700         synchronized (mStats) {
701             mStats.notePhoneSignalStrengthLocked(signalStrength);
702         }
703     }
704 
notePhoneDataConnectionState(int dataType, boolean hasData)705     public void notePhoneDataConnectionState(int dataType, boolean hasData) {
706         enforceCallingPermission();
707         synchronized (mStats) {
708             mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
709         }
710     }
711 
notePhoneState(int state)712     public void notePhoneState(int state) {
713         enforceCallingPermission();
714         int simState = TelephonyManager.getDefault().getSimState();
715         synchronized (mStats) {
716             mStats.notePhoneStateLocked(state, simState);
717         }
718     }
719 
noteWifiOn()720     public void noteWifiOn() {
721         enforceCallingPermission();
722         synchronized (mStats) {
723             mStats.noteWifiOnLocked();
724         }
725     }
726 
noteWifiOff()727     public void noteWifiOff() {
728         enforceCallingPermission();
729         synchronized (mStats) {
730             mStats.noteWifiOffLocked();
731         }
732     }
733 
noteStartAudio(int uid)734     public void noteStartAudio(int uid) {
735         enforceCallingPermission();
736         synchronized (mStats) {
737             mStats.noteAudioOnLocked(uid);
738             StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null,
739                     StatsLog.AUDIO_STATE_CHANGED__STATE__ON);
740         }
741     }
742 
noteStopAudio(int uid)743     public void noteStopAudio(int uid) {
744         enforceCallingPermission();
745         synchronized (mStats) {
746             mStats.noteAudioOffLocked(uid);
747             StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null,
748                     StatsLog.AUDIO_STATE_CHANGED__STATE__OFF);
749         }
750     }
751 
noteStartVideo(int uid)752     public void noteStartVideo(int uid) {
753         enforceCallingPermission();
754         synchronized (mStats) {
755             mStats.noteVideoOnLocked(uid);
756             StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, null,
757                     StatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__ON);
758         }
759     }
760 
noteStopVideo(int uid)761     public void noteStopVideo(int uid) {
762         enforceCallingPermission();
763         synchronized (mStats) {
764             mStats.noteVideoOffLocked(uid);
765             StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid,
766                     null, StatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__OFF);
767         }
768     }
769 
noteResetAudio()770     public void noteResetAudio() {
771         enforceCallingPermission();
772         synchronized (mStats) {
773             mStats.noteResetAudioLocked();
774             StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, -1, null,
775                     StatsLog.AUDIO_STATE_CHANGED__STATE__RESET);
776         }
777     }
778 
noteResetVideo()779     public void noteResetVideo() {
780         enforceCallingPermission();
781         synchronized (mStats) {
782             mStats.noteResetVideoLocked();
783             StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, -1, null,
784                     StatsLog.MEDIA_CODEC_STATE_CHANGED__STATE__RESET);
785         }
786     }
787 
noteFlashlightOn(int uid)788     public void noteFlashlightOn(int uid) {
789         enforceCallingPermission();
790         synchronized (mStats) {
791             mStats.noteFlashlightOnLocked(uid);
792             StatsLog.write_non_chained(StatsLog.FLASHLIGHT_STATE_CHANGED, uid, null,
793                     StatsLog.FLASHLIGHT_STATE_CHANGED__STATE__ON);
794         }
795     }
796 
noteFlashlightOff(int uid)797     public void noteFlashlightOff(int uid) {
798         enforceCallingPermission();
799         synchronized (mStats) {
800             mStats.noteFlashlightOffLocked(uid);
801             StatsLog.write_non_chained(StatsLog.FLASHLIGHT_STATE_CHANGED, uid, null,
802                     StatsLog.FLASHLIGHT_STATE_CHANGED__STATE__OFF);
803         }
804     }
805 
noteStartCamera(int uid)806     public void noteStartCamera(int uid) {
807         enforceCallingPermission();
808         if (DBG) Slog.d(TAG, "begin noteStartCamera");
809         synchronized (mStats) {
810             mStats.noteCameraOnLocked(uid);
811             StatsLog.write_non_chained(StatsLog.CAMERA_STATE_CHANGED, uid, null,
812                     StatsLog.CAMERA_STATE_CHANGED__STATE__ON);
813         }
814         if (DBG) Slog.d(TAG, "end noteStartCamera");
815     }
816 
noteStopCamera(int uid)817     public void noteStopCamera(int uid) {
818         enforceCallingPermission();
819         synchronized (mStats) {
820             mStats.noteCameraOffLocked(uid);
821             StatsLog.write_non_chained(StatsLog.CAMERA_STATE_CHANGED, uid, null,
822                     StatsLog.CAMERA_STATE_CHANGED__STATE__OFF);
823         }
824     }
825 
noteResetCamera()826     public void noteResetCamera() {
827         enforceCallingPermission();
828         synchronized (mStats) {
829             mStats.noteResetCameraLocked();
830             StatsLog.write_non_chained(StatsLog.CAMERA_STATE_CHANGED, -1, null,
831                     StatsLog.CAMERA_STATE_CHANGED__STATE__RESET);
832         }
833     }
834 
noteResetFlashlight()835     public void noteResetFlashlight() {
836         enforceCallingPermission();
837         synchronized (mStats) {
838             mStats.noteResetFlashlightLocked();
839             StatsLog.write_non_chained(StatsLog.FLASHLIGHT_STATE_CHANGED, -1, null,
840                     StatsLog.FLASHLIGHT_STATE_CHANGED__STATE__RESET);
841         }
842     }
843 
844     @Override
noteWifiRadioPowerState(int powerState, long tsNanos, int uid)845     public void noteWifiRadioPowerState(int powerState, long tsNanos, int uid) {
846         enforceCallingPermission();
847 
848         // There was a change in WiFi power state.
849         // Collect data now for the past activity.
850         synchronized (mStats) {
851             if (mStats.isOnBattery()) {
852                 final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
853                         powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
854                         : "inactive";
855                 mWorker.scheduleSync("wifi-data: " + type, BatteryExternalStatsWorker.UPDATE_WIFI);
856             }
857             mStats.noteWifiRadioPowerState(powerState, tsNanos, uid);
858         }
859     }
860 
noteWifiRunning(WorkSource ws)861     public void noteWifiRunning(WorkSource ws) {
862         enforceCallingPermission();
863         synchronized (mStats) {
864             mStats.noteWifiRunningLocked(ws);
865         }
866     }
867 
noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs)868     public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
869         enforceCallingPermission();
870         synchronized (mStats) {
871             mStats.noteWifiRunningChangedLocked(oldWs, newWs);
872         }
873     }
874 
noteWifiStopped(WorkSource ws)875     public void noteWifiStopped(WorkSource ws) {
876         enforceCallingPermission();
877         synchronized (mStats) {
878             mStats.noteWifiStoppedLocked(ws);
879         }
880     }
881 
noteWifiState(int wifiState, String accessPoint)882     public void noteWifiState(int wifiState, String accessPoint) {
883         enforceCallingPermission();
884         synchronized (mStats) {
885             mStats.noteWifiStateLocked(wifiState, accessPoint);
886         }
887     }
888 
noteWifiSupplicantStateChanged(int supplState, boolean failedAuth)889     public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
890         enforceCallingPermission();
891         synchronized (mStats) {
892             mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
893         }
894     }
895 
noteWifiRssiChanged(int newRssi)896     public void noteWifiRssiChanged(int newRssi) {
897         enforceCallingPermission();
898         synchronized (mStats) {
899             mStats.noteWifiRssiChangedLocked(newRssi);
900         }
901     }
902 
noteFullWifiLockAcquired(int uid)903     public void noteFullWifiLockAcquired(int uid) {
904         enforceCallingPermission();
905         synchronized (mStats) {
906             mStats.noteFullWifiLockAcquiredLocked(uid);
907         }
908     }
909 
noteFullWifiLockReleased(int uid)910     public void noteFullWifiLockReleased(int uid) {
911         enforceCallingPermission();
912         synchronized (mStats) {
913             mStats.noteFullWifiLockReleasedLocked(uid);
914         }
915     }
916 
noteWifiScanStarted(int uid)917     public void noteWifiScanStarted(int uid) {
918         enforceCallingPermission();
919         synchronized (mStats) {
920             mStats.noteWifiScanStartedLocked(uid);
921         }
922     }
923 
noteWifiScanStopped(int uid)924     public void noteWifiScanStopped(int uid) {
925         enforceCallingPermission();
926         synchronized (mStats) {
927             mStats.noteWifiScanStoppedLocked(uid);
928         }
929     }
930 
noteWifiMulticastEnabled(int uid)931     public void noteWifiMulticastEnabled(int uid) {
932         enforceCallingPermission();
933         synchronized (mStats) {
934             mStats.noteWifiMulticastEnabledLocked(uid);
935         }
936     }
937 
noteWifiMulticastDisabled(int uid)938     public void noteWifiMulticastDisabled(int uid) {
939         enforceCallingPermission();
940         synchronized (mStats) {
941             mStats.noteWifiMulticastDisabledLocked(uid);
942         }
943     }
944 
noteFullWifiLockAcquiredFromSource(WorkSource ws)945     public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
946         enforceCallingPermission();
947         synchronized (mStats) {
948             mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
949         }
950     }
951 
noteFullWifiLockReleasedFromSource(WorkSource ws)952     public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
953         enforceCallingPermission();
954         synchronized (mStats) {
955             mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
956         }
957     }
958 
noteWifiScanStartedFromSource(WorkSource ws)959     public void noteWifiScanStartedFromSource(WorkSource ws) {
960         enforceCallingPermission();
961         synchronized (mStats) {
962             mStats.noteWifiScanStartedFromSourceLocked(ws);
963         }
964     }
965 
noteWifiScanStoppedFromSource(WorkSource ws)966     public void noteWifiScanStoppedFromSource(WorkSource ws) {
967         enforceCallingPermission();
968         synchronized (mStats) {
969             mStats.noteWifiScanStoppedFromSourceLocked(ws);
970         }
971     }
972 
noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph)973     public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
974         enforceCallingPermission();
975         synchronized (mStats) {
976             mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
977         }
978     }
979 
noteWifiBatchedScanStoppedFromSource(WorkSource ws)980     public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
981         enforceCallingPermission();
982         synchronized (mStats) {
983             mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
984         }
985     }
986 
987     @Override
noteNetworkInterfaceType(String iface, int networkType)988     public void noteNetworkInterfaceType(String iface, int networkType) {
989         enforceCallingPermission();
990         synchronized (mStats) {
991             mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
992         }
993     }
994 
995     @Override
noteNetworkStatsEnabled()996     public void noteNetworkStatsEnabled() {
997         enforceCallingPermission();
998         // During device boot, qtaguid isn't enabled until after the inital
999         // loading of battery stats. Now that they're enabled, take our initial
1000         // snapshot for future delta calculation.
1001         mWorker.scheduleSync("network-stats-enabled",
1002                 BatteryExternalStatsWorker.UPDATE_RADIO | BatteryExternalStatsWorker.UPDATE_WIFI);
1003     }
1004 
1005     @Override
noteDeviceIdleMode(int mode, String activeReason, int activeUid)1006     public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) {
1007         enforceCallingPermission();
1008         synchronized (mStats) {
1009             mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
1010         }
1011     }
1012 
notePackageInstalled(String pkgName, long versionCode)1013     public void notePackageInstalled(String pkgName, long versionCode) {
1014         enforceCallingPermission();
1015         synchronized (mStats) {
1016             mStats.notePackageInstalledLocked(pkgName, versionCode);
1017         }
1018     }
1019 
notePackageUninstalled(String pkgName)1020     public void notePackageUninstalled(String pkgName) {
1021         enforceCallingPermission();
1022         synchronized (mStats) {
1023             mStats.notePackageUninstalledLocked(pkgName);
1024         }
1025     }
1026 
1027     @Override
noteBleScanStarted(WorkSource ws, boolean isUnoptimized)1028     public void noteBleScanStarted(WorkSource ws, boolean isUnoptimized) {
1029         enforceCallingPermission();
1030         synchronized (mStats) {
1031             mStats.noteBluetoothScanStartedFromSourceLocked(ws, isUnoptimized);
1032         }
1033     }
1034 
1035     @Override
noteBleScanStopped(WorkSource ws, boolean isUnoptimized)1036     public void noteBleScanStopped(WorkSource ws, boolean isUnoptimized) {
1037         enforceCallingPermission();
1038         synchronized (mStats) {
1039             mStats.noteBluetoothScanStoppedFromSourceLocked(ws, isUnoptimized);
1040         }
1041     }
1042 
1043     @Override
noteResetBleScan()1044     public void noteResetBleScan() {
1045         enforceCallingPermission();
1046         synchronized (mStats) {
1047             mStats.noteResetBluetoothScanLocked();
1048         }
1049     }
1050 
1051     @Override
noteBleScanResults(WorkSource ws, int numNewResults)1052     public void noteBleScanResults(WorkSource ws, int numNewResults) {
1053         enforceCallingPermission();
1054         synchronized (mStats) {
1055             mStats.noteBluetoothScanResultsFromSourceLocked(ws, numNewResults);
1056         }
1057     }
1058 
1059     @Override
noteWifiControllerActivity(WifiActivityEnergyInfo info)1060     public void noteWifiControllerActivity(WifiActivityEnergyInfo info) {
1061         enforceCallingPermission();
1062 
1063         if (info == null || !info.isValid()) {
1064             Slog.e(TAG, "invalid wifi data given: " + info);
1065             return;
1066         }
1067 
1068         mStats.updateWifiState(info);
1069     }
1070 
1071     @Override
noteBluetoothControllerActivity(BluetoothActivityEnergyInfo info)1072     public void noteBluetoothControllerActivity(BluetoothActivityEnergyInfo info) {
1073         enforceCallingPermission();
1074         if (info == null || !info.isValid()) {
1075             Slog.e(TAG, "invalid bluetooth data given: " + info);
1076             return;
1077         }
1078 
1079         synchronized (mStats) {
1080             mStats.updateBluetoothStateLocked(info);
1081         }
1082     }
1083 
1084     @Override
noteModemControllerActivity(ModemActivityInfo info)1085     public void noteModemControllerActivity(ModemActivityInfo info) {
1086         enforceCallingPermission();
1087 
1088         if (info == null || !info.isValid()) {
1089             Slog.e(TAG, "invalid modem data given: " + info);
1090             return;
1091         }
1092 
1093         mStats.updateMobileRadioState(info);
1094     }
1095 
isOnBattery()1096     public boolean isOnBattery() {
1097         return mStats.isOnBattery();
1098     }
1099 
1100     @Override
setBatteryState(final int status, final int health, final int plugType, final int level, final int temp, final int volt, final int chargeUAh, final int chargeFullUAh)1101     public void setBatteryState(final int status, final int health, final int plugType,
1102             final int level, final int temp, final int volt, final int chargeUAh,
1103             final int chargeFullUAh) {
1104         enforceCallingPermission();
1105 
1106         // BatteryService calls us here and we may update external state. It would be wrong
1107         // to block such a low level service like BatteryService on external stats like WiFi.
1108         mWorker.scheduleRunnable(() -> {
1109             synchronized (mStats) {
1110                 final boolean onBattery = BatteryStatsImpl.isOnBattery(plugType, status);
1111                 if (mStats.isOnBattery() == onBattery) {
1112                     // The battery state has not changed, so we don't need to sync external
1113                     // stats immediately.
1114                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
1115                             chargeUAh, chargeFullUAh);
1116                     return;
1117                 }
1118             }
1119 
1120             // Sync external stats first as the battery has changed states. If we don't sync
1121             // before changing the state, we may not collect the relevant data later.
1122             // Order here is guaranteed since we're scheduling from the same thread and we are
1123             // using a single threaded executor.
1124             mWorker.scheduleSync("battery-state", BatteryExternalStatsWorker.UPDATE_ALL);
1125             mWorker.scheduleRunnable(() -> {
1126                 synchronized (mStats) {
1127                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
1128                             chargeUAh, chargeFullUAh);
1129                 }
1130             });
1131         });
1132     }
1133 
getAwakeTimeBattery()1134     public long getAwakeTimeBattery() {
1135         mContext.enforceCallingOrSelfPermission(
1136                 android.Manifest.permission.BATTERY_STATS, null);
1137         return mStats.getAwakeTimeBattery();
1138     }
1139 
getAwakeTimePlugged()1140     public long getAwakeTimePlugged() {
1141         mContext.enforceCallingOrSelfPermission(
1142                 android.Manifest.permission.BATTERY_STATS, null);
1143         return mStats.getAwakeTimePlugged();
1144     }
1145 
enforceCallingPermission()1146     public void enforceCallingPermission() {
1147         if (Binder.getCallingPid() == Process.myPid()) {
1148             return;
1149         }
1150         mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1151                 Binder.getCallingPid(), Binder.getCallingUid(), null);
1152     }
1153 
1154     final class WakeupReasonThread extends Thread {
1155         private static final int MAX_REASON_SIZE = 512;
1156         private CharsetDecoder mDecoder;
1157         private ByteBuffer mUtf8Buffer;
1158         private CharBuffer mUtf16Buffer;
1159 
WakeupReasonThread()1160         WakeupReasonThread() {
1161             super("BatteryStats_wakeupReason");
1162         }
1163 
run()1164         public void run() {
1165             Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
1166 
1167             mDecoder = StandardCharsets.UTF_8
1168                     .newDecoder()
1169                     .onMalformedInput(CodingErrorAction.REPLACE)
1170                     .onUnmappableCharacter(CodingErrorAction.REPLACE)
1171                     .replaceWith("?");
1172 
1173             mUtf8Buffer = ByteBuffer.allocateDirect(MAX_REASON_SIZE);
1174             mUtf16Buffer = CharBuffer.allocate(MAX_REASON_SIZE);
1175 
1176             try {
1177                 String reason;
1178                 while ((reason = waitWakeup()) != null) {
1179                     synchronized (mStats) {
1180                         mStats.noteWakeupReasonLocked(reason);
1181                     }
1182                 }
1183             } catch (RuntimeException e) {
1184                 Slog.e(TAG, "Failure reading wakeup reasons", e);
1185             }
1186         }
1187 
waitWakeup()1188         private String waitWakeup() {
1189             mUtf8Buffer.clear();
1190             mUtf16Buffer.clear();
1191             mDecoder.reset();
1192 
1193             int bytesWritten = nativeWaitWakeup(mUtf8Buffer);
1194             if (bytesWritten < 0) {
1195                 return null;
1196             } else if (bytesWritten == 0) {
1197                 return "unknown";
1198             }
1199 
1200             // Set the buffer's limit to the number of bytes written.
1201             mUtf8Buffer.limit(bytesWritten);
1202 
1203             // Decode the buffer from UTF-8 to UTF-16.
1204             // Unmappable characters will be replaced.
1205             mDecoder.decode(mUtf8Buffer, mUtf16Buffer, true);
1206             mUtf16Buffer.flip();
1207 
1208             // Create a String from the UTF-16 buffer.
1209             return mUtf16Buffer.toString();
1210         }
1211     }
1212 
nativeWaitWakeup(ByteBuffer outBuffer)1213     private static native int nativeWaitWakeup(ByteBuffer outBuffer);
1214 
dumpHelp(PrintWriter pw)1215     private void dumpHelp(PrintWriter pw) {
1216         pw.println("Battery stats (batterystats) dump options:");
1217         pw.println("  [--checkin] [--proto] [--history] [--history-start] [--charged] [-c]");
1218         pw.println("  [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
1219         pw.println("  --checkin: generate output for a checkin report; will write (and clear) the");
1220         pw.println("             last old completed stats when they had been reset.");
1221         pw.println("  -c: write the current stats in checkin format.");
1222         pw.println("  --proto: write the current aggregate stats (without history) in proto format.");
1223         pw.println("  --history: show only history data.");
1224         pw.println("  --history-start <num>: show only history data starting at given time offset.");
1225         pw.println("  --charged: only output data since last charged.");
1226         pw.println("  --daily: only output full daily data.");
1227         pw.println("  --reset: reset the stats, clearing all current data.");
1228         pw.println("  --write: force write current collected stats to disk.");
1229         pw.println("  --new-daily: immediately create and write new daily stats record.");
1230         pw.println("  --read-daily: read-load last written daily stats.");
1231         pw.println("  --settings: dump the settings key/values related to batterystats");
1232         pw.println("  --cpu: dump cpu stats for debugging purpose");
1233         pw.println("  <package.name>: optional name of package to filter output by.");
1234         pw.println("  -h: print this help text.");
1235         pw.println("Battery stats (batterystats) commands:");
1236         pw.println("  enable|disable <option>");
1237         pw.println("    Enable or disable a running option.  Option state is not saved across boots.");
1238         pw.println("    Options are:");
1239         pw.println("      full-history: include additional detailed events in battery history:");
1240         pw.println("          wake_lock_in, alarms and proc events");
1241         pw.println("      no-auto-reset: don't automatically reset stats when unplugged");
1242         pw.println("      pretend-screen-off: pretend the screen is off, even if screen state changes");
1243     }
1244 
dumpSettings(PrintWriter pw)1245     private void dumpSettings(PrintWriter pw) {
1246         synchronized (mStats) {
1247             mStats.dumpConstantsLocked(pw);
1248         }
1249     }
1250 
dumpCpuStats(PrintWriter pw)1251     private void dumpCpuStats(PrintWriter pw) {
1252         synchronized (mStats) {
1253             mStats.dumpCpuStatsLocked(pw);
1254         }
1255     }
1256 
doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable)1257     private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
1258         i++;
1259         if (i >= args.length) {
1260             pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
1261             dumpHelp(pw);
1262             return -1;
1263         }
1264         if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
1265             synchronized (mStats) {
1266                 mStats.setRecordAllHistoryLocked(enable);
1267             }
1268         } else if ("no-auto-reset".equals(args[i])) {
1269             synchronized (mStats) {
1270                 mStats.setNoAutoReset(enable);
1271             }
1272         } else if ("pretend-screen-off".equals(args[i])) {
1273             synchronized (mStats) {
1274                 mStats.setPretendScreenOff(enable);
1275             }
1276         } else {
1277             pw.println("Unknown enable/disable option: " + args[i]);
1278             dumpHelp(pw);
1279             return -1;
1280         }
1281         return i;
1282     }
1283 
1284 
1285     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1286     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1287         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
1288 
1289         int flags = 0;
1290         boolean useCheckinFormat = false;
1291         boolean toProto = false;
1292         boolean isRealCheckin = false;
1293         boolean noOutput = false;
1294         boolean writeData = false;
1295         long historyStart = -1;
1296         int reqUid = -1;
1297         if (args != null) {
1298             for (int i=0; i<args.length; i++) {
1299                 String arg = args[i];
1300                 if ("--checkin".equals(arg)) {
1301                     useCheckinFormat = true;
1302                     isRealCheckin = true;
1303                 } else if ("--history".equals(arg)) {
1304                     flags |= BatteryStats.DUMP_HISTORY_ONLY;
1305                 } else if ("--history-start".equals(arg)) {
1306                     flags |= BatteryStats.DUMP_HISTORY_ONLY;
1307                     i++;
1308                     if (i >= args.length) {
1309                         pw.println("Missing time argument for --history-since");
1310                         dumpHelp(pw);
1311                         return;
1312                     }
1313                     historyStart = Long.parseLong(args[i]);
1314                     writeData = true;
1315                 } else if ("-c".equals(arg)) {
1316                     useCheckinFormat = true;
1317                     flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
1318                 } else if ("--proto".equals(arg)) {
1319                     toProto = true;
1320                 } else if ("--charged".equals(arg)) {
1321                     flags |= BatteryStats.DUMP_CHARGED_ONLY;
1322                 } else if ("--daily".equals(arg)) {
1323                     flags |= BatteryStats.DUMP_DAILY_ONLY;
1324                 } else if ("--reset".equals(arg)) {
1325                     synchronized (mStats) {
1326                         mStats.resetAllStatsCmdLocked();
1327                         pw.println("Battery stats reset.");
1328                         noOutput = true;
1329                     }
1330                     mWorker.scheduleSync("dump", BatteryExternalStatsWorker.UPDATE_ALL);
1331                 } else if ("--write".equals(arg)) {
1332                     syncStats("dump", BatteryExternalStatsWorker.UPDATE_ALL);
1333                     synchronized (mStats) {
1334                         mStats.writeSyncLocked();
1335                         pw.println("Battery stats written.");
1336                         noOutput = true;
1337                     }
1338                 } else if ("--new-daily".equals(arg)) {
1339                     synchronized (mStats) {
1340                         mStats.recordDailyStatsLocked();
1341                         pw.println("New daily stats written.");
1342                         noOutput = true;
1343                     }
1344                 } else if ("--read-daily".equals(arg)) {
1345                     synchronized (mStats) {
1346                         mStats.readDailyStatsLocked();
1347                         pw.println("Last daily stats read.");
1348                         noOutput = true;
1349                     }
1350                 } else if ("--enable".equals(arg) || "enable".equals(arg)) {
1351                     i = doEnableOrDisable(pw, i, args, true);
1352                     if (i < 0) {
1353                         return;
1354                     }
1355                     pw.println("Enabled: " + args[i]);
1356                     return;
1357                 } else if ("--disable".equals(arg) || "disable".equals(arg)) {
1358                     i = doEnableOrDisable(pw, i, args, false);
1359                     if (i < 0) {
1360                         return;
1361                     }
1362                     pw.println("Disabled: " + args[i]);
1363                     return;
1364                 } else if ("-h".equals(arg)) {
1365                     dumpHelp(pw);
1366                     return;
1367                 } else if ("--settings".equals(arg)) {
1368                     dumpSettings(pw);
1369                     return;
1370                 } else if ("--cpu".equals(arg)) {
1371                     dumpCpuStats(pw);
1372                     return;
1373                 } else if ("-a".equals(arg)) {
1374                     flags |= BatteryStats.DUMP_VERBOSE;
1375                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
1376                     pw.println("Unknown option: " + arg);
1377                     dumpHelp(pw);
1378                     return;
1379                 } else {
1380                     // Not an option, last argument must be a package name.
1381                     try {
1382                         reqUid = mContext.getPackageManager().getPackageUidAsUser(arg,
1383                                 UserHandle.getCallingUserId());
1384                     } catch (PackageManager.NameNotFoundException e) {
1385                         pw.println("Unknown package: " + arg);
1386                         dumpHelp(pw);
1387                         return;
1388                     }
1389                 }
1390             }
1391         }
1392         if (noOutput) {
1393             return;
1394         }
1395 
1396         long ident = Binder.clearCallingIdentity();
1397         try {
1398             if (BatteryStatsHelper.checkWifiOnly(mContext)) {
1399                 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
1400             }
1401             // Fetch data from external sources and update the BatteryStatsImpl object with them.
1402             syncStats("dump", BatteryExternalStatsWorker.UPDATE_ALL);
1403         } finally {
1404             Binder.restoreCallingIdentity(ident);
1405         }
1406 
1407         if (reqUid >= 0) {
1408             // By default, if the caller is only interested in a specific package, then
1409             // we only dump the aggregated data since charged.
1410             if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
1411                 flags |= BatteryStats.DUMP_CHARGED_ONLY;
1412                 // Also if they are doing -c, we don't want history.
1413                 flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
1414             }
1415         }
1416 
1417         if (toProto) {
1418             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
1419                     PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
1420             if (isRealCheckin) {
1421                 // For a real checkin, first we want to prefer to use the last complete checkin
1422                 // file if there is one.
1423                 synchronized (mStats.mCheckinFile) {
1424                     if (mStats.mCheckinFile.exists()) {
1425                         try {
1426                             byte[] raw = mStats.mCheckinFile.readFully();
1427                             if (raw != null) {
1428                                 Parcel in = Parcel.obtain();
1429                                 in.unmarshall(raw, 0, raw.length);
1430                                 in.setDataPosition(0);
1431                                 BatteryStatsImpl checkinStats = new BatteryStatsImpl(
1432                                         null, mStats.mHandler, null, mUserManagerUserInfoProvider);
1433                                 checkinStats.readSummaryFromParcel(in);
1434                                 in.recycle();
1435                                 checkinStats.dumpProtoLocked(
1436                                         mContext, fd, apps, flags, historyStart);
1437                                 mStats.mCheckinFile.delete();
1438                                 return;
1439                             }
1440                         } catch (IOException | ParcelFormatException e) {
1441                             Slog.w(TAG, "Failure reading checkin file "
1442                                     + mStats.mCheckinFile.getBaseFile(), e);
1443                         }
1444                     }
1445                 }
1446             }
1447             if (DBG) Slog.d(TAG, "begin dumpProtoLocked from UID " + Binder.getCallingUid());
1448             synchronized (mStats) {
1449                 mStats.dumpProtoLocked(mContext, fd, apps, flags, historyStart);
1450                 if (writeData) {
1451                     mStats.writeAsyncLocked();
1452                 }
1453             }
1454             if (DBG) Slog.d(TAG, "end dumpProtoLocked");
1455         } else if (useCheckinFormat) {
1456             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
1457                     PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
1458             if (isRealCheckin) {
1459                 // For a real checkin, first we want to prefer to use the last complete checkin
1460                 // file if there is one.
1461                 synchronized (mStats.mCheckinFile) {
1462                     if (mStats.mCheckinFile.exists()) {
1463                         try {
1464                             byte[] raw = mStats.mCheckinFile.readFully();
1465                             if (raw != null) {
1466                                 Parcel in = Parcel.obtain();
1467                                 in.unmarshall(raw, 0, raw.length);
1468                                 in.setDataPosition(0);
1469                                 BatteryStatsImpl checkinStats = new BatteryStatsImpl(
1470                                         null, mStats.mHandler, null, mUserManagerUserInfoProvider);
1471                                 checkinStats.readSummaryFromParcel(in);
1472                                 in.recycle();
1473                                 checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
1474                                         historyStart);
1475                                 mStats.mCheckinFile.delete();
1476                                 return;
1477                             }
1478                         } catch (IOException | ParcelFormatException e) {
1479                             Slog.w(TAG, "Failure reading checkin file "
1480                                     + mStats.mCheckinFile.getBaseFile(), e);
1481                         }
1482                     }
1483                 }
1484             }
1485             if (DBG) Slog.d(TAG, "begin dumpCheckinLocked from UID " + Binder.getCallingUid());
1486             synchronized (mStats) {
1487                 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
1488                 if (writeData) {
1489                     mStats.writeAsyncLocked();
1490                 }
1491             }
1492             if (DBG) Slog.d(TAG, "end dumpCheckinLocked");
1493         } else {
1494             if (DBG) Slog.d(TAG, "begin dumpLocked from UID " + Binder.getCallingUid());
1495             synchronized (mStats) {
1496                 mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
1497                 if (writeData) {
1498                     mStats.writeAsyncLocked();
1499                 }
1500             }
1501             if (DBG) Slog.d(TAG, "end dumpLocked");
1502         }
1503     }
1504 
1505     /**
1506      * Gets a snapshot of cellular stats
1507      * @hide
1508      */
getCellularBatteryStats()1509     public CellularBatteryStats getCellularBatteryStats() {
1510         synchronized (mStats) {
1511             return mStats.getCellularBatteryStats();
1512         }
1513     }
1514 
1515     /**
1516      * Gets a snapshot of Wifi stats
1517      * @hide
1518      */
getWifiBatteryStats()1519     public WifiBatteryStats getWifiBatteryStats() {
1520         synchronized (mStats) {
1521             return mStats.getWifiBatteryStats();
1522         }
1523     }
1524 
1525     /**
1526      * Gets a snapshot of Gps stats
1527      * @hide
1528      */
getGpsBatteryStats()1529     public GpsBatteryStats getGpsBatteryStats() {
1530         synchronized (mStats) {
1531             return mStats.getGpsBatteryStats();
1532         }
1533     }
1534 
1535     /**
1536      * Gets a snapshot of the system health for a particular uid.
1537      */
1538     @Override
takeUidSnapshot(int requestUid)1539     public HealthStatsParceler takeUidSnapshot(int requestUid) {
1540         if (requestUid != Binder.getCallingUid()) {
1541             mContext.enforceCallingOrSelfPermission(
1542                     android.Manifest.permission.BATTERY_STATS, null);
1543         }
1544         long ident = Binder.clearCallingIdentity();
1545         try {
1546             if (shouldCollectExternalStats()) {
1547                 syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL);
1548             }
1549             synchronized (mStats) {
1550                 return getHealthStatsForUidLocked(requestUid);
1551             }
1552         } catch (Exception ex) {
1553             Slog.w(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex);
1554             throw ex;
1555         } finally {
1556             Binder.restoreCallingIdentity(ident);
1557         }
1558     }
1559 
1560     /**
1561      * Gets a snapshot of the system health for a number of uids.
1562      */
1563     @Override
takeUidSnapshots(int[] requestUids)1564     public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) {
1565         if (!onlyCaller(requestUids)) {
1566             mContext.enforceCallingOrSelfPermission(
1567                     android.Manifest.permission.BATTERY_STATS, null);
1568         }
1569         long ident = Binder.clearCallingIdentity();
1570         int i=-1;
1571         try {
1572             if (shouldCollectExternalStats()) {
1573                 syncStats("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL);
1574             }
1575             synchronized (mStats) {
1576                 final int N = requestUids.length;
1577                 final HealthStatsParceler[] results = new HealthStatsParceler[N];
1578                 for (i=0; i<N; i++) {
1579                     results[i] = getHealthStatsForUidLocked(requestUids[i]);
1580                 }
1581                 return results;
1582             }
1583         } catch (Exception ex) {
1584             if (DBG) Slog.d(TAG, "Crashed while writing for takeUidSnapshots("
1585                     + Arrays.toString(requestUids) + ") i=" + i, ex);
1586             throw ex;
1587         } finally {
1588             Binder.restoreCallingIdentity(ident);
1589         }
1590     }
1591 
shouldCollectExternalStats()1592     private boolean shouldCollectExternalStats() {
1593         return (SystemClock.elapsedRealtime() - mWorker.getLastCollectionTimeStamp())
1594                 > mStats.getExternalStatsCollectionRateLimitMs();
1595     }
1596 
1597     /**
1598      * Returns whether the Binder.getCallingUid is the only thing in requestUids.
1599      */
onlyCaller(int[] requestUids)1600     private static boolean onlyCaller(int[] requestUids) {
1601         final int caller = Binder.getCallingUid();
1602         final int N = requestUids.length;
1603         for (int i=0; i<N; i++) {
1604             if (requestUids[i] != caller) {
1605                 return false;
1606             }
1607         }
1608         return true;
1609     }
1610 
1611     /**
1612      * Gets a HealthStatsParceler for the given uid. You should probably call
1613      * updateExternalStatsSync first.
1614      */
getHealthStatsForUidLocked(int requestUid)1615     HealthStatsParceler getHealthStatsForUidLocked(int requestUid) {
1616         final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter();
1617         final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS);
1618         final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid);
1619         if (uid != null) {
1620             writer.writeUid(uidWriter, mStats, uid);
1621         }
1622         return new HealthStatsParceler(uidWriter);
1623     }
1624 
1625 }
1626