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