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 noteStartSensor(int uid, int sensor) {
    488         enforceCallingPermission();
    489         synchronized (mStats) {
    490             mStats.noteStartSensorLocked(uid, sensor);
    491         }
    492     }
    493 
    494     public void noteStopSensor(int uid, int sensor) {
    495         enforceCallingPermission();
    496         synchronized (mStats) {
    497             mStats.noteStopSensorLocked(uid, sensor);
    498         }
    499     }
    500 
    501     public void noteVibratorOn(int uid, long durationMillis) {
    502         enforceCallingPermission();
    503         synchronized (mStats) {
    504             mStats.noteVibratorOnLocked(uid, durationMillis);
    505         }
    506     }
    507 
    508     public void noteVibratorOff(int uid) {
    509         enforceCallingPermission();
    510         synchronized (mStats) {
    511             mStats.noteVibratorOffLocked(uid);
    512         }
    513     }
    514 
    515     public void noteStartGps(int uid) {
    516         enforceCallingPermission();
    517         synchronized (mStats) {
    518             mStats.noteStartGpsLocked(uid);
    519         }
    520     }
    521 
    522     public void noteStopGps(int uid) {
    523         enforceCallingPermission();
    524         synchronized (mStats) {
    525             mStats.noteStopGpsLocked(uid);
    526         }
    527     }
    528 
    529     public void noteScreenState(int state) {
    530         enforceCallingPermission();
    531         synchronized (mStats) {
    532             mStats.noteScreenStateLocked(state);
    533         }
    534     }
    535 
    536     public void noteScreenBrightness(int brightness) {
    537         enforceCallingPermission();
    538         synchronized (mStats) {
    539             mStats.noteScreenBrightnessLocked(brightness);
    540         }
    541     }
    542 
    543     public void noteUserActivity(int uid, int event) {
    544         enforceCallingPermission();
    545         synchronized (mStats) {
    546             mStats.noteUserActivityLocked(uid, event);
    547         }
    548     }
    549 
    550     public void noteWakeUp(String reason, int reasonUid) {
    551         enforceCallingPermission();
    552         synchronized (mStats) {
    553             mStats.noteWakeUpLocked(reason, reasonUid);
    554         }
    555     }
    556 
    557     public void noteInteractive(boolean interactive) {
    558         enforceCallingPermission();
    559         synchronized (mStats) {
    560             mStats.noteInteractiveLocked(interactive);
    561         }
    562     }
    563 
    564     public void noteConnectivityChanged(int type, String extra) {
    565         enforceCallingPermission();
    566         synchronized (mStats) {
    567             mStats.noteConnectivityChangedLocked(type, extra);
    568         }
    569     }
    570 
    571     public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) {
    572         enforceCallingPermission();
    573         synchronized (mStats) {
    574             mStats.noteMobileRadioPowerState(powerState, timestampNs, uid);
    575         }
    576     }
    577 
    578     public void notePhoneOn() {
    579         enforceCallingPermission();
    580         synchronized (mStats) {
    581             mStats.notePhoneOnLocked();
    582         }
    583     }
    584 
    585     public void notePhoneOff() {
    586         enforceCallingPermission();
    587         synchronized (mStats) {
    588             mStats.notePhoneOffLocked();
    589         }
    590     }
    591 
    592     public void notePhoneSignalStrength(SignalStrength signalStrength) {
    593         enforceCallingPermission();
    594         synchronized (mStats) {
    595             mStats.notePhoneSignalStrengthLocked(signalStrength);
    596         }
    597     }
    598 
    599     public void notePhoneDataConnectionState(int dataType, boolean hasData) {
    600         enforceCallingPermission();
    601         synchronized (mStats) {
    602             mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
    603         }
    604     }
    605 
    606     public void notePhoneState(int state) {
    607         enforceCallingPermission();
    608         int simState = TelephonyManager.getDefault().getSimState();
    609         synchronized (mStats) {
    610             mStats.notePhoneStateLocked(state, simState);
    611         }
    612     }
    613 
    614     public void noteWifiOn() {
    615         enforceCallingPermission();
    616         synchronized (mStats) {
    617             mStats.noteWifiOnLocked();
    618         }
    619     }
    620 
    621     public void noteWifiOff() {
    622         enforceCallingPermission();
    623         synchronized (mStats) {
    624             mStats.noteWifiOffLocked();
    625         }
    626     }
    627 
    628     public void noteStartAudio(int uid) {
    629         enforceCallingPermission();
    630         synchronized (mStats) {
    631             mStats.noteAudioOnLocked(uid);
    632         }
    633     }
    634 
    635     public void noteStopAudio(int uid) {
    636         enforceCallingPermission();
    637         synchronized (mStats) {
    638             mStats.noteAudioOffLocked(uid);
    639         }
    640     }
    641 
    642     public void noteStartVideo(int uid) {
    643         enforceCallingPermission();
    644         synchronized (mStats) {
    645             mStats.noteVideoOnLocked(uid);
    646         }
    647     }
    648 
    649     public void noteStopVideo(int uid) {
    650         enforceCallingPermission();
    651         synchronized (mStats) {
    652             mStats.noteVideoOffLocked(uid);
    653         }
    654     }
    655 
    656     public void noteResetAudio() {
    657         enforceCallingPermission();
    658         synchronized (mStats) {
    659             mStats.noteResetAudioLocked();
    660         }
    661     }
    662 
    663     public void noteResetVideo() {
    664         enforceCallingPermission();
    665         synchronized (mStats) {
    666             mStats.noteResetVideoLocked();
    667         }
    668     }
    669 
    670     public void noteFlashlightOn(int uid) {
    671         enforceCallingPermission();
    672         synchronized (mStats) {
    673             mStats.noteFlashlightOnLocked(uid);
    674         }
    675     }
    676 
    677     public void noteFlashlightOff(int uid) {
    678         enforceCallingPermission();
    679         synchronized (mStats) {
    680             mStats.noteFlashlightOffLocked(uid);
    681         }
    682     }
    683 
    684     public void noteStartCamera(int uid) {
    685         enforceCallingPermission();
    686         synchronized (mStats) {
    687             mStats.noteCameraOnLocked(uid);
    688         }
    689     }
    690 
    691     public void noteStopCamera(int uid) {
    692         enforceCallingPermission();
    693         synchronized (mStats) {
    694             mStats.noteCameraOffLocked(uid);
    695         }
    696     }
    697 
    698     public void noteResetCamera() {
    699         enforceCallingPermission();
    700         synchronized (mStats) {
    701             mStats.noteResetCameraLocked();
    702         }
    703     }
    704 
    705     public void noteResetFlashlight() {
    706         enforceCallingPermission();
    707         synchronized (mStats) {
    708             mStats.noteResetFlashlightLocked();
    709         }
    710     }
    711 
    712     @Override
    713     public void noteWifiRadioPowerState(int powerState, long tsNanos) {
    714         enforceCallingPermission();
    715 
    716         // There was a change in WiFi power state.
    717         // Collect data now for the past activity.
    718         synchronized (mStats) {
    719             if (mStats.isOnBattery()) {
    720                 final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH ||
    721                         powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active"
    722                         : "inactive";
    723                 mHandler.scheduleSync("wifi-data: " + type,
    724                         BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI);
    725             }
    726             mStats.noteWifiRadioPowerState(powerState, tsNanos);
    727         }
    728     }
    729 
    730     public void noteWifiRunning(WorkSource ws) {
    731         enforceCallingPermission();
    732         synchronized (mStats) {
    733             mStats.noteWifiRunningLocked(ws);
    734         }
    735     }
    736 
    737     public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
    738         enforceCallingPermission();
    739         synchronized (mStats) {
    740             mStats.noteWifiRunningChangedLocked(oldWs, newWs);
    741         }
    742     }
    743 
    744     public void noteWifiStopped(WorkSource ws) {
    745         enforceCallingPermission();
    746         synchronized (mStats) {
    747             mStats.noteWifiStoppedLocked(ws);
    748         }
    749     }
    750 
    751     public void noteWifiState(int wifiState, String accessPoint) {
    752         enforceCallingPermission();
    753         synchronized (mStats) {
    754             mStats.noteWifiStateLocked(wifiState, accessPoint);
    755         }
    756     }
    757 
    758     public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
    759         enforceCallingPermission();
    760         synchronized (mStats) {
    761             mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
    762         }
    763     }
    764 
    765     public void noteWifiRssiChanged(int newRssi) {
    766         enforceCallingPermission();
    767         synchronized (mStats) {
    768             mStats.noteWifiRssiChangedLocked(newRssi);
    769         }
    770     }
    771 
    772     public void noteFullWifiLockAcquired(int uid) {
    773         enforceCallingPermission();
    774         synchronized (mStats) {
    775             mStats.noteFullWifiLockAcquiredLocked(uid);
    776         }
    777     }
    778 
    779     public void noteFullWifiLockReleased(int uid) {
    780         enforceCallingPermission();
    781         synchronized (mStats) {
    782             mStats.noteFullWifiLockReleasedLocked(uid);
    783         }
    784     }
    785 
    786     public void noteWifiScanStarted(int uid) {
    787         enforceCallingPermission();
    788         synchronized (mStats) {
    789             mStats.noteWifiScanStartedLocked(uid);
    790         }
    791     }
    792 
    793     public void noteWifiScanStopped(int uid) {
    794         enforceCallingPermission();
    795         synchronized (mStats) {
    796             mStats.noteWifiScanStoppedLocked(uid);
    797         }
    798     }
    799 
    800     public void noteWifiMulticastEnabled(int uid) {
    801         enforceCallingPermission();
    802         synchronized (mStats) {
    803             mStats.noteWifiMulticastEnabledLocked(uid);
    804         }
    805     }
    806 
    807     public void noteWifiMulticastDisabled(int uid) {
    808         enforceCallingPermission();
    809         synchronized (mStats) {
    810             mStats.noteWifiMulticastDisabledLocked(uid);
    811         }
    812     }
    813 
    814     public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
    815         enforceCallingPermission();
    816         synchronized (mStats) {
    817             mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
    818         }
    819     }
    820 
    821     public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
    822         enforceCallingPermission();
    823         synchronized (mStats) {
    824             mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
    825         }
    826     }
    827 
    828     public void noteWifiScanStartedFromSource(WorkSource ws) {
    829         enforceCallingPermission();
    830         synchronized (mStats) {
    831             mStats.noteWifiScanStartedFromSourceLocked(ws);
    832         }
    833     }
    834 
    835     public void noteWifiScanStoppedFromSource(WorkSource ws) {
    836         enforceCallingPermission();
    837         synchronized (mStats) {
    838             mStats.noteWifiScanStoppedFromSourceLocked(ws);
    839         }
    840     }
    841 
    842     public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
    843         enforceCallingPermission();
    844         synchronized (mStats) {
    845             mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
    846         }
    847     }
    848 
    849     public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
    850         enforceCallingPermission();
    851         synchronized (mStats) {
    852             mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
    853         }
    854     }
    855 
    856     public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
    857         enforceCallingPermission();
    858         synchronized (mStats) {
    859             mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
    860         }
    861     }
    862 
    863     @Override
    864     public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
    865         enforceCallingPermission();
    866         synchronized (mStats) {
    867             mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
    868         }
    869     }
    870 
    871     @Override
    872     public void noteNetworkInterfaceType(String iface, int networkType) {
    873         enforceCallingPermission();
    874         synchronized (mStats) {
    875             mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
    876         }
    877     }
    878 
    879     @Override
    880     public void noteNetworkStatsEnabled() {
    881         enforceCallingPermission();
    882         synchronized (mStats) {
    883             mStats.noteNetworkStatsEnabledLocked();
    884         }
    885     }
    886 
    887     @Override
    888     public void noteDeviceIdleMode(int mode, String activeReason, int activeUid) {
    889         enforceCallingPermission();
    890         synchronized (mStats) {
    891             mStats.noteDeviceIdleModeLocked(mode, activeReason, activeUid);
    892         }
    893     }
    894 
    895     public void notePackageInstalled(String pkgName, int versionCode) {
    896         enforceCallingPermission();
    897         synchronized (mStats) {
    898             mStats.notePackageInstalledLocked(pkgName, versionCode);
    899         }
    900     }
    901 
    902     public void notePackageUninstalled(String pkgName) {
    903         enforceCallingPermission();
    904         synchronized (mStats) {
    905             mStats.notePackageUninstalledLocked(pkgName);
    906         }
    907     }
    908 
    909     @Override
    910     public void noteBleScanStarted(WorkSource ws) {
    911         enforceCallingPermission();
    912         synchronized (mStats) {
    913             mStats.noteBluetoothScanStartedFromSourceLocked(ws);
    914         }
    915     }
    916 
    917     @Override
    918     public void noteBleScanStopped(WorkSource ws) {
    919         enforceCallingPermission();
    920         synchronized (mStats) {
    921             mStats.noteBluetoothScanStoppedFromSourceLocked(ws);
    922         }
    923     }
    924 
    925     @Override
    926     public void noteResetBleScan() {
    927         enforceCallingPermission();
    928         synchronized (mStats) {
    929             mStats.noteResetBluetoothScanLocked();
    930         }
    931     }
    932 
    933     @Override
    934     public void noteWifiControllerActivity(WifiActivityEnergyInfo info) {
    935         enforceCallingPermission();
    936 
    937         if (info == null || !info.isValid()) {
    938             Slog.e(TAG, "invalid wifi data given: " + info);
    939             return;
    940         }
    941 
    942         synchronized (mStats) {
    943             mStats.updateWifiStateLocked(info);
    944         }
    945     }
    946 
    947     @Override
    948     public void noteBluetoothControllerActivity(BluetoothActivityEnergyInfo info) {
    949         enforceCallingPermission();
    950         if (info == null || !info.isValid()) {
    951             Slog.e(TAG, "invalid bluetooth data given: " + info);
    952             return;
    953         }
    954 
    955         synchronized (mStats) {
    956             mStats.updateBluetoothStateLocked(info);
    957         }
    958     }
    959 
    960     @Override
    961     public void noteModemControllerActivity(ModemActivityInfo info) {
    962         enforceCallingPermission();
    963 
    964         if (info == null || !info.isValid()) {
    965             Slog.e(TAG, "invalid modem data given: " + info);
    966             return;
    967         }
    968 
    969         synchronized (mStats) {
    970             mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime(), info);
    971         }
    972     }
    973 
    974     public boolean isOnBattery() {
    975         return mStats.isOnBattery();
    976     }
    977 
    978     @Override
    979     public void setBatteryState(final int status, final int health, final int plugType,
    980             final int level, final int temp, final int volt, final int chargeUAh) {
    981         enforceCallingPermission();
    982 
    983         // BatteryService calls us here and we may update external state. It would be wrong
    984         // to block such a low level service like BatteryService on external stats like WiFi.
    985         mHandler.post(new Runnable() {
    986             @Override
    987             public void run() {
    988                 synchronized (mStats) {
    989                     final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
    990                     if (mStats.isOnBattery() == onBattery) {
    991                         // The battery state has not changed, so we don't need to sync external
    992                         // stats immediately.
    993                         mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
    994                                 chargeUAh);
    995                         return;
    996                     }
    997                 }
    998 
    999                 // Sync external stats first as the battery has changed states. If we don't sync
   1000                 // immediately here, we may not collect the relevant data later.
   1001                 updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
   1002                 synchronized (mStats) {
   1003                     mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
   1004                             chargeUAh);
   1005                 }
   1006             }
   1007         });
   1008     }
   1009 
   1010     public long getAwakeTimeBattery() {
   1011         mContext.enforceCallingOrSelfPermission(
   1012                 android.Manifest.permission.BATTERY_STATS, null);
   1013         return mStats.getAwakeTimeBattery();
   1014     }
   1015 
   1016     public long getAwakeTimePlugged() {
   1017         mContext.enforceCallingOrSelfPermission(
   1018                 android.Manifest.permission.BATTERY_STATS, null);
   1019         return mStats.getAwakeTimePlugged();
   1020     }
   1021 
   1022     public void enforceCallingPermission() {
   1023         if (Binder.getCallingPid() == Process.myPid()) {
   1024             return;
   1025         }
   1026         mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
   1027                 Binder.getCallingPid(), Binder.getCallingUid(), null);
   1028     }
   1029 
   1030     final class WakeupReasonThread extends Thread {
   1031         private static final int MAX_REASON_SIZE = 512;
   1032         private CharsetDecoder mDecoder;
   1033         private ByteBuffer mUtf8Buffer;
   1034         private CharBuffer mUtf16Buffer;
   1035 
   1036         WakeupReasonThread() {
   1037             super("BatteryStats_wakeupReason");
   1038         }
   1039 
   1040         public void run() {
   1041             Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
   1042 
   1043             mDecoder = StandardCharsets.UTF_8
   1044                     .newDecoder()
   1045                     .onMalformedInput(CodingErrorAction.REPLACE)
   1046                     .onUnmappableCharacter(CodingErrorAction.REPLACE)
   1047                     .replaceWith("?");
   1048 
   1049             mUtf8Buffer = ByteBuffer.allocateDirect(MAX_REASON_SIZE);
   1050             mUtf16Buffer = CharBuffer.allocate(MAX_REASON_SIZE);
   1051 
   1052             try {
   1053                 String reason;
   1054                 while ((reason = waitWakeup()) != null) {
   1055                     synchronized (mStats) {
   1056                         mStats.noteWakeupReasonLocked(reason);
   1057                     }
   1058                 }
   1059             } catch (RuntimeException e) {
   1060                 Slog.e(TAG, "Failure reading wakeup reasons", e);
   1061             }
   1062         }
   1063 
   1064         private String waitWakeup() {
   1065             mUtf8Buffer.clear();
   1066             mUtf16Buffer.clear();
   1067             mDecoder.reset();
   1068 
   1069             int bytesWritten = nativeWaitWakeup(mUtf8Buffer);
   1070             if (bytesWritten < 0) {
   1071                 return null;
   1072             } else if (bytesWritten == 0) {
   1073                 return "unknown";
   1074             }
   1075 
   1076             // Set the buffer's limit to the number of bytes written.
   1077             mUtf8Buffer.limit(bytesWritten);
   1078 
   1079             // Decode the buffer from UTF-8 to UTF-16.
   1080             // Unmappable characters will be replaced.
   1081             mDecoder.decode(mUtf8Buffer, mUtf16Buffer, true);
   1082             mUtf16Buffer.flip();
   1083 
   1084             // Create a String from the UTF-16 buffer.
   1085             return mUtf16Buffer.toString();
   1086         }
   1087     }
   1088 
   1089     private static native int nativeWaitWakeup(ByteBuffer outBuffer);
   1090 
   1091     private void dumpHelp(PrintWriter pw) {
   1092         pw.println("Battery stats (batterystats) dump options:");
   1093         pw.println("  [--checkin] [--history] [--history-start] [--charged] [-c]");
   1094         pw.println("  [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
   1095         pw.println("  --checkin: generate output for a checkin report; will write (and clear) the");
   1096         pw.println("             last old completed stats when they had been reset.");
   1097         pw.println("  -c: write the current stats in checkin format.");
   1098         pw.println("  --history: show only history data.");
   1099         pw.println("  --history-start <num>: show only history data starting at given time offset.");
   1100         pw.println("  --charged: only output data since last charged.");
   1101         pw.println("  --daily: only output full daily data.");
   1102         pw.println("  --reset: reset the stats, clearing all current data.");
   1103         pw.println("  --write: force write current collected stats to disk.");
   1104         pw.println("  --new-daily: immediately create and write new daily stats record.");
   1105         pw.println("  --read-daily: read-load last written daily stats.");
   1106         pw.println("  <package.name>: optional name of package to filter output by.");
   1107         pw.println("  -h: print this help text.");
   1108         pw.println("Battery stats (batterystats) commands:");
   1109         pw.println("  enable|disable <option>");
   1110         pw.println("    Enable or disable a running option.  Option state is not saved across boots.");
   1111         pw.println("    Options are:");
   1112         pw.println("      full-history: include additional detailed events in battery history:");
   1113         pw.println("          wake_lock_in, alarms and proc events");
   1114         pw.println("      no-auto-reset: don't automatically reset stats when unplugged");
   1115     }
   1116 
   1117     private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
   1118         i++;
   1119         if (i >= args.length) {
   1120             pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
   1121             dumpHelp(pw);
   1122             return -1;
   1123         }
   1124         if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
   1125             synchronized (mStats) {
   1126                 mStats.setRecordAllHistoryLocked(enable);
   1127             }
   1128         } else if ("no-auto-reset".equals(args[i])) {
   1129             synchronized (mStats) {
   1130                 mStats.setNoAutoReset(enable);
   1131             }
   1132         } else {
   1133             pw.println("Unknown enable/disable option: " + args[i]);
   1134             dumpHelp(pw);
   1135             return -1;
   1136         }
   1137         return i;
   1138     }
   1139 
   1140 
   1141     @Override
   1142     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1143         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
   1144                 != PackageManager.PERMISSION_GRANTED) {
   1145             pw.println("Permission Denial: can't dump BatteryStats from from pid="
   1146                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
   1147                     + " without permission " + android.Manifest.permission.DUMP);
   1148             return;
   1149         }
   1150 
   1151         int flags = 0;
   1152         boolean useCheckinFormat = false;
   1153         boolean isRealCheckin = false;
   1154         boolean noOutput = false;
   1155         boolean writeData = false;
   1156         long historyStart = -1;
   1157         int reqUid = -1;
   1158         if (args != null) {
   1159             for (int i=0; i<args.length; i++) {
   1160                 String arg = args[i];
   1161                 if ("--checkin".equals(arg)) {
   1162                     useCheckinFormat = true;
   1163                     isRealCheckin = true;
   1164                 } else if ("--history".equals(arg)) {
   1165                     flags |= BatteryStats.DUMP_HISTORY_ONLY;
   1166                 } else if ("--history-start".equals(arg)) {
   1167                     flags |= BatteryStats.DUMP_HISTORY_ONLY;
   1168                     i++;
   1169                     if (i >= args.length) {
   1170                         pw.println("Missing time argument for --history-since");
   1171                         dumpHelp(pw);
   1172                         return;
   1173                     }
   1174                     historyStart = Long.parseLong(args[i]);
   1175                     writeData = true;
   1176                 } else if ("-c".equals(arg)) {
   1177                     useCheckinFormat = true;
   1178                     flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
   1179                 } else if ("--charged".equals(arg)) {
   1180                     flags |= BatteryStats.DUMP_CHARGED_ONLY;
   1181                 } else if ("--daily".equals(arg)) {
   1182                     flags |= BatteryStats.DUMP_DAILY_ONLY;
   1183                 } else if ("--reset".equals(arg)) {
   1184                     synchronized (mStats) {
   1185                         mStats.resetAllStatsCmdLocked();
   1186                         pw.println("Battery stats reset.");
   1187                         noOutput = true;
   1188                     }
   1189                     updateExternalStatsSync("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
   1190                 } else if ("--write".equals(arg)) {
   1191                     updateExternalStatsSync("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
   1192                     synchronized (mStats) {
   1193                         mStats.writeSyncLocked();
   1194                         pw.println("Battery stats written.");
   1195                         noOutput = true;
   1196                     }
   1197                 } else if ("--new-daily".equals(arg)) {
   1198                     synchronized (mStats) {
   1199                         mStats.recordDailyStatsLocked();
   1200                         pw.println("New daily stats written.");
   1201                         noOutput = true;
   1202                     }
   1203                 } else if ("--read-daily".equals(arg)) {
   1204                     synchronized (mStats) {
   1205                         mStats.readDailyStatsLocked();
   1206                         pw.println("Last daily stats read.");
   1207                         noOutput = true;
   1208                     }
   1209                 } else if ("--enable".equals(arg) || "enable".equals(arg)) {
   1210                     i = doEnableOrDisable(pw, i, args, true);
   1211                     if (i < 0) {
   1212                         return;
   1213                     }
   1214                     pw.println("Enabled: " + args[i]);
   1215                     return;
   1216                 } else if ("--disable".equals(arg) || "disable".equals(arg)) {
   1217                     i = doEnableOrDisable(pw, i, args, false);
   1218                     if (i < 0) {
   1219                         return;
   1220                     }
   1221                     pw.println("Disabled: " + args[i]);
   1222                     return;
   1223                 } else if ("-h".equals(arg)) {
   1224                     dumpHelp(pw);
   1225                     return;
   1226                 } else if ("-a".equals(arg)) {
   1227                     flags |= BatteryStats.DUMP_VERBOSE;
   1228                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
   1229                     pw.println("Unknown option: " + arg);
   1230                     dumpHelp(pw);
   1231                     return;
   1232                 } else {
   1233                     // Not an option, last argument must be a package name.
   1234                     try {
   1235                         reqUid = mContext.getPackageManager().getPackageUidAsUser(arg,
   1236                                 UserHandle.getCallingUserId());
   1237                     } catch (PackageManager.NameNotFoundException e) {
   1238                         pw.println("Unknown package: " + arg);
   1239                         dumpHelp(pw);
   1240                         return;
   1241                     }
   1242                 }
   1243             }
   1244         }
   1245         if (noOutput) {
   1246             return;
   1247         }
   1248 
   1249         long ident = Binder.clearCallingIdentity();
   1250         try {
   1251             if (BatteryStatsHelper.checkWifiOnly(mContext)) {
   1252                 flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
   1253             }
   1254             // Fetch data from external sources and update the BatteryStatsImpl object with them.
   1255             updateExternalStatsSync("dump", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
   1256         } finally {
   1257             Binder.restoreCallingIdentity(ident);
   1258         }
   1259 
   1260         if (reqUid >= 0) {
   1261             // By default, if the caller is only interested in a specific package, then
   1262             // we only dump the aggregated data since charged.
   1263             if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
   1264                 flags |= BatteryStats.DUMP_CHARGED_ONLY;
   1265                 // Also if they are doing -c, we don't want history.
   1266                 flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
   1267             }
   1268         }
   1269 
   1270         if (useCheckinFormat) {
   1271             List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
   1272                     PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_ALL);
   1273             if (isRealCheckin) {
   1274                 // For a real checkin, first we want to prefer to use the last complete checkin
   1275                 // file if there is one.
   1276                 synchronized (mStats.mCheckinFile) {
   1277                     if (mStats.mCheckinFile.exists()) {
   1278                         try {
   1279                             byte[] raw = mStats.mCheckinFile.readFully();
   1280                             if (raw != null) {
   1281                                 Parcel in = Parcel.obtain();
   1282                                 in.unmarshall(raw, 0, raw.length);
   1283                                 in.setDataPosition(0);
   1284                                 BatteryStatsImpl checkinStats = new BatteryStatsImpl(
   1285                                         null, mStats.mHandler, null);
   1286                                 checkinStats.readSummaryFromParcel(in);
   1287                                 in.recycle();
   1288                                 checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
   1289                                         historyStart);
   1290                                 mStats.mCheckinFile.delete();
   1291                                 return;
   1292                             }
   1293                         } catch (IOException | ParcelFormatException e) {
   1294                             Slog.w(TAG, "Failure reading checkin file "
   1295                                     + mStats.mCheckinFile.getBaseFile(), e);
   1296                         }
   1297                     }
   1298                 }
   1299             }
   1300             synchronized (mStats) {
   1301                 mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
   1302                 if (writeData) {
   1303                     mStats.writeAsyncLocked();
   1304                 }
   1305             }
   1306         } else {
   1307             synchronized (mStats) {
   1308                 mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
   1309                 if (writeData) {
   1310                     mStats.writeAsyncLocked();
   1311                 }
   1312             }
   1313         }
   1314     }
   1315 
   1316     private WifiActivityEnergyInfo extractDelta(WifiActivityEnergyInfo latest) {
   1317         final long timePeriodMs = latest.mTimestamp - mLastInfo.mTimestamp;
   1318         final long lastIdleMs = mLastInfo.mControllerIdleTimeMs;
   1319         final long lastTxMs = mLastInfo.mControllerTxTimeMs;
   1320         final long lastRxMs = mLastInfo.mControllerRxTimeMs;
   1321         final long lastEnergy = mLastInfo.mControllerEnergyUsed;
   1322 
   1323         // We will modify the last info object to be the delta, and store the new
   1324         // WifiActivityEnergyInfo object as our last one.
   1325         final WifiActivityEnergyInfo delta = mLastInfo;
   1326         delta.mTimestamp = latest.getTimeStamp();
   1327         delta.mStackState = latest.getStackState();
   1328 
   1329         final long txTimeMs = latest.mControllerTxTimeMs - lastTxMs;
   1330         final long rxTimeMs = latest.mControllerRxTimeMs - lastRxMs;
   1331         final long idleTimeMs = latest.mControllerIdleTimeMs - lastIdleMs;
   1332 
   1333         if (txTimeMs < 0 || rxTimeMs < 0) {
   1334             // The stats were reset by the WiFi system (which is why our delta is negative).
   1335             // Returns the unaltered stats.
   1336             delta.mControllerEnergyUsed = latest.mControllerEnergyUsed;
   1337             delta.mControllerRxTimeMs = latest.mControllerRxTimeMs;
   1338             delta.mControllerTxTimeMs = latest.mControllerTxTimeMs;
   1339             delta.mControllerIdleTimeMs = latest.mControllerIdleTimeMs;
   1340             Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta);
   1341         } else {
   1342             final long totalActiveTimeMs = txTimeMs + rxTimeMs;
   1343             long maxExpectedIdleTimeMs;
   1344             if (totalActiveTimeMs > timePeriodMs) {
   1345                 // Cap the max idle time at zero since the active time consumed the whole time
   1346                 maxExpectedIdleTimeMs = 0;
   1347                 if (totalActiveTimeMs > timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) {
   1348                     StringBuilder sb = new StringBuilder();
   1349                     sb.append("Total Active time ");
   1350                     TimeUtils.formatDuration(totalActiveTimeMs, sb);
   1351                     sb.append(" is longer than sample period ");
   1352                     TimeUtils.formatDuration(timePeriodMs, sb);
   1353                     sb.append(".\n");
   1354                     sb.append("Previous WiFi snapshot: ").append("idle=");
   1355                     TimeUtils.formatDuration(lastIdleMs, sb);
   1356                     sb.append(" rx=");
   1357                     TimeUtils.formatDuration(lastRxMs, sb);
   1358                     sb.append(" tx=");
   1359                     TimeUtils.formatDuration(lastTxMs, sb);
   1360                     sb.append(" e=").append(lastEnergy);
   1361                     sb.append("\n");
   1362                     sb.append("Current WiFi snapshot: ").append("idle=");
   1363                     TimeUtils.formatDuration(latest.mControllerIdleTimeMs, sb);
   1364                     sb.append(" rx=");
   1365                     TimeUtils.formatDuration(latest.mControllerRxTimeMs, sb);
   1366                     sb.append(" tx=");
   1367                     TimeUtils.formatDuration(latest.mControllerTxTimeMs, sb);
   1368                     sb.append(" e=").append(latest.mControllerEnergyUsed);
   1369                     Slog.wtf(TAG, sb.toString());
   1370                 }
   1371             } else {
   1372                 maxExpectedIdleTimeMs = timePeriodMs - totalActiveTimeMs;
   1373             }
   1374             // These times seem to be the most reliable.
   1375             delta.mControllerTxTimeMs = txTimeMs;
   1376             delta.mControllerRxTimeMs = rxTimeMs;
   1377             // WiFi calculates the idle time as a difference from the on time and the various
   1378             // Rx + Tx times. There seems to be some missing time there because this sometimes
   1379             // becomes negative. Just cap it at 0 and ensure that it is less than the expected idle
   1380             // time from the difference in timestamps.
   1381             // b/21613534
   1382             delta.mControllerIdleTimeMs = Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs));
   1383             delta.mControllerEnergyUsed = Math.max(0, latest.mControllerEnergyUsed - lastEnergy);
   1384         }
   1385 
   1386         mLastInfo = latest;
   1387         return delta;
   1388     }
   1389 
   1390     /**
   1391      * Helper method to extract the Parcelable controller info from a
   1392      * SynchronousResultReceiver.
   1393      */
   1394     private static <T extends Parcelable> T awaitControllerInfo(
   1395             @Nullable SynchronousResultReceiver receiver) throws TimeoutException {
   1396         if (receiver == null) {
   1397             return null;
   1398         }
   1399 
   1400         final SynchronousResultReceiver.Result result =
   1401                 receiver.awaitResult(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS);
   1402         if (result.bundle != null) {
   1403             // This is the final destination for the Bundle.
   1404             result.bundle.setDefusable(true);
   1405 
   1406             final T data = result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY);
   1407             if (data != null) {
   1408                 return data;
   1409             }
   1410         }
   1411         Slog.e(TAG, "no controller energy info supplied");
   1412         return null;
   1413     }
   1414 
   1415     /**
   1416      * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
   1417      * batterystats with that information.
   1418      *
   1419      * We first grab a lock specific to this method, then once all the data has been collected,
   1420      * we grab the mStats lock and update the data.
   1421      *
   1422      * @param reason The reason why this collection was requested. Useful for debugging.
   1423      * @param updateFlags Which external stats to update. Can be a combination of
   1424      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_CPU},
   1425      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_RADIO},
   1426      *                    {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_WIFI},
   1427      *                    and {@link BatteryStatsImpl.ExternalStatsSync#UPDATE_BT}.
   1428      */
   1429     void updateExternalStatsSync(final String reason, int updateFlags) {
   1430         SynchronousResultReceiver wifiReceiver = null;
   1431         SynchronousResultReceiver bluetoothReceiver = null;
   1432         SynchronousResultReceiver modemReceiver = null;
   1433 
   1434         synchronized (mExternalStatsLock) {
   1435             if (mContext == null) {
   1436                 // Don't do any work yet.
   1437                 return;
   1438             }
   1439 
   1440             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_WIFI) != 0) {
   1441                 if (mWifiManager == null) {
   1442                     mWifiManager = IWifiManager.Stub.asInterface(
   1443                             ServiceManager.getService(Context.WIFI_SERVICE));
   1444                 }
   1445 
   1446                 if (mWifiManager != null) {
   1447                     try {
   1448                         wifiReceiver = new SynchronousResultReceiver();
   1449                         mWifiManager.requestActivityInfo(wifiReceiver);
   1450                     } catch (RemoteException e) {
   1451                         // Oh well.
   1452                     }
   1453                 }
   1454             }
   1455 
   1456             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_BT) != 0) {
   1457                 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
   1458                 if (adapter != null) {
   1459                     bluetoothReceiver = new SynchronousResultReceiver();
   1460                     adapter.requestControllerActivityEnergyInfo(bluetoothReceiver);
   1461                 }
   1462             }
   1463 
   1464             if ((updateFlags & BatteryStatsImpl.ExternalStatsSync.UPDATE_RADIO) != 0) {
   1465                 if (mTelephony == null) {
   1466                     mTelephony = TelephonyManager.from(mContext);
   1467                 }
   1468 
   1469                 if (mTelephony != null) {
   1470                     modemReceiver = new SynchronousResultReceiver();
   1471                     mTelephony.requestModemActivityInfo(modemReceiver);
   1472                 }
   1473             }
   1474 
   1475             WifiActivityEnergyInfo wifiInfo = null;
   1476             BluetoothActivityEnergyInfo bluetoothInfo = null;
   1477             ModemActivityInfo modemInfo = null;
   1478             try {
   1479                 wifiInfo = awaitControllerInfo(wifiReceiver);
   1480             } catch (TimeoutException e) {
   1481                 Slog.w(TAG, "Timeout reading wifi stats");
   1482             }
   1483 
   1484             try {
   1485                 bluetoothInfo = awaitControllerInfo(bluetoothReceiver);
   1486             } catch (TimeoutException e) {
   1487                 Slog.w(TAG, "Timeout reading bt stats");
   1488             }
   1489 
   1490             try {
   1491                 modemInfo = awaitControllerInfo(modemReceiver);
   1492             } catch (TimeoutException e) {
   1493                 Slog.w(TAG, "Timeout reading modem stats");
   1494             }
   1495 
   1496             synchronized (mStats) {
   1497                 mStats.addHistoryEventLocked(
   1498                         SystemClock.elapsedRealtime(),
   1499                         SystemClock.uptimeMillis(),
   1500                         BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS,
   1501                         reason, 0);
   1502 
   1503                 mStats.updateCpuTimeLocked();
   1504                 mStats.updateKernelWakelocksLocked();
   1505 
   1506                 if (wifiInfo != null) {
   1507                     if (wifiInfo.isValid()) {
   1508                         mStats.updateWifiStateLocked(extractDelta(wifiInfo));
   1509                     } else {
   1510                         Slog.e(TAG, "wifi info is invalid: " + wifiInfo);
   1511                     }
   1512                 }
   1513 
   1514                 if (bluetoothInfo != null) {
   1515                     if (bluetoothInfo.isValid()) {
   1516                         mStats.updateBluetoothStateLocked(bluetoothInfo);
   1517                     } else {
   1518                         Slog.e(TAG, "bluetooth info is invalid: " + bluetoothInfo);
   1519                     }
   1520                 }
   1521 
   1522                 if (modemInfo != null) {
   1523                     if (modemInfo.isValid()) {
   1524                         mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime(),
   1525                                 modemInfo);
   1526                     } else {
   1527                         Slog.e(TAG, "modem info is invalid: " + modemInfo);
   1528                     }
   1529                 }
   1530             }
   1531         }
   1532     }
   1533 
   1534     /**
   1535      * Gets a snapshot of the system health for a particular uid.
   1536      */
   1537     @Override
   1538     public HealthStatsParceler takeUidSnapshot(int requestUid) {
   1539         if (requestUid != Binder.getCallingUid()) {
   1540             mContext.enforceCallingOrSelfPermission(
   1541                     android.Manifest.permission.BATTERY_STATS, null);
   1542         }
   1543         long ident = Binder.clearCallingIdentity();
   1544         try {
   1545             updateExternalStatsSync("get-health-stats-for-uid",
   1546                     BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
   1547             synchronized (mStats) {
   1548                 return getHealthStatsForUidLocked(requestUid);
   1549             }
   1550         } catch (Exception ex) {
   1551             Slog.d(TAG, "Crashed while writing for takeUidSnapshot(" + requestUid + ")", ex);
   1552             throw ex;
   1553         } finally {
   1554             Binder.restoreCallingIdentity(ident);
   1555         }
   1556     }
   1557 
   1558     /**
   1559      * Gets a snapshot of the system health for a number of uids.
   1560      */
   1561     @Override
   1562     public HealthStatsParceler[] takeUidSnapshots(int[] requestUids) {
   1563         if (!onlyCaller(requestUids)) {
   1564             mContext.enforceCallingOrSelfPermission(
   1565                     android.Manifest.permission.BATTERY_STATS, null);
   1566         }
   1567         long ident = Binder.clearCallingIdentity();
   1568         int i=-1;
   1569         try {
   1570             updateExternalStatsSync("get-health-stats-for-uids",
   1571                     BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
   1572             synchronized (mStats) {
   1573                 final int N = requestUids.length;
   1574                 final HealthStatsParceler[] results = new HealthStatsParceler[N];
   1575                 for (i=0; i<N; i++) {
   1576                     results[i] = getHealthStatsForUidLocked(requestUids[i]);
   1577                 }
   1578                 return results;
   1579             }
   1580         } catch (Exception ex) {
   1581             Slog.d(TAG, "Crashed while writing for takeUidSnapshots("
   1582                     + Arrays.toString(requestUids) + ") i=" + i, ex);
   1583             throw ex;
   1584         } finally {
   1585             Binder.restoreCallingIdentity(ident);
   1586         }
   1587     }
   1588 
   1589     /**
   1590      * Returns whether the Binder.getCallingUid is the only thing in requestUids.
   1591      */
   1592     private static boolean onlyCaller(int[] requestUids) {
   1593         final int caller = Binder.getCallingUid();
   1594         final int N = requestUids.length;
   1595         for (int i=0; i<N; i++) {
   1596             if (requestUids[i] != caller) {
   1597                 return false;
   1598             }
   1599         }
   1600         return true;
   1601     }
   1602 
   1603     /**
   1604      * Gets a HealthStatsParceler for the given uid. You should probably call
   1605      * updateExternalStatsSync first.
   1606      */
   1607     HealthStatsParceler getHealthStatsForUidLocked(int requestUid) {
   1608         final HealthStatsBatteryStatsWriter writer = new HealthStatsBatteryStatsWriter();
   1609         final HealthStatsWriter uidWriter = new HealthStatsWriter(UidHealthStats.CONSTANTS);
   1610         final BatteryStats.Uid uid = mStats.getUidStats().get(requestUid);
   1611         if (uid != null) {
   1612             writer.writeUid(uidWriter, mStats, uid);
   1613         }
   1614         return new HealthStatsParceler(uidWriter);
   1615     }
   1616 
   1617 }
   1618