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