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