BatteryStatsService.java revision 1e38382b542f5cef9957a89692b02c55a3dd351c
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.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothHeadset;
22import android.bluetooth.BluetoothProfile;
23import android.content.Context;
24import android.content.pm.ApplicationInfo;
25import android.content.pm.PackageManager;
26import android.net.wifi.IWifiManager;
27import android.net.wifi.WifiActivityEnergyInfo;
28import android.os.BatteryStats;
29import android.os.Binder;
30import android.os.Handler;
31import android.os.IBinder;
32import android.os.Looper;
33import android.os.Message;
34import android.os.Parcel;
35import android.os.ParcelFileDescriptor;
36import android.os.PowerManagerInternal;
37import android.os.Process;
38import android.os.RemoteException;
39import android.os.ServiceManager;
40import android.os.SystemClock;
41import android.os.UserHandle;
42import android.os.WorkSource;
43import android.telephony.DataConnectionRealTimeInfo;
44import android.telephony.SignalStrength;
45import android.telephony.TelephonyManager;
46import android.util.Slog;
47
48import com.android.internal.annotations.GuardedBy;
49import com.android.internal.app.IBatteryStats;
50import com.android.internal.os.BatteryStatsHelper;
51import com.android.internal.os.BatteryStatsImpl;
52import com.android.internal.os.PowerProfile;
53import com.android.server.FgThread;
54import com.android.server.LocalServices;
55
56import java.io.File;
57import java.io.FileDescriptor;
58import java.io.IOException;
59import java.io.PrintWriter;
60import java.util.List;
61
62/**
63 * All information we are collecting about things that can happen that impact
64 * battery life.
65 */
66public final class BatteryStatsService extends IBatteryStats.Stub
67        implements PowerManagerInternal.LowPowerModeListener {
68    static final String TAG = "BatteryStatsService";
69
70    static IBatteryStats sService;
71    final BatteryStatsImpl mStats;
72    final BatteryStatsHandler mHandler;
73    Context mContext;
74    private boolean mBluetoothPendingStats;
75    private BluetoothHeadset mBluetoothHeadset;
76    PowerManagerInternal mPowerManagerInternal;
77
78    class BatteryStatsHandler extends Handler implements BatteryStatsImpl.ExternalStatsSync {
79        public static final int MSG_SYNC_EXTERNAL_STATS = 1;
80        public static final int MSG_WRITE_TO_DISK = 2;
81
82        public BatteryStatsHandler(Looper looper) {
83            super(looper);
84        }
85
86        @Override
87        public void handleMessage(Message msg) {
88            switch (msg.what) {
89                case MSG_SYNC_EXTERNAL_STATS:
90                    updateExternalStats();
91                    break;
92
93                case MSG_WRITE_TO_DISK:
94                    updateExternalStats();
95                    synchronized (mStats) {
96                        mStats.writeAsyncLocked();
97                    }
98                    break;
99            }
100        }
101
102        @Override
103        public void scheduleSync() {
104            if (!hasMessages(MSG_SYNC_EXTERNAL_STATS)) {
105                sendEmptyMessage(MSG_SYNC_EXTERNAL_STATS);
106            }
107        }
108    }
109
110    BatteryStatsService(File systemDir, Handler handler) {
111        // Our handler here will be accessing the disk, use a different thread than
112        // what the ActivityManagerService gave us (no I/O on that one!).
113        mHandler = new BatteryStatsHandler(FgThread.getHandler().getLooper());
114
115        // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
116        mStats = new BatteryStatsImpl(systemDir, handler, mHandler);
117    }
118
119    public void publish(Context context) {
120        mContext = context;
121        ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
122        mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
123        mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
124                com.android.internal.R.integer.config_radioScanningTimeout)
125                * 1000L);
126        mStats.setPowerProfile(new PowerProfile(context));
127    }
128
129    /**
130     * At the time when the constructor runs, the power manager has not yet been
131     * initialized.  So we initialize the low power observer later.
132     */
133    public void initPowerManagement() {
134        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
135        mPowerManagerInternal.registerLowPowerModeObserver(this);
136        mStats.notePowerSaveMode(mPowerManagerInternal.getLowPowerModeEnabled());
137        (new WakeupReasonThread()).start();
138    }
139
140    public void shutdown() {
141        Slog.w("BatteryStats", "Writing battery stats before shutdown...");
142
143        updateExternalStats();
144        synchronized (mStats) {
145            mStats.shutdownLocked();
146        }
147    }
148
149    public static IBatteryStats getService() {
150        if (sService != null) {
151            return sService;
152        }
153        IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME);
154        sService = asInterface(b);
155        return sService;
156    }
157
158    @Override
159    public void onLowPowerModeChanged(boolean enabled) {
160        synchronized (mStats) {
161            mStats.notePowerSaveMode(enabled);
162        }
163    }
164
165    /**
166     * @return the current statistics object, which may be modified
167     * to reflect events that affect battery usage.  You must lock the
168     * stats object before doing anything with it.
169     */
170    public BatteryStatsImpl getActiveStatistics() {
171        return mStats;
172    }
173
174    /**
175     * Schedules a write to disk to occur. This will cause the BatteryStatsImpl
176     * object to update with the latest info, then write to disk.
177     */
178    public void scheduleWriteToDisk() {
179        mHandler.sendEmptyMessage(BatteryStatsHandler.MSG_WRITE_TO_DISK);
180    }
181
182    // These are for direct use by the activity manager...
183
184    void addIsolatedUid(int isolatedUid, int appUid) {
185        synchronized (mStats) {
186            mStats.addIsolatedUidLocked(isolatedUid, appUid);
187        }
188    }
189
190    void removeIsolatedUid(int isolatedUid, int appUid) {
191        synchronized (mStats) {
192            mStats.removeIsolatedUidLocked(isolatedUid, appUid);
193        }
194    }
195
196    void noteProcessStart(String name, int uid) {
197        synchronized (mStats) {
198            mStats.noteProcessStartLocked(name, uid);
199        }
200    }
201
202    void noteProcessCrash(String name, int uid) {
203        synchronized (mStats) {
204            mStats.noteProcessCrashLocked(name, uid);
205        }
206    }
207
208    void noteProcessAnr(String name, int uid) {
209        synchronized (mStats) {
210            mStats.noteProcessAnrLocked(name, uid);
211        }
212    }
213
214    void noteProcessState(String name, int uid, int state) {
215        synchronized (mStats) {
216            mStats.noteProcessStateLocked(name, uid, state);
217        }
218    }
219
220    void noteProcessFinish(String name, int uid) {
221        synchronized (mStats) {
222            mStats.noteProcessFinishLocked(name, uid);
223        }
224    }
225
226    // Public interface...
227
228    public byte[] getStatistics() {
229        mContext.enforceCallingPermission(
230                android.Manifest.permission.BATTERY_STATS, null);
231        //Slog.i("foo", "SENDING BATTERY INFO:");
232        //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
233        Parcel out = Parcel.obtain();
234        updateExternalStats();
235        synchronized (mStats) {
236            mStats.writeToParcel(out, 0);
237        }
238        byte[] data = out.marshall();
239        out.recycle();
240        return data;
241    }
242
243    public ParcelFileDescriptor getStatisticsStream() {
244        mContext.enforceCallingPermission(
245                android.Manifest.permission.BATTERY_STATS, null);
246        //Slog.i("foo", "SENDING BATTERY INFO:");
247        //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
248        Parcel out = Parcel.obtain();
249        updateExternalStats();
250        synchronized (mStats) {
251            mStats.writeToParcel(out, 0);
252        }
253        byte[] data = out.marshall();
254        out.recycle();
255        try {
256            return ParcelFileDescriptor.fromData(data, "battery-stats");
257        } catch (IOException e) {
258            Slog.w(TAG, "Unable to create shared memory", e);
259            return null;
260        }
261    }
262
263    public boolean isCharging() {
264        synchronized (mStats) {
265            return mStats.isCharging();
266        }
267    }
268
269    public long computeBatteryTimeRemaining() {
270        synchronized (mStats) {
271            long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
272            return time >= 0 ? (time/1000) : time;
273        }
274    }
275
276    public long computeChargeTimeRemaining() {
277        synchronized (mStats) {
278            long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
279            return time >= 0 ? (time/1000) : time;
280        }
281    }
282
283    public void noteEvent(int code, String name, int uid) {
284        enforceCallingPermission();
285        synchronized (mStats) {
286            mStats.noteEventLocked(code, name, uid);
287        }
288    }
289
290    public void noteSyncStart(String name, int uid) {
291        enforceCallingPermission();
292        synchronized (mStats) {
293            mStats.noteSyncStartLocked(name, uid);
294        }
295    }
296
297    public void noteSyncFinish(String name, int uid) {
298        enforceCallingPermission();
299        synchronized (mStats) {
300            mStats.noteSyncFinishLocked(name, uid);
301        }
302    }
303
304    public void noteJobStart(String name, int uid) {
305        enforceCallingPermission();
306        synchronized (mStats) {
307            mStats.noteJobStartLocked(name, uid);
308        }
309    }
310
311    public void noteJobFinish(String name, int uid) {
312        enforceCallingPermission();
313        synchronized (mStats) {
314            mStats.noteJobFinishLocked(name, uid);
315        }
316    }
317
318    public void noteAlarmStart(String name, int uid) {
319        enforceCallingPermission();
320        synchronized (mStats) {
321            mStats.noteAlarmStartLocked(name, uid);
322        }
323    }
324
325    public void noteAlarmFinish(String name, int uid) {
326        enforceCallingPermission();
327        synchronized (mStats) {
328            mStats.noteAlarmFinishLocked(name, uid);
329        }
330    }
331
332    public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
333            boolean unimportantForLogging) {
334        enforceCallingPermission();
335        synchronized (mStats) {
336            mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging,
337                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
338        }
339    }
340
341    public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) {
342        enforceCallingPermission();
343        synchronized (mStats) {
344            mStats.noteStopWakeLocked(uid, pid, name, historyName, type,
345                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
346        }
347    }
348
349    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name,
350            String historyName, int type, boolean unimportantForLogging) {
351        enforceCallingPermission();
352        synchronized (mStats) {
353            mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
354                    type, unimportantForLogging);
355        }
356    }
357
358    public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name,
359            String historyName, int type, WorkSource newWs, int newPid, String newName,
360            String newHistoryName, int newType, boolean newUnimportantForLogging) {
361        enforceCallingPermission();
362        synchronized (mStats) {
363            mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
364                    newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
365        }
366    }
367
368    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName,
369            int type) {
370        enforceCallingPermission();
371        synchronized (mStats) {
372            mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type);
373        }
374    }
375
376    public void noteStartSensor(int uid, int sensor) {
377        enforceCallingPermission();
378        synchronized (mStats) {
379            mStats.noteStartSensorLocked(uid, sensor);
380        }
381    }
382
383    public void noteStopSensor(int uid, int sensor) {
384        enforceCallingPermission();
385        synchronized (mStats) {
386            mStats.noteStopSensorLocked(uid, sensor);
387        }
388    }
389
390    public void noteVibratorOn(int uid, long durationMillis) {
391        enforceCallingPermission();
392        synchronized (mStats) {
393            mStats.noteVibratorOnLocked(uid, durationMillis);
394        }
395    }
396
397    public void noteVibratorOff(int uid) {
398        enforceCallingPermission();
399        synchronized (mStats) {
400            mStats.noteVibratorOffLocked(uid);
401        }
402    }
403
404    public void noteStartGps(int uid) {
405        enforceCallingPermission();
406        synchronized (mStats) {
407            mStats.noteStartGpsLocked(uid);
408        }
409    }
410
411    public void noteStopGps(int uid) {
412        enforceCallingPermission();
413        synchronized (mStats) {
414            mStats.noteStopGpsLocked(uid);
415        }
416    }
417
418    public void noteScreenState(int state) {
419        enforceCallingPermission();
420        synchronized (mStats) {
421            mStats.noteScreenStateLocked(state);
422        }
423    }
424
425    public void noteScreenBrightness(int brightness) {
426        enforceCallingPermission();
427        synchronized (mStats) {
428            mStats.noteScreenBrightnessLocked(brightness);
429        }
430    }
431
432    public void noteUserActivity(int uid, int event) {
433        enforceCallingPermission();
434        synchronized (mStats) {
435            mStats.noteUserActivityLocked(uid, event);
436        }
437    }
438
439    public void noteInteractive(boolean interactive) {
440        enforceCallingPermission();
441        synchronized (mStats) {
442            mStats.noteInteractiveLocked(interactive);
443        }
444    }
445
446    public void noteConnectivityChanged(int type, String extra) {
447        enforceCallingPermission();
448        synchronized (mStats) {
449            mStats.noteConnectivityChangedLocked(type, extra);
450        }
451    }
452
453    public void noteMobileRadioPowerState(int powerState, long timestampNs) {
454        enforceCallingPermission();
455        synchronized (mStats) {
456            mStats.noteMobileRadioPowerState(powerState, timestampNs);
457        }
458    }
459
460    public void notePhoneOn() {
461        enforceCallingPermission();
462        synchronized (mStats) {
463            mStats.notePhoneOnLocked();
464        }
465    }
466
467    public void notePhoneOff() {
468        enforceCallingPermission();
469        synchronized (mStats) {
470            mStats.notePhoneOffLocked();
471        }
472    }
473
474    public void notePhoneSignalStrength(SignalStrength signalStrength) {
475        enforceCallingPermission();
476        synchronized (mStats) {
477            mStats.notePhoneSignalStrengthLocked(signalStrength);
478        }
479    }
480
481    public void notePhoneDataConnectionState(int dataType, boolean hasData) {
482        enforceCallingPermission();
483        synchronized (mStats) {
484            mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
485        }
486    }
487
488    public void notePhoneState(int state) {
489        enforceCallingPermission();
490        int simState = TelephonyManager.getDefault().getSimState();
491        synchronized (mStats) {
492            mStats.notePhoneStateLocked(state, simState);
493        }
494    }
495
496    public void noteWifiOn() {
497        enforceCallingPermission();
498        synchronized (mStats) {
499            mStats.noteWifiOnLocked();
500        }
501    }
502
503    public void noteWifiOff() {
504        enforceCallingPermission();
505        synchronized (mStats) {
506            mStats.noteWifiOffLocked();
507        }
508    }
509
510    public void noteStartAudio(int uid) {
511        enforceCallingPermission();
512        synchronized (mStats) {
513            mStats.noteAudioOnLocked(uid);
514        }
515    }
516
517    public void noteStopAudio(int uid) {
518        enforceCallingPermission();
519        synchronized (mStats) {
520            mStats.noteAudioOffLocked(uid);
521        }
522    }
523
524    public void noteStartVideo(int uid) {
525        enforceCallingPermission();
526        synchronized (mStats) {
527            mStats.noteVideoOnLocked(uid);
528        }
529    }
530
531    public void noteStopVideo(int uid) {
532        enforceCallingPermission();
533        synchronized (mStats) {
534            mStats.noteVideoOffLocked(uid);
535        }
536    }
537
538    public void noteResetAudio() {
539        enforceCallingPermission();
540        synchronized (mStats) {
541            mStats.noteResetAudioLocked();
542        }
543    }
544
545    public void noteResetVideo() {
546        enforceCallingPermission();
547        synchronized (mStats) {
548            mStats.noteResetVideoLocked();
549        }
550    }
551
552    public void noteFlashlightOn() {
553        enforceCallingPermission();
554        synchronized (mStats) {
555            mStats.noteFlashlightOnLocked();
556        }
557    }
558
559    public void noteFlashlightOff() {
560        enforceCallingPermission();
561        synchronized (mStats) {
562            mStats.noteFlashlightOffLocked();
563        }
564    }
565
566    @Override
567    public void noteWifiRadioPowerState(int powerState, long tsNanos) {
568        enforceCallingPermission();
569
570        // There was a change in WiFi power state.
571        // Collect data now for the past activity.
572        mHandler.scheduleSync();
573    }
574
575    public void noteWifiRunning(WorkSource ws) {
576        enforceCallingPermission();
577        synchronized (mStats) {
578            mStats.noteWifiRunningLocked(ws);
579        }
580    }
581
582    public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
583        enforceCallingPermission();
584        synchronized (mStats) {
585            mStats.noteWifiRunningChangedLocked(oldWs, newWs);
586        }
587    }
588
589    public void noteWifiStopped(WorkSource ws) {
590        enforceCallingPermission();
591        synchronized (mStats) {
592            mStats.noteWifiStoppedLocked(ws);
593        }
594    }
595
596    public void noteWifiState(int wifiState, String accessPoint) {
597        enforceCallingPermission();
598        synchronized (mStats) {
599            mStats.noteWifiStateLocked(wifiState, accessPoint);
600        }
601    }
602
603    public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
604        enforceCallingPermission();
605        synchronized (mStats) {
606            mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
607        }
608    }
609
610    public void noteWifiRssiChanged(int newRssi) {
611        enforceCallingPermission();
612        synchronized (mStats) {
613            mStats.noteWifiRssiChangedLocked(newRssi);
614        }
615    }
616
617    public void noteBluetoothOn() {
618        enforceCallingPermission();
619        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
620        if (adapter != null) {
621            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
622                                    BluetoothProfile.HEADSET);
623        }
624        synchronized (mStats) {
625            if (mBluetoothHeadset != null) {
626                mStats.noteBluetoothOnLocked();
627                mStats.setBtHeadset(mBluetoothHeadset);
628            } else {
629                mBluetoothPendingStats = true;
630            }
631        }
632    }
633
634    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
635        new BluetoothProfile.ServiceListener() {
636        public void onServiceConnected(int profile, BluetoothProfile proxy) {
637            mBluetoothHeadset = (BluetoothHeadset) proxy;
638            synchronized (mStats) {
639                if (mBluetoothPendingStats) {
640                    mStats.noteBluetoothOnLocked();
641                    mStats.setBtHeadset(mBluetoothHeadset);
642                    mBluetoothPendingStats = false;
643                }
644            }
645        }
646
647        public void onServiceDisconnected(int profile) {
648            mBluetoothHeadset = null;
649        }
650    };
651
652    public void noteBluetoothOff() {
653        enforceCallingPermission();
654        synchronized (mStats) {
655            mBluetoothPendingStats = false;
656            mStats.noteBluetoothOffLocked();
657        }
658    }
659
660    public void noteBluetoothState(int bluetoothState) {
661        enforceCallingPermission();
662        synchronized (mStats) {
663            mStats.noteBluetoothStateLocked(bluetoothState);
664        }
665    }
666
667    public void noteFullWifiLockAcquired(int uid) {
668        enforceCallingPermission();
669        synchronized (mStats) {
670            mStats.noteFullWifiLockAcquiredLocked(uid);
671        }
672    }
673
674    public void noteFullWifiLockReleased(int uid) {
675        enforceCallingPermission();
676        synchronized (mStats) {
677            mStats.noteFullWifiLockReleasedLocked(uid);
678        }
679    }
680
681    public void noteWifiScanStarted(int uid) {
682        enforceCallingPermission();
683        synchronized (mStats) {
684            mStats.noteWifiScanStartedLocked(uid);
685        }
686    }
687
688    public void noteWifiScanStopped(int uid) {
689        enforceCallingPermission();
690        synchronized (mStats) {
691            mStats.noteWifiScanStoppedLocked(uid);
692        }
693    }
694
695    public void noteWifiMulticastEnabled(int uid) {
696        enforceCallingPermission();
697        synchronized (mStats) {
698            mStats.noteWifiMulticastEnabledLocked(uid);
699        }
700    }
701
702    public void noteWifiMulticastDisabled(int uid) {
703        enforceCallingPermission();
704        synchronized (mStats) {
705            mStats.noteWifiMulticastDisabledLocked(uid);
706        }
707    }
708
709    public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
710        enforceCallingPermission();
711        synchronized (mStats) {
712            mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
713        }
714    }
715
716    public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
717        enforceCallingPermission();
718        synchronized (mStats) {
719            mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
720        }
721    }
722
723    public void noteWifiScanStartedFromSource(WorkSource ws) {
724        enforceCallingPermission();
725        synchronized (mStats) {
726            mStats.noteWifiScanStartedFromSourceLocked(ws);
727        }
728    }
729
730    public void noteWifiScanStoppedFromSource(WorkSource ws) {
731        enforceCallingPermission();
732        synchronized (mStats) {
733            mStats.noteWifiScanStoppedFromSourceLocked(ws);
734        }
735    }
736
737    public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
738        enforceCallingPermission();
739        synchronized (mStats) {
740            mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
741        }
742    }
743
744    public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
745        enforceCallingPermission();
746        synchronized (mStats) {
747            mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
748        }
749    }
750
751    public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
752        enforceCallingPermission();
753        synchronized (mStats) {
754            mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
755        }
756    }
757
758    @Override
759    public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
760        enforceCallingPermission();
761        synchronized (mStats) {
762            mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
763        }
764    }
765
766    @Override
767    public void noteNetworkInterfaceType(String iface, int networkType) {
768        enforceCallingPermission();
769        synchronized (mStats) {
770            mStats.noteNetworkInterfaceTypeLocked(iface, networkType);
771        }
772    }
773
774    @Override
775    public void noteNetworkStatsEnabled() {
776        enforceCallingPermission();
777        synchronized (mStats) {
778            mStats.noteNetworkStatsEnabledLocked();
779        }
780    }
781
782    @Override
783    public void noteDeviceIdleMode(boolean enabled, boolean fromActive, boolean fromMotion) {
784        enforceCallingPermission();
785        synchronized (mStats) {
786            mStats.noteDeviceIdleModeLocked(enabled, fromActive, fromMotion);
787        }
788    }
789
790    public void notePackageInstalled(String pkgName, int versionCode) {
791        enforceCallingPermission();
792        synchronized (mStats) {
793            mStats.notePackageInstalledLocked(pkgName, versionCode);
794        }
795    }
796
797    public void notePackageUninstalled(String pkgName) {
798        enforceCallingPermission();
799        synchronized (mStats) {
800            mStats.notePackageUninstalledLocked(pkgName);
801        }
802    }
803
804    public boolean isOnBattery() {
805        return mStats.isOnBattery();
806    }
807
808    public void setBatteryState(int status, int health, int plugType, int level,
809            int temp, int volt) {
810        enforceCallingPermission();
811        synchronized (mStats) {
812            final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
813            if (mStats.isOnBattery() == onBattery) {
814                // The battery state has not changed, so we don't need to sync external
815                // stats immediately.
816                mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
817                return;
818            }
819        }
820
821        // Sync external stats first as the battery has changed states. If we don't sync
822        // immediately here, we may not collect the relevant data later.
823        updateExternalStats();
824        synchronized (mStats) {
825            mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
826        }
827    }
828
829    public long getAwakeTimeBattery() {
830        mContext.enforceCallingOrSelfPermission(
831                android.Manifest.permission.BATTERY_STATS, null);
832        return mStats.getAwakeTimeBattery();
833    }
834
835    public long getAwakeTimePlugged() {
836        mContext.enforceCallingOrSelfPermission(
837                android.Manifest.permission.BATTERY_STATS, null);
838        return mStats.getAwakeTimePlugged();
839    }
840
841    public void enforceCallingPermission() {
842        if (Binder.getCallingPid() == Process.myPid()) {
843            return;
844        }
845        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
846                Binder.getCallingPid(), Binder.getCallingUid(), null);
847    }
848
849    final class WakeupReasonThread extends Thread {
850        final int[] mIrqs = new int[32];
851        final String[] mReasons = new String[32];
852
853        WakeupReasonThread() {
854            super("BatteryStats_wakeupReason");
855        }
856
857        public void run() {
858            Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
859
860            try {
861                int num;
862                while ((num=nativeWaitWakeup(mIrqs, mReasons)) >= 0) {
863                    synchronized (mStats) {
864                        if (num > 0) {
865                            for (int i=0; i<num; i++) {
866                                mStats.noteWakeupReasonLocked(mReasons[i]);
867                            }
868                        } else {
869                            mStats.noteWakeupReasonLocked("unknown");
870                        }
871                    }
872                }
873            } catch (RuntimeException e) {
874                Slog.e(TAG, "Failure reading wakeup reasons", e);
875            }
876        }
877    }
878
879    private static native int nativeWaitWakeup(int[] outIrqs, String[] outReasons);
880
881    private void dumpHelp(PrintWriter pw) {
882        pw.println("Battery stats (batterystats) dump options:");
883        pw.println("  [--checkin] [--history] [--history-start] [--charged] [-c]");
884        pw.println("  [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
885        pw.println("  --checkin: format output for a checkin report.");
886        pw.println("  --history: show only history data.");
887        pw.println("  --history-start <num>: show only history data starting at given time offset.");
888        pw.println("  --charged: only output data since last charged.");
889        pw.println("  --daily: only output full daily data.");
890        pw.println("  --reset: reset the stats, clearing all current data.");
891        pw.println("  --write: force write current collected stats to disk.");
892        pw.println("  --new-daily: immediately create and write new daily stats record.");
893        pw.println("  --read-daily: read-load last written daily stats.");
894        pw.println("  <package.name>: optional name of package to filter output by.");
895        pw.println("  -h: print this help text.");
896        pw.println("Battery stats (batterystats) commands:");
897        pw.println("  enable|disable <option>");
898        pw.println("    Enable or disable a running option.  Option state is not saved across boots.");
899        pw.println("    Options are:");
900        pw.println("      full-history: include additional detailed events in battery history:");
901        pw.println("          wake_lock_in, alarms and proc events");
902        pw.println("      no-auto-reset: don't automatically reset stats when unplugged");
903    }
904
905    private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
906        i++;
907        if (i >= args.length) {
908            pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
909            dumpHelp(pw);
910            return -1;
911        }
912        if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
913            synchronized (mStats) {
914                mStats.setRecordAllHistoryLocked(enable);
915            }
916        } else if ("no-auto-reset".equals(args[i])) {
917            synchronized (mStats) {
918                mStats.setNoAutoReset(enable);
919            }
920        } else {
921            pw.println("Unknown enable/disable option: " + args[i]);
922            dumpHelp(pw);
923            return -1;
924        }
925        return i;
926    }
927
928
929    @Override
930    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
931        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
932                != PackageManager.PERMISSION_GRANTED) {
933            pw.println("Permission Denial: can't dump BatteryStats from from pid="
934                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
935                    + " without permission " + android.Manifest.permission.DUMP);
936            return;
937        }
938
939        int flags = 0;
940        boolean useCheckinFormat = false;
941        boolean isRealCheckin = false;
942        boolean noOutput = false;
943        boolean writeData = false;
944        long historyStart = -1;
945        int reqUid = -1;
946        if (args != null) {
947            for (int i=0; i<args.length; i++) {
948                String arg = args[i];
949                if ("--checkin".equals(arg)) {
950                    useCheckinFormat = true;
951                    isRealCheckin = true;
952                } else if ("--history".equals(arg)) {
953                    flags |= BatteryStats.DUMP_HISTORY_ONLY;
954                } else if ("--history-start".equals(arg)) {
955                    flags |= BatteryStats.DUMP_HISTORY_ONLY;
956                    i++;
957                    if (i >= args.length) {
958                        pw.println("Missing time argument for --history-since");
959                        dumpHelp(pw);
960                        return;
961                    }
962                    historyStart = Long.parseLong(args[i]);
963                    writeData = true;
964                } else if ("-c".equals(arg)) {
965                    useCheckinFormat = true;
966                    flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
967                } else if ("--charged".equals(arg)) {
968                    flags |= BatteryStats.DUMP_CHARGED_ONLY;
969                } else if ("--daily".equals(arg)) {
970                    flags |= BatteryStats.DUMP_DAILY_ONLY;
971                } else if ("--reset".equals(arg)) {
972                    synchronized (mStats) {
973                        mStats.resetAllStatsCmdLocked();
974                        pw.println("Battery stats reset.");
975                        noOutput = true;
976                    }
977                    updateExternalStats();
978                } else if ("--write".equals(arg)) {
979                    updateExternalStats();
980                    synchronized (mStats) {
981                        mStats.writeSyncLocked();
982                        pw.println("Battery stats written.");
983                        noOutput = true;
984                    }
985                } else if ("--new-daily".equals(arg)) {
986                    synchronized (mStats) {
987                        mStats.recordDailyStatsLocked();
988                        pw.println("New daily stats written.");
989                        noOutput = true;
990                    }
991                } else if ("--read-daily".equals(arg)) {
992                    synchronized (mStats) {
993                        mStats.readDailyStatsLocked();
994                        pw.println("Last daily stats read.");
995                        noOutput = true;
996                    }
997                } else if ("--enable".equals(arg) || "enable".equals(arg)) {
998                    i = doEnableOrDisable(pw, i, args, true);
999                    if (i < 0) {
1000                        return;
1001                    }
1002                    pw.println("Enabled: " + args[i]);
1003                    return;
1004                } else if ("--disable".equals(arg) || "disable".equals(arg)) {
1005                    i = doEnableOrDisable(pw, i, args, false);
1006                    if (i < 0) {
1007                        return;
1008                    }
1009                    pw.println("Disabled: " + args[i]);
1010                    return;
1011                } else if ("-h".equals(arg)) {
1012                    dumpHelp(pw);
1013                    return;
1014                } else if ("-a".equals(arg)) {
1015                    flags |= BatteryStats.DUMP_VERBOSE;
1016                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
1017                    pw.println("Unknown option: " + arg);
1018                    dumpHelp(pw);
1019                    return;
1020                } else {
1021                    // Not an option, last argument must be a package name.
1022                    try {
1023                        reqUid = mContext.getPackageManager().getPackageUid(arg,
1024                                UserHandle.getCallingUserId());
1025                    } catch (PackageManager.NameNotFoundException e) {
1026                        pw.println("Unknown package: " + arg);
1027                        dumpHelp(pw);
1028                        return;
1029                    }
1030                }
1031            }
1032        }
1033        if (noOutput) {
1034            return;
1035        }
1036        if (BatteryStatsHelper.checkWifiOnly(mContext)) {
1037            flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
1038        }
1039        if (reqUid >= 0) {
1040            // By default, if the caller is only interested in a specific package, then
1041            // we only dump the aggregated data since charged.
1042            if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
1043                flags |= BatteryStats.DUMP_CHARGED_ONLY;
1044                // Also if they are doing -c, we don't want history.
1045                flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
1046            }
1047        }
1048
1049        // Fetch data from external sources and update the BatteryStatsImpl object with them.
1050        updateExternalStats();
1051
1052        if (useCheckinFormat) {
1053            List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
1054            if (isRealCheckin) {
1055                // For a real checkin, first we want to prefer to use the last complete checkin
1056                // file if there is one.
1057                synchronized (mStats.mCheckinFile) {
1058                    if (mStats.mCheckinFile.exists()) {
1059                        try {
1060                            byte[] raw = mStats.mCheckinFile.readFully();
1061                            if (raw != null) {
1062                                Parcel in = Parcel.obtain();
1063                                in.unmarshall(raw, 0, raw.length);
1064                                in.setDataPosition(0);
1065                                BatteryStatsImpl checkinStats = new BatteryStatsImpl(
1066                                        null, mStats.mHandler, null);
1067                                checkinStats.readSummaryFromParcel(in);
1068                                in.recycle();
1069                                checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
1070                                        historyStart);
1071                                mStats.mCheckinFile.delete();
1072                                return;
1073                            }
1074                        } catch (IOException e) {
1075                            Slog.w(TAG, "Failure reading checkin file "
1076                                    + mStats.mCheckinFile.getBaseFile(), e);
1077                        }
1078                    }
1079                }
1080            }
1081            synchronized (mStats) {
1082                mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
1083                if (writeData) {
1084                    mStats.writeAsyncLocked();
1085                }
1086            }
1087        } else {
1088            synchronized (mStats) {
1089                mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
1090                if (writeData) {
1091                    mStats.writeAsyncLocked();
1092                }
1093            }
1094        }
1095    }
1096
1097    // Objects for extracting data from external sources.
1098    private final Object mExternalStatsLock = new Object();
1099
1100    @GuardedBy("mExternalStatsLock")
1101    private IWifiManager mWifiManager;
1102
1103    // WiFi keeps an accumulated total of stats, unlike Bluetooth.
1104    // Keep the last WiFi stats so we can compute a delta.
1105    @GuardedBy("mExternalStatsLock")
1106    private WifiActivityEnergyInfo mLastInfo = new WifiActivityEnergyInfo(0, 0, 0, 0, 0, 0);
1107
1108    @GuardedBy("mExternalStatsLock")
1109    private WifiActivityEnergyInfo pullWifiEnergyInfoLocked() {
1110        if (mWifiManager == null) {
1111            mWifiManager = IWifiManager.Stub.asInterface(
1112                    ServiceManager.getService(Context.WIFI_SERVICE));
1113            if (mWifiManager == null) {
1114                return null;
1115            }
1116        }
1117
1118        try {
1119            // We read the data even if we are not on battery. This is so that we keep the
1120            // correct delta from when we should start reading (aka when we are on battery).
1121            WifiActivityEnergyInfo info = mWifiManager.reportActivityInfo();
1122            if (info != null && info.isValid()) {
1123                // We will modify the last info object to be the delta, and store the new
1124                // WifiActivityEnergyInfo object as our last one.
1125                final WifiActivityEnergyInfo result = mLastInfo;
1126                result.mTimestamp = info.getTimeStamp();
1127                result.mStackState = info.getStackState();
1128                result.mControllerTxTimeMs =
1129                        info.mControllerTxTimeMs - mLastInfo.mControllerTxTimeMs;
1130                result.mControllerRxTimeMs =
1131                        info.mControllerRxTimeMs - mLastInfo.mControllerRxTimeMs;
1132                result.mControllerEnergyUsed =
1133                        info.mControllerEnergyUsed - mLastInfo.mControllerEnergyUsed;
1134
1135                // WiFi calculates the idle time as a difference from the on time and the various
1136                // Rx + Tx times. There seems to be some missing time there because this sometimes
1137                // becomes negative. Just cap it at 0 and move on.
1138                result.mControllerIdleTimeMs =
1139                        Math.max(0, info.mControllerIdleTimeMs - mLastInfo.mControllerIdleTimeMs);
1140
1141                if (result.mControllerTxTimeMs < 0 ||
1142                        result.mControllerRxTimeMs < 0) {
1143                    // The stats were reset by the WiFi system (which is why our delta is negative).
1144                    // Returns the unaltered stats.
1145                    result.mControllerEnergyUsed = info.mControllerEnergyUsed;
1146                    result.mControllerRxTimeMs = info.mControllerRxTimeMs;
1147                    result.mControllerTxTimeMs = info.mControllerTxTimeMs;
1148                    result.mControllerIdleTimeMs = info.mControllerIdleTimeMs;
1149
1150                    Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result);
1151                }
1152                mLastInfo = info;
1153                return result;
1154            }
1155        } catch (RemoteException e) {
1156            // Nothing to report, WiFi is dead.
1157        }
1158        return null;
1159    }
1160
1161    @GuardedBy("mExternalStatsLock")
1162    private BluetoothActivityEnergyInfo pullBluetoothEnergyInfoLocked() {
1163        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1164        if (adapter != null) {
1165            BluetoothActivityEnergyInfo info = adapter.getControllerActivityEnergyInfo(
1166                    BluetoothAdapter.ACTIVITY_ENERGY_INFO_REFRESHED);
1167            if (info != null && info.isValid()) {
1168                return info;
1169            }
1170        }
1171        return null;
1172    }
1173
1174    /**
1175     * Fetches data from external sources (WiFi controller, bluetooth chipset) and updates
1176     * batterystats with that information.
1177     *
1178     * We first grab a lock specific to this method, then once all the data has been collected,
1179     * we grab the mStats lock and update the data.
1180     */
1181    void updateExternalStats() {
1182        synchronized (mExternalStatsLock) {
1183            if (mContext == null) {
1184                // We haven't started yet (which means the BatteryStatsImpl object has
1185                // no power profile. Don't consume data we can't compute yet.
1186                return;
1187            }
1188
1189            final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked();
1190            final BluetoothActivityEnergyInfo bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
1191            synchronized (mStats) {
1192                mStats.updateKernelWakelocksLocked();
1193                mStats.updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
1194                mStats.updateWifiStateLocked(wifiEnergyInfo);
1195                mStats.updateBluetoothStateLocked(bluetoothEnergyInfo);
1196            }
1197        }
1198    }
1199}
1200