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