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