BatteryStatsService.java revision d953c53d3b04d772bb1b62ede1c2011641ca82b5
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.BluetoothAdapter;
20import android.bluetooth.BluetoothHeadset;
21import android.bluetooth.BluetoothProfile;
22import android.content.Context;
23import android.content.pm.ApplicationInfo;
24import android.content.pm.PackageManager;
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.PowerManagerInternal;
32import android.os.Process;
33import android.os.ServiceManager;
34import android.os.SystemClock;
35import android.os.UserHandle;
36import android.os.WorkSource;
37import android.telephony.SignalStrength;
38import android.telephony.TelephonyManager;
39import android.util.Slog;
40
41import com.android.internal.app.IBatteryStats;
42import com.android.internal.os.BatteryStatsHelper;
43import com.android.internal.os.BatteryStatsImpl;
44import com.android.internal.os.PowerProfile;
45import com.android.server.LocalServices;
46
47import java.io.File;
48import java.io.FileDescriptor;
49import java.io.FileOutputStream;
50import java.io.IOException;
51import java.io.PrintWriter;
52import java.util.List;
53
54/**
55 * All information we are collecting about things that can happen that impact
56 * battery life.
57 */
58public final class BatteryStatsService extends IBatteryStats.Stub
59        implements PowerManagerInternal.LowPowerModeListener {
60    static final String TAG = "BatteryStatsService";
61
62    static IBatteryStats sService;
63
64    final BatteryStatsImpl mStats;
65    Context mContext;
66    private boolean mBluetoothPendingStats;
67    private BluetoothHeadset mBluetoothHeadset;
68    PowerManagerInternal mPowerManagerInternal;
69
70    BatteryStatsService(File systemDir, Handler handler) {
71        mStats = new BatteryStatsImpl(systemDir, handler);
72    }
73
74    public void publish(Context context) {
75        mContext = context;
76        ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
77        mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
78        mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
79                com.android.internal.R.integer.config_radioScanningTimeout)
80                * 1000L);
81    }
82
83    /**
84     * At the time when the constructor runs, the power manager has not yet been
85     * initialized.  So we initialize the low power observer later.
86     */
87    public void initPowerManagement() {
88        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
89        mPowerManagerInternal.registerLowPowerModeObserver(this);
90        mStats.noteLowPowerMode(mPowerManagerInternal.getLowPowerModeEnabled());
91        (new WakeupReasonThread()).start();
92    }
93
94    public void shutdown() {
95        Slog.w("BatteryStats", "Writing battery stats before shutdown...");
96        synchronized (mStats) {
97            mStats.shutdownLocked();
98        }
99    }
100
101    public static IBatteryStats getService() {
102        if (sService != null) {
103            return sService;
104        }
105        IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME);
106        sService = asInterface(b);
107        return sService;
108    }
109
110    @Override
111    public void onLowPowerModeChanged(boolean enabled) {
112        synchronized (mStats) {
113            mStats.noteLowPowerMode(enabled);
114        }
115    }
116
117    /**
118     * @return the current statistics object, which may be modified
119     * to reflect events that affect battery usage.  You must lock the
120     * stats object before doing anything with it.
121     */
122    public BatteryStatsImpl getActiveStatistics() {
123        return mStats;
124    }
125
126    public byte[] getStatistics() {
127        mContext.enforceCallingPermission(
128                android.Manifest.permission.BATTERY_STATS, null);
129        //Slog.i("foo", "SENDING BATTERY INFO:");
130        //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
131        Parcel out = Parcel.obtain();
132        mStats.writeToParcel(out, 0);
133        byte[] data = out.marshall();
134        out.recycle();
135        return data;
136    }
137
138    public ParcelFileDescriptor getStatisticsStream() {
139        mContext.enforceCallingPermission(
140                android.Manifest.permission.BATTERY_STATS, null);
141        //Slog.i("foo", "SENDING BATTERY INFO:");
142        //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
143        Parcel out = Parcel.obtain();
144        mStats.writeToParcel(out, 0);
145        byte[] data = out.marshall();
146        out.recycle();
147        try {
148            return ParcelFileDescriptor.fromData(data, "battery-stats");
149        } catch (IOException e) {
150            Slog.w(TAG, "Unable to create shared memory", e);
151            return null;
152        }
153    }
154
155    public long computeBatteryTimeRemaining() {
156        synchronized (mStats) {
157            long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
158            return time >= 0 ? (time/1000) : time;
159        }
160    }
161
162    public long computeChargeTimeRemaining() {
163        synchronized (mStats) {
164            long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
165            return time >= 0 ? (time/1000) : time;
166        }
167    }
168
169    public void addIsolatedUid(int isolatedUid, int appUid) {
170        enforceCallingPermission();
171        synchronized (mStats) {
172            mStats.addIsolatedUidLocked(isolatedUid, appUid);
173        }
174    }
175
176    public void removeIsolatedUid(int isolatedUid, int appUid) {
177        enforceCallingPermission();
178        synchronized (mStats) {
179            mStats.removeIsolatedUidLocked(isolatedUid, appUid);
180        }
181    }
182
183    public void noteEvent(int code, String name, int uid) {
184        enforceCallingPermission();
185        synchronized (mStats) {
186            mStats.noteEventLocked(code, name, uid);
187        }
188    }
189
190    public void noteProcessStart(String name, int uid) {
191        enforceCallingPermission();
192        synchronized (mStats) {
193            mStats.noteProcessStartLocked(name, uid);
194        }
195    }
196
197    public void noteProcessState(String name, int uid, int state) {
198        enforceCallingPermission();
199        synchronized (mStats) {
200            mStats.noteProcessStateLocked(name, uid, state);
201        }
202    }
203
204    public void noteProcessFinish(String name, int uid) {
205        enforceCallingPermission();
206        synchronized (mStats) {
207            mStats.noteProcessFinishLocked(name, uid);
208        }
209    }
210
211    public void noteSyncStart(String name, int uid) {
212        enforceCallingPermission();
213        synchronized (mStats) {
214            mStats.noteSyncStartLocked(name, uid);
215        }
216    }
217
218    public void noteSyncFinish(String name, int uid) {
219        enforceCallingPermission();
220        synchronized (mStats) {
221            mStats.noteSyncFinishLocked(name, uid);
222        }
223    }
224
225    public void noteJobStart(String name, int uid) {
226        enforceCallingPermission();
227        synchronized (mStats) {
228            mStats.noteJobStartLocked(name, uid);
229        }
230    }
231
232    public void noteJobFinish(String name, int uid) {
233        enforceCallingPermission();
234        synchronized (mStats) {
235            mStats.noteJobFinishLocked(name, uid);
236        }
237    }
238
239    public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
240            boolean unimportantForLogging) {
241        enforceCallingPermission();
242        synchronized (mStats) {
243            mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging,
244                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
245        }
246    }
247
248    public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) {
249        enforceCallingPermission();
250        synchronized (mStats) {
251            mStats.noteStopWakeLocked(uid, pid, name, historyName, type,
252                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
253        }
254    }
255
256    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name,
257            String historyName, int type, boolean unimportantForLogging) {
258        enforceCallingPermission();
259        synchronized (mStats) {
260            mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
261                    type, unimportantForLogging);
262        }
263    }
264
265    public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name,
266            String historyName, int type, WorkSource newWs, int newPid, String newName,
267            String newHistoryName, int newType, boolean newUnimportantForLogging) {
268        enforceCallingPermission();
269        synchronized (mStats) {
270            mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
271                    newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
272        }
273    }
274
275    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName,
276            int type) {
277        enforceCallingPermission();
278        synchronized (mStats) {
279            mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type);
280        }
281    }
282
283    public void noteStartSensor(int uid, int sensor) {
284        enforceCallingPermission();
285        synchronized (mStats) {
286            mStats.noteStartSensorLocked(uid, sensor);
287        }
288    }
289
290    public void noteStopSensor(int uid, int sensor) {
291        enforceCallingPermission();
292        synchronized (mStats) {
293            mStats.noteStopSensorLocked(uid, sensor);
294        }
295    }
296
297    public void noteVibratorOn(int uid, long durationMillis) {
298        enforceCallingPermission();
299        synchronized (mStats) {
300            mStats.noteVibratorOnLocked(uid, durationMillis);
301        }
302    }
303
304    public void noteVibratorOff(int uid) {
305        enforceCallingPermission();
306        synchronized (mStats) {
307            mStats.noteVibratorOffLocked(uid);
308        }
309    }
310
311    public void noteStartGps(int uid) {
312        enforceCallingPermission();
313        synchronized (mStats) {
314            mStats.noteStartGpsLocked(uid);
315        }
316    }
317
318    public void noteStopGps(int uid) {
319        enforceCallingPermission();
320        synchronized (mStats) {
321            mStats.noteStopGpsLocked(uid);
322        }
323    }
324
325    public void noteScreenState(int state) {
326        enforceCallingPermission();
327        synchronized (mStats) {
328            mStats.noteScreenStateLocked(state);
329        }
330    }
331
332    public void noteScreenBrightness(int brightness) {
333        enforceCallingPermission();
334        synchronized (mStats) {
335            mStats.noteScreenBrightnessLocked(brightness);
336        }
337    }
338
339    public void noteUserActivity(int uid, int event) {
340        enforceCallingPermission();
341        synchronized (mStats) {
342            mStats.noteUserActivityLocked(uid, event);
343        }
344    }
345
346    public void noteInteractive(boolean interactive) {
347        enforceCallingPermission();
348        synchronized (mStats) {
349            mStats.noteInteractiveLocked(interactive);
350        }
351    }
352
353    public void noteMobileRadioPowerState(int powerState, long timestampNs) {
354        enforceCallingPermission();
355        synchronized (mStats) {
356            mStats.noteMobileRadioPowerState(powerState, timestampNs);
357        }
358    }
359
360    public void notePhoneOn() {
361        enforceCallingPermission();
362        synchronized (mStats) {
363            mStats.notePhoneOnLocked();
364        }
365    }
366
367    public void notePhoneOff() {
368        enforceCallingPermission();
369        synchronized (mStats) {
370            mStats.notePhoneOffLocked();
371        }
372    }
373
374    public void notePhoneSignalStrength(SignalStrength signalStrength) {
375        enforceCallingPermission();
376        synchronized (mStats) {
377            mStats.notePhoneSignalStrengthLocked(signalStrength);
378        }
379    }
380
381    public void notePhoneDataConnectionState(int dataType, boolean hasData) {
382        enforceCallingPermission();
383        synchronized (mStats) {
384            mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
385        }
386    }
387
388    public void notePhoneState(int state) {
389        enforceCallingPermission();
390        int simState = TelephonyManager.getDefault().getSimState();
391        synchronized (mStats) {
392            mStats.notePhoneStateLocked(state, simState);
393        }
394    }
395
396    public void noteWifiOn() {
397        enforceCallingPermission();
398        synchronized (mStats) {
399            mStats.noteWifiOnLocked();
400        }
401    }
402
403    public void noteWifiOff() {
404        enforceCallingPermission();
405        synchronized (mStats) {
406            mStats.noteWifiOffLocked();
407        }
408    }
409
410    public void noteStartAudio(int uid) {
411        enforceCallingPermission();
412        synchronized (mStats) {
413            mStats.noteAudioOnLocked(uid);
414        }
415    }
416
417    public void noteStopAudio(int uid) {
418        enforceCallingPermission();
419        synchronized (mStats) {
420            mStats.noteAudioOffLocked(uid);
421        }
422    }
423
424    public void noteStartVideo(int uid) {
425        enforceCallingPermission();
426        synchronized (mStats) {
427            mStats.noteVideoOnLocked(uid);
428        }
429    }
430
431    public void noteStopVideo(int uid) {
432        enforceCallingPermission();
433        synchronized (mStats) {
434            mStats.noteVideoOffLocked(uid);
435        }
436    }
437
438    public void noteResetAudio() {
439        enforceCallingPermission();
440        synchronized (mStats) {
441            mStats.noteResetAudioLocked();
442        }
443    }
444
445    public void noteResetVideo() {
446        enforceCallingPermission();
447        synchronized (mStats) {
448            mStats.noteResetVideoLocked();
449        }
450    }
451
452    public void noteFlashlightOn() {
453        enforceCallingPermission();
454        synchronized (mStats) {
455            mStats.noteFlashlightOnLocked();
456        }
457    }
458
459    public void noteFlashlightOff() {
460        enforceCallingPermission();
461        synchronized (mStats) {
462            mStats.noteFlashlightOffLocked();
463        }
464    }
465
466    public void noteWifiRunning(WorkSource ws) {
467        enforceCallingPermission();
468        synchronized (mStats) {
469            mStats.noteWifiRunningLocked(ws);
470        }
471    }
472
473    public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
474        enforceCallingPermission();
475        synchronized (mStats) {
476            mStats.noteWifiRunningChangedLocked(oldWs, newWs);
477        }
478    }
479
480    public void noteWifiStopped(WorkSource ws) {
481        enforceCallingPermission();
482        synchronized (mStats) {
483            mStats.noteWifiStoppedLocked(ws);
484        }
485    }
486
487    public void noteWifiState(int wifiState, String accessPoint) {
488        enforceCallingPermission();
489        synchronized (mStats) {
490            mStats.noteWifiStateLocked(wifiState, accessPoint);
491        }
492    }
493
494    public void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth) {
495        enforceCallingPermission();
496        synchronized (mStats) {
497            mStats.noteWifiSupplicantStateChangedLocked(supplState, failedAuth);
498        }
499    }
500
501    public void noteWifiRssiChanged(int newRssi) {
502        enforceCallingPermission();
503        synchronized (mStats) {
504            mStats.noteWifiRssiChangedLocked(newRssi);
505        }
506    }
507
508    public void noteBluetoothOn() {
509        enforceCallingPermission();
510        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
511        if (adapter != null) {
512            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
513                                    BluetoothProfile.HEADSET);
514        }
515        synchronized (mStats) {
516            if (mBluetoothHeadset != null) {
517                mStats.noteBluetoothOnLocked();
518                mStats.setBtHeadset(mBluetoothHeadset);
519            } else {
520                mBluetoothPendingStats = true;
521            }
522        }
523    }
524
525    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
526        new BluetoothProfile.ServiceListener() {
527        public void onServiceConnected(int profile, BluetoothProfile proxy) {
528            mBluetoothHeadset = (BluetoothHeadset) proxy;
529            synchronized (mStats) {
530                if (mBluetoothPendingStats) {
531                    mStats.noteBluetoothOnLocked();
532                    mStats.setBtHeadset(mBluetoothHeadset);
533                    mBluetoothPendingStats = false;
534                }
535            }
536        }
537
538        public void onServiceDisconnected(int profile) {
539            mBluetoothHeadset = null;
540        }
541    };
542
543    public void noteBluetoothOff() {
544        enforceCallingPermission();
545        synchronized (mStats) {
546            mBluetoothPendingStats = false;
547            mStats.noteBluetoothOffLocked();
548        }
549    }
550
551    public void noteBluetoothState(int bluetoothState) {
552        enforceCallingPermission();
553        synchronized (mStats) {
554            mStats.noteBluetoothStateLocked(bluetoothState);
555        }
556    }
557
558    public void noteFullWifiLockAcquired(int uid) {
559        enforceCallingPermission();
560        synchronized (mStats) {
561            mStats.noteFullWifiLockAcquiredLocked(uid);
562        }
563    }
564
565    public void noteFullWifiLockReleased(int uid) {
566        enforceCallingPermission();
567        synchronized (mStats) {
568            mStats.noteFullWifiLockReleasedLocked(uid);
569        }
570    }
571
572    public void noteWifiScanStarted(int uid) {
573        enforceCallingPermission();
574        synchronized (mStats) {
575            mStats.noteWifiScanStartedLocked(uid);
576        }
577    }
578
579    public void noteWifiScanStopped(int uid) {
580        enforceCallingPermission();
581        synchronized (mStats) {
582            mStats.noteWifiScanStoppedLocked(uid);
583        }
584    }
585
586    public void noteWifiMulticastEnabled(int uid) {
587        enforceCallingPermission();
588        synchronized (mStats) {
589            mStats.noteWifiMulticastEnabledLocked(uid);
590        }
591    }
592
593    public void noteWifiMulticastDisabled(int uid) {
594        enforceCallingPermission();
595        synchronized (mStats) {
596            mStats.noteWifiMulticastDisabledLocked(uid);
597        }
598    }
599
600    public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
601        enforceCallingPermission();
602        synchronized (mStats) {
603            mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
604        }
605    }
606
607    public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
608        enforceCallingPermission();
609        synchronized (mStats) {
610            mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
611        }
612    }
613
614    public void noteWifiScanStartedFromSource(WorkSource ws) {
615        enforceCallingPermission();
616        synchronized (mStats) {
617            mStats.noteWifiScanStartedFromSourceLocked(ws);
618        }
619    }
620
621    public void noteWifiScanStoppedFromSource(WorkSource ws) {
622        enforceCallingPermission();
623        synchronized (mStats) {
624            mStats.noteWifiScanStoppedFromSourceLocked(ws);
625        }
626    }
627
628    public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
629        enforceCallingPermission();
630        synchronized (mStats) {
631            mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
632        }
633    }
634
635    public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
636        enforceCallingPermission();
637        synchronized (mStats) {
638            mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
639        }
640    }
641
642    public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
643        enforceCallingPermission();
644        synchronized (mStats) {
645            mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
646        }
647    }
648
649    public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
650        enforceCallingPermission();
651        synchronized (mStats) {
652            mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
653        }
654    }
655
656    @Override
657    public void noteNetworkInterfaceType(String iface, int type) {
658        enforceCallingPermission();
659        synchronized (mStats) {
660            mStats.noteNetworkInterfaceTypeLocked(iface, type);
661        }
662    }
663
664    @Override
665    public void noteNetworkStatsEnabled() {
666        enforceCallingPermission();
667        synchronized (mStats) {
668            mStats.noteNetworkStatsEnabledLocked();
669        }
670    }
671
672    public boolean isOnBattery() {
673        return mStats.isOnBattery();
674    }
675
676    public void setBatteryState(int status, int health, int plugType, int level,
677            int temp, int volt) {
678        enforceCallingPermission();
679        mStats.setBatteryState(status, health, plugType, level, temp, volt);
680    }
681
682    public long getAwakeTimeBattery() {
683        mContext.enforceCallingOrSelfPermission(
684                android.Manifest.permission.BATTERY_STATS, null);
685        return mStats.getAwakeTimeBattery();
686    }
687
688    public long getAwakeTimePlugged() {
689        mContext.enforceCallingOrSelfPermission(
690                android.Manifest.permission.BATTERY_STATS, null);
691        return mStats.getAwakeTimePlugged();
692    }
693
694    public void enforceCallingPermission() {
695        if (Binder.getCallingPid() == Process.myPid()) {
696            return;
697        }
698        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
699                Binder.getCallingPid(), Binder.getCallingUid(), null);
700    }
701
702    final class WakeupReasonThread extends Thread {
703        final int[] mIrqs = new int[32];
704        final String[] mReasons = new String[32];
705
706        WakeupReasonThread() {
707            super("BatteryStats_wakeupReason");
708        }
709
710        public void run() {
711            Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
712
713            try {
714                int num;
715                while ((num=nativeWaitWakeup(mIrqs, mReasons)) >= 0) {
716                    synchronized (mStats) {
717                        if (num > 0) {
718                            for (int i=0; i<num; i++) {
719                                mStats.noteWakeupReasonLocked(mReasons[i]);
720                            }
721                        } else {
722                            mStats.noteWakeupReasonLocked("unknown");
723                        }
724                    }
725                }
726            } catch (RuntimeException e) {
727                Slog.e(TAG, "Failure reading wakeup reasons", e);
728            }
729        }
730    }
731
732    private static native int nativeWaitWakeup(int[] outIrqs, String[] outReasons);
733
734    private void dumpHelp(PrintWriter pw) {
735        pw.println("Battery stats (batterystats) dump options:");
736        pw.println("  [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]");
737        pw.println("  [--reset] [--write] [-h] [<package.name>]");
738        pw.println("  --checkin: format output for a checkin report.");
739        pw.println("  --history: show only history data.");
740        pw.println("  --history-start <num>: show only history data starting at given time offset.");
741        pw.println("  --unplugged: only output data since last unplugged.");
742        pw.println("  --charged: only output data since last charged.");
743        pw.println("  --reset: reset the stats, clearing all current data.");
744        pw.println("  --write: force write current collected stats to disk.");
745        pw.println("  <package.name>: optional name of package to filter output by.");
746        pw.println("  -h: print this help text.");
747        pw.println("Battery stats (batterystats) commands:");
748        pw.println("  enable|disable <option>");
749        pw.println("    Enable or disable a running option.  Option state is not saved across boots.");
750        pw.println("    Options are:");
751        pw.println("      full-history: include additional detailed events in battery history:");
752        pw.println("          wake_lock_in and proc events");
753        pw.println("      no-auto-reset: don't automatically reset stats when unplugged");
754    }
755
756    private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
757        i++;
758        if (i >= args.length) {
759            pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
760            dumpHelp(pw);
761            return -1;
762        }
763        if ("full-wake-history".equals(args[i]) || "full-history".equals(args[i])) {
764            synchronized (mStats) {
765                mStats.setRecordAllHistoryLocked(enable);
766            }
767        } else if ("no-auto-reset".equals(args[i])) {
768            synchronized (mStats) {
769                mStats.setNoAutoReset(enable);
770            }
771        } else {
772            pw.println("Unknown enable/disable option: " + args[i]);
773            dumpHelp(pw);
774            return -1;
775        }
776        return i;
777    }
778
779    @Override
780    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
781        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
782                != PackageManager.PERMISSION_GRANTED) {
783            pw.println("Permission Denial: can't dump BatteryStats from from pid="
784                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
785                    + " without permission " + android.Manifest.permission.DUMP);
786            return;
787        }
788
789        int flags = 0;
790        boolean useCheckinFormat = false;
791        boolean isRealCheckin = false;
792        boolean noOutput = false;
793        boolean writeData = false;
794        long historyStart = -1;
795        int reqUid = -1;
796        if (args != null) {
797            for (int i=0; i<args.length; i++) {
798                String arg = args[i];
799                if ("--checkin".equals(arg)) {
800                    useCheckinFormat = true;
801                    isRealCheckin = true;
802                } else if ("--history".equals(arg)) {
803                    flags |= BatteryStats.DUMP_HISTORY_ONLY;
804                } else if ("--history-start".equals(arg)) {
805                    flags |= BatteryStats.DUMP_HISTORY_ONLY;
806                    i++;
807                    if (i >= args.length) {
808                        pw.println("Missing time argument for --history-since");
809                        dumpHelp(pw);
810                        return;
811                    }
812                    historyStart = Long.parseLong(args[i]);
813                    writeData = true;
814                } else if ("-c".equals(arg)) {
815                    useCheckinFormat = true;
816                    flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
817                } else if ("--unplugged".equals(arg)) {
818                    flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
819                } else if ("--charged".equals(arg)) {
820                    flags |= BatteryStats.DUMP_CHARGED_ONLY;
821                } else if ("--reset".equals(arg)) {
822                    synchronized (mStats) {
823                        mStats.resetAllStatsCmdLocked();
824                        pw.println("Battery stats reset.");
825                        noOutput = true;
826                    }
827                } else if ("--write".equals(arg)) {
828                    synchronized (mStats) {
829                        mStats.writeSyncLocked();
830                        pw.println("Battery stats written.");
831                        noOutput = true;
832                    }
833                } else if ("--enable".equals(arg) || "enable".equals(arg)) {
834                    i = doEnableOrDisable(pw, i, args, true);
835                    if (i < 0) {
836                        return;
837                    }
838                    pw.println("Enabled: " + args[i]);
839                    return;
840                } else if ("--disable".equals(arg) || "disable".equals(arg)) {
841                    i = doEnableOrDisable(pw, i, args, false);
842                    if (i < 0) {
843                        return;
844                    }
845                    pw.println("Disabled: " + args[i]);
846                    return;
847                } else if ("-h".equals(arg)) {
848                    dumpHelp(pw);
849                    return;
850                } else if ("-a".equals(arg)) {
851                    flags |= BatteryStats.DUMP_VERBOSE;
852                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
853                    pw.println("Unknown option: " + arg);
854                    dumpHelp(pw);
855                    return;
856                } else {
857                    // Not an option, last argument must be a package name.
858                    try {
859                        reqUid = mContext.getPackageManager().getPackageUid(arg,
860                                UserHandle.getCallingUserId());
861                    } catch (PackageManager.NameNotFoundException e) {
862                        pw.println("Unknown package: " + arg);
863                        dumpHelp(pw);
864                        return;
865                    }
866                }
867            }
868        }
869        if (noOutput) {
870            return;
871        }
872        if (BatteryStatsHelper.checkWifiOnly(mContext)) {
873            flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
874        }
875        if (useCheckinFormat) {
876            List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
877            if (isRealCheckin) {
878                // For a real checkin, first we want to prefer to use the last complete checkin
879                // file if there is one.
880                synchronized (mStats.mCheckinFile) {
881                    if (mStats.mCheckinFile.exists()) {
882                        try {
883                            byte[] raw = mStats.mCheckinFile.readFully();
884                            if (raw != null) {
885                                Parcel in = Parcel.obtain();
886                                in.unmarshall(raw, 0, raw.length);
887                                in.setDataPosition(0);
888                                BatteryStatsImpl checkinStats = new BatteryStatsImpl(
889                                        null, mStats.mHandler);
890                                checkinStats.readSummaryFromParcel(in);
891                                in.recycle();
892                                checkinStats.dumpCheckinLocked(mContext, pw, apps, flags,
893                                        historyStart);
894                                mStats.mCheckinFile.delete();
895                                return;
896                            }
897                        } catch (IOException e) {
898                            Slog.w(TAG, "Failure reading checkin file "
899                                    + mStats.mCheckinFile.getBaseFile(), e);
900                        }
901                    }
902                }
903            }
904            synchronized (mStats) {
905                mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
906                if (writeData) {
907                    mStats.writeAsyncLocked();
908                }
909            }
910        } else {
911            synchronized (mStats) {
912                mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
913                if (writeData) {
914                    mStats.writeAsyncLocked();
915                }
916            }
917        }
918    }
919}
920