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