BatteryStatsService.java revision e95c3cd89591ba586aa8a0f7a17660c6fb8770bc
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.Process;
31import android.os.ServiceManager;
32import android.os.SystemClock;
33import android.os.UserHandle;
34import android.os.WorkSource;
35import android.telephony.DataConnectionRealTimeInfo;
36import android.telephony.SignalStrength;
37import android.telephony.TelephonyManager;
38import android.util.Slog;
39
40import com.android.internal.app.IBatteryStats;
41import com.android.internal.os.BatteryStatsImpl;
42import com.android.internal.os.PowerProfile;
43
44import java.io.FileDescriptor;
45import java.io.PrintWriter;
46import java.util.List;
47
48/**
49 * All information we are collecting about things that can happen that impact
50 * battery life.
51 */
52public final class BatteryStatsService extends IBatteryStats.Stub {
53    static final String TAG = "BatteryStatsService";
54
55    static IBatteryStats sService;
56
57    final BatteryStatsImpl mStats;
58    Context mContext;
59    private boolean mBluetoothPendingStats;
60    private BluetoothHeadset mBluetoothHeadset;
61
62    BatteryStatsService(String filename, Handler handler) {
63        mStats = new BatteryStatsImpl(filename, handler);
64    }
65
66    public void publish(Context context) {
67        mContext = context;
68        ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
69        mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
70        mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
71                com.android.internal.R.integer.config_radioScanningTimeout)
72                * 1000L);
73        (new WakeupReasonThread()).start();
74     }
75
76    public void shutdown() {
77        Slog.w("BatteryStats", "Writing battery stats before shutdown...");
78        synchronized (mStats) {
79            mStats.shutdownLocked();
80        }
81    }
82
83    public static IBatteryStats getService() {
84        if (sService != null) {
85            return sService;
86        }
87        IBinder b = ServiceManager.getService(BatteryStats.SERVICE_NAME);
88        sService = asInterface(b);
89        return sService;
90    }
91
92    /**
93     * @return the current statistics object, which may be modified
94     * to reflect events that affect battery usage.  You must lock the
95     * stats object before doing anything with it.
96     */
97    public BatteryStatsImpl getActiveStatistics() {
98        return mStats;
99    }
100
101    public byte[] getStatistics() {
102        mContext.enforceCallingPermission(
103                android.Manifest.permission.BATTERY_STATS, null);
104        //Slog.i("foo", "SENDING BATTERY INFO:");
105        //mStats.dumpLocked(new LogPrinter(Log.INFO, "foo", Log.LOG_ID_SYSTEM));
106        Parcel out = Parcel.obtain();
107        mStats.writeToParcel(out, 0);
108        byte[] data = out.marshall();
109        out.recycle();
110        return data;
111    }
112
113    public long computeBatteryTimeRemaining() {
114        synchronized (mStats) {
115            long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
116            return time >= 0 ? (time/1000) : time;
117        }
118    }
119
120    public long computeChargeTimeRemaining() {
121        synchronized (mStats) {
122            long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
123            return time >= 0 ? (time/1000) : time;
124        }
125    }
126
127    public void addIsolatedUid(int isolatedUid, int appUid) {
128        enforceCallingPermission();
129        synchronized (mStats) {
130            mStats.addIsolatedUidLocked(isolatedUid, appUid);
131        }
132    }
133
134    public void removeIsolatedUid(int isolatedUid, int appUid) {
135        enforceCallingPermission();
136        synchronized (mStats) {
137            mStats.removeIsolatedUidLocked(isolatedUid, appUid);
138        }
139    }
140
141    public void noteEvent(int code, String name, int uid) {
142        enforceCallingPermission();
143        synchronized (mStats) {
144            mStats.noteEventLocked(code, name, uid);
145        }
146    }
147
148    public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
149            boolean unimportantForLogging) {
150        enforceCallingPermission();
151        synchronized (mStats) {
152            mStats.noteStartWakeLocked(uid, pid, name, historyName, type, unimportantForLogging,
153                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
154        }
155    }
156
157    public void noteStopWakelock(int uid, int pid, String name, int type) {
158        enforceCallingPermission();
159        synchronized (mStats) {
160            mStats.noteStopWakeLocked(uid, pid, name, type, SystemClock.elapsedRealtime(),
161                    SystemClock.uptimeMillis());
162        }
163    }
164
165    public void noteStartWakelockFromSource(WorkSource ws, int pid, String name,
166            String historyName, int type, boolean unimportantForLogging) {
167        enforceCallingPermission();
168        synchronized (mStats) {
169            mStats.noteStartWakeFromSourceLocked(ws, pid, name, historyName,
170                    type, unimportantForLogging);
171        }
172    }
173
174    public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name, int type,
175            WorkSource newWs, int newPid, String newName,
176            String newHistoryName, int newType, boolean newUnimportantForLogging) {
177        enforceCallingPermission();
178        synchronized (mStats) {
179            mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, type,
180                    newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
181        }
182    }
183
184    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) {
185        enforceCallingPermission();
186        synchronized (mStats) {
187            mStats.noteStopWakeFromSourceLocked(ws, pid, name, type);
188        }
189    }
190
191    public void noteStartSensor(int uid, int sensor) {
192        enforceCallingPermission();
193        synchronized (mStats) {
194            mStats.noteStartSensorLocked(uid, sensor);
195        }
196    }
197
198    public void noteStopSensor(int uid, int sensor) {
199        enforceCallingPermission();
200        synchronized (mStats) {
201            mStats.noteStopSensorLocked(uid, sensor);
202        }
203    }
204
205    public void noteVibratorOn(int uid, long durationMillis) {
206        enforceCallingPermission();
207        synchronized (mStats) {
208            mStats.noteVibratorOnLocked(uid, durationMillis);
209        }
210    }
211
212    public void noteVibratorOff(int uid) {
213        enforceCallingPermission();
214        synchronized (mStats) {
215            mStats.noteVibratorOffLocked(uid);
216        }
217    }
218
219    public void noteStartGps(int uid) {
220        enforceCallingPermission();
221        synchronized (mStats) {
222            mStats.noteStartGpsLocked(uid);
223        }
224    }
225
226    public void noteStopGps(int uid) {
227        enforceCallingPermission();
228        synchronized (mStats) {
229            mStats.noteStopGpsLocked(uid);
230        }
231    }
232
233    public void noteScreenState(int state) {
234        enforceCallingPermission();
235        synchronized (mStats) {
236            mStats.noteScreenStateLocked(state);
237        }
238    }
239
240    public void noteScreenBrightness(int brightness) {
241        enforceCallingPermission();
242        synchronized (mStats) {
243            mStats.noteScreenBrightnessLocked(brightness);
244        }
245    }
246
247    public void noteUserActivity(int uid, int event) {
248        enforceCallingPermission();
249        synchronized (mStats) {
250            mStats.noteUserActivityLocked(uid, event);
251        }
252    }
253
254    public void noteInteractive(boolean interactive) {
255        enforceCallingPermission();
256        synchronized (mStats) {
257            mStats.noteInteractiveLocked(interactive);
258        }
259    }
260
261    public void noteMobileRadioPowerState(int powerState, long timestampNs) {
262        enforceCallingPermission();
263        synchronized (mStats) {
264            mStats.noteMobileRadioPowerState(powerState, timestampNs);
265        }
266    }
267
268    public void notePhoneOn() {
269        enforceCallingPermission();
270        synchronized (mStats) {
271            mStats.notePhoneOnLocked();
272        }
273    }
274
275    public void notePhoneOff() {
276        enforceCallingPermission();
277        synchronized (mStats) {
278            mStats.notePhoneOffLocked();
279        }
280    }
281
282    public void notePhoneSignalStrength(SignalStrength signalStrength) {
283        enforceCallingPermission();
284        synchronized (mStats) {
285            mStats.notePhoneSignalStrengthLocked(signalStrength);
286        }
287    }
288
289    public void notePhoneDataConnectionState(int dataType, boolean hasData) {
290        enforceCallingPermission();
291        synchronized (mStats) {
292            mStats.notePhoneDataConnectionStateLocked(dataType, hasData);
293        }
294    }
295
296    public void notePhoneState(int state) {
297        enforceCallingPermission();
298        int simState = TelephonyManager.getDefault().getSimState();
299        synchronized (mStats) {
300            mStats.notePhoneStateLocked(state, simState);
301        }
302    }
303
304    public void noteWifiOn() {
305        enforceCallingPermission();
306        synchronized (mStats) {
307            mStats.noteWifiOnLocked();
308        }
309    }
310
311    public void noteWifiOff() {
312        enforceCallingPermission();
313        synchronized (mStats) {
314            mStats.noteWifiOffLocked();
315        }
316    }
317
318    public void noteStartAudio(int uid) {
319        enforceCallingPermission();
320        synchronized (mStats) {
321            mStats.noteAudioOnLocked(uid);
322        }
323    }
324
325    public void noteStopAudio(int uid) {
326        enforceCallingPermission();
327        synchronized (mStats) {
328            mStats.noteAudioOffLocked(uid);
329        }
330    }
331
332    public void noteStartVideo(int uid) {
333        enforceCallingPermission();
334        synchronized (mStats) {
335            mStats.noteVideoOnLocked(uid);
336        }
337    }
338
339    public void noteStopVideo(int uid) {
340        enforceCallingPermission();
341        synchronized (mStats) {
342            mStats.noteVideoOffLocked(uid);
343        }
344    }
345
346    public void noteWifiRunning(WorkSource ws) {
347        enforceCallingPermission();
348        synchronized (mStats) {
349            mStats.noteWifiRunningLocked(ws);
350        }
351    }
352
353    public void noteWifiRunningChanged(WorkSource oldWs, WorkSource newWs) {
354        enforceCallingPermission();
355        synchronized (mStats) {
356            mStats.noteWifiRunningChangedLocked(oldWs, newWs);
357        }
358    }
359
360    public void noteWifiStopped(WorkSource ws) {
361        enforceCallingPermission();
362        synchronized (mStats) {
363            mStats.noteWifiStoppedLocked(ws);
364        }
365    }
366
367    public void noteWifiState(int wifiState, String accessPoint) {
368        enforceCallingPermission();
369        synchronized (mStats) {
370            mStats.noteWifiStateLocked(wifiState, accessPoint);
371        }
372    }
373
374    public void noteBluetoothOn() {
375        enforceCallingPermission();
376        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
377        if (adapter != null) {
378            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
379                                    BluetoothProfile.HEADSET);
380        }
381        synchronized (mStats) {
382            if (mBluetoothHeadset != null) {
383                mStats.noteBluetoothOnLocked();
384                mStats.setBtHeadset(mBluetoothHeadset);
385            } else {
386                mBluetoothPendingStats = true;
387            }
388        }
389    }
390
391    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
392        new BluetoothProfile.ServiceListener() {
393        public void onServiceConnected(int profile, BluetoothProfile proxy) {
394            mBluetoothHeadset = (BluetoothHeadset) proxy;
395            synchronized (mStats) {
396                if (mBluetoothPendingStats) {
397                    mStats.noteBluetoothOnLocked();
398                    mStats.setBtHeadset(mBluetoothHeadset);
399                    mBluetoothPendingStats = false;
400                }
401            }
402        }
403
404        public void onServiceDisconnected(int profile) {
405            mBluetoothHeadset = null;
406        }
407    };
408
409    public void noteBluetoothOff() {
410        enforceCallingPermission();
411        synchronized (mStats) {
412            mBluetoothPendingStats = false;
413            mStats.noteBluetoothOffLocked();
414        }
415    }
416
417    public void noteBluetoothState(int bluetoothState) {
418        enforceCallingPermission();
419        synchronized (mStats) {
420            mStats.noteBluetoothStateLocked(bluetoothState);
421        }
422    }
423
424    public void noteFullWifiLockAcquired(int uid) {
425        enforceCallingPermission();
426        synchronized (mStats) {
427            mStats.noteFullWifiLockAcquiredLocked(uid);
428        }
429    }
430
431    public void noteFullWifiLockReleased(int uid) {
432        enforceCallingPermission();
433        synchronized (mStats) {
434            mStats.noteFullWifiLockReleasedLocked(uid);
435        }
436    }
437
438    public void noteWifiScanStarted(int uid) {
439        enforceCallingPermission();
440        synchronized (mStats) {
441            mStats.noteWifiScanStartedLocked(uid);
442        }
443    }
444
445    public void noteWifiScanStopped(int uid) {
446        enforceCallingPermission();
447        synchronized (mStats) {
448            mStats.noteWifiScanStoppedLocked(uid);
449        }
450    }
451
452    public void noteWifiMulticastEnabled(int uid) {
453        enforceCallingPermission();
454        synchronized (mStats) {
455            mStats.noteWifiMulticastEnabledLocked(uid);
456        }
457    }
458
459    public void noteWifiMulticastDisabled(int uid) {
460        enforceCallingPermission();
461        synchronized (mStats) {
462            mStats.noteWifiMulticastDisabledLocked(uid);
463        }
464    }
465
466    public void noteFullWifiLockAcquiredFromSource(WorkSource ws) {
467        enforceCallingPermission();
468        synchronized (mStats) {
469            mStats.noteFullWifiLockAcquiredFromSourceLocked(ws);
470        }
471    }
472
473    public void noteFullWifiLockReleasedFromSource(WorkSource ws) {
474        enforceCallingPermission();
475        synchronized (mStats) {
476            mStats.noteFullWifiLockReleasedFromSourceLocked(ws);
477        }
478    }
479
480    public void noteWifiScanStartedFromSource(WorkSource ws) {
481        enforceCallingPermission();
482        synchronized (mStats) {
483            mStats.noteWifiScanStartedFromSourceLocked(ws);
484        }
485    }
486
487    public void noteWifiScanStoppedFromSource(WorkSource ws) {
488        enforceCallingPermission();
489        synchronized (mStats) {
490            mStats.noteWifiScanStoppedFromSourceLocked(ws);
491        }
492    }
493
494    public void noteWifiBatchedScanStartedFromSource(WorkSource ws, int csph) {
495        enforceCallingPermission();
496        synchronized (mStats) {
497            mStats.noteWifiBatchedScanStartedFromSourceLocked(ws, csph);
498        }
499    }
500
501    public void noteWifiBatchedScanStoppedFromSource(WorkSource ws) {
502        enforceCallingPermission();
503        synchronized (mStats) {
504            mStats.noteWifiBatchedScanStoppedFromSourceLocked(ws);
505        }
506    }
507
508    public void noteWifiMulticastEnabledFromSource(WorkSource ws) {
509        enforceCallingPermission();
510        synchronized (mStats) {
511            mStats.noteWifiMulticastEnabledFromSourceLocked(ws);
512        }
513    }
514
515    public void noteWifiMulticastDisabledFromSource(WorkSource ws) {
516        enforceCallingPermission();
517        synchronized (mStats) {
518            mStats.noteWifiMulticastDisabledFromSourceLocked(ws);
519        }
520    }
521
522    @Override
523    public void noteNetworkInterfaceType(String iface, int type) {
524        enforceCallingPermission();
525        synchronized (mStats) {
526            mStats.noteNetworkInterfaceTypeLocked(iface, type);
527        }
528    }
529
530    @Override
531    public void noteNetworkStatsEnabled() {
532        enforceCallingPermission();
533        synchronized (mStats) {
534            mStats.noteNetworkStatsEnabledLocked();
535        }
536    }
537
538    public boolean isOnBattery() {
539        return mStats.isOnBattery();
540    }
541
542    public void setBatteryState(int status, int health, int plugType, int level,
543            int temp, int volt) {
544        enforceCallingPermission();
545        mStats.setBatteryState(status, health, plugType, level, temp, volt);
546    }
547
548    public long getAwakeTimeBattery() {
549        mContext.enforceCallingOrSelfPermission(
550                android.Manifest.permission.BATTERY_STATS, null);
551        return mStats.getAwakeTimeBattery();
552    }
553
554    public long getAwakeTimePlugged() {
555        mContext.enforceCallingOrSelfPermission(
556                android.Manifest.permission.BATTERY_STATS, null);
557        return mStats.getAwakeTimePlugged();
558    }
559
560    public void enforceCallingPermission() {
561        if (Binder.getCallingPid() == Process.myPid()) {
562            return;
563        }
564        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
565                Binder.getCallingPid(), Binder.getCallingUid(), null);
566    }
567
568    final class WakeupReasonThread extends Thread {
569        final int[] mIrqs = new int[32];
570        final String[] mReasons = new String[32];
571
572        WakeupReasonThread() {
573            super("BatteryStats_wakeupReason");
574        }
575
576        public void run() {
577            Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
578
579            try {
580                int num;
581                while ((num=nativeWaitWakeup(mIrqs, mReasons)) >= 0) {
582                    synchronized (mStats) {
583                        if (num > 0) {
584                            for (int i=0; i<num; i++) {
585                                mStats.noteWakeupReasonLocked(mReasons[i]);
586                            }
587                        } else {
588                            mStats.noteWakeupReasonLocked("unknown");
589                        }
590                    }
591                }
592            } catch (RuntimeException e) {
593                Slog.e(TAG, "Failure reading wakeup reasons", e);
594            }
595        }
596    }
597
598    private static native int nativeWaitWakeup(int[] outIrqs, String[] outReasons);
599
600    private void dumpHelp(PrintWriter pw) {
601        pw.println("Battery stats (batterystats) dump options:");
602        pw.println("  [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]");
603        pw.println("  [--reset] [--write] [-h] [<package.name>]");
604        pw.println("  --checkin: format output for a checkin report.");
605        pw.println("  --history: show only history data.");
606        pw.println("  --history-start <num>: show only history data starting at given time offset.");
607        pw.println("  --unplugged: only output data since last unplugged.");
608        pw.println("  --charged: only output data since last charged.");
609        pw.println("  --reset: reset the stats, clearing all current data.");
610        pw.println("  --write: force write current collected stats to disk.");
611        pw.println("  -h: print this help text.");
612        pw.println("  <package.name>: optional name of package to filter output by.");
613    }
614
615    @Override
616    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
617        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
618                != PackageManager.PERMISSION_GRANTED) {
619            pw.println("Permission Denial: can't dump BatteryStats from from pid="
620                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
621                    + " without permission " + android.Manifest.permission.DUMP);
622            return;
623        }
624
625        int flags = 0;
626        boolean isCheckin = false;
627        boolean noOutput = false;
628        long historyStart = -1;
629        int reqUid = -1;
630        if (args != null) {
631            for (int i=0; i<args.length; i++) {
632                String arg = args[i];
633                if ("--checkin".equals(arg)) {
634                    isCheckin = true;
635                } else if ("--history".equals(arg)) {
636                    flags |= BatteryStats.DUMP_HISTORY_ONLY;
637                } else if ("--history-start".equals(arg)) {
638                    flags |= BatteryStats.DUMP_HISTORY_ONLY;
639                    i++;
640                    if (i >= args.length) {
641                        pw.println("Missing time argument for --history-since");
642                        dumpHelp(pw);
643                        return;
644                    }
645                    historyStart = Long.parseLong(args[i]);
646                } else if ("-c".equals(arg)) {
647                    isCheckin = true;
648                    flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
649                } else if ("--unplugged".equals(arg)) {
650                    flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
651                } else if ("--charged".equals(arg)) {
652                    flags |= BatteryStats.DUMP_CHARGED_ONLY;
653                } else if ("--reset".equals(arg)) {
654                    synchronized (mStats) {
655                        mStats.resetAllStatsCmdLocked();
656                        pw.println("Battery stats reset.");
657                        noOutput = true;
658                    }
659                } else if ("--write".equals(arg)) {
660                    synchronized (mStats) {
661                        mStats.writeSyncLocked();
662                        pw.println("Battery stats written.");
663                        noOutput = true;
664                    }
665                } else if ("-h".equals(arg)) {
666                    dumpHelp(pw);
667                    return;
668                } else if ("-a".equals(arg)) {
669                    flags |= BatteryStats.DUMP_VERBOSE;
670                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
671                    pw.println("Unknown option: " + arg);
672                    dumpHelp(pw);
673                    return;
674                } else {
675                    // Not an option, last argument must be a package name.
676                    try {
677                        reqUid = mContext.getPackageManager().getPackageUid(arg,
678                                UserHandle.getCallingUserId());
679                    } catch (PackageManager.NameNotFoundException e) {
680                        pw.println("Unknown package: " + arg);
681                        dumpHelp(pw);
682                        return;
683                    }
684                }
685            }
686        }
687        if (noOutput) {
688            return;
689        }
690        if (isCheckin) {
691            List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
692            synchronized (mStats) {
693                mStats.dumpCheckinLocked(mContext, pw, apps, flags, historyStart);
694            }
695        } else {
696            synchronized (mStats) {
697                mStats.dumpLocked(mContext, pw, flags, reqUid, historyStart);
698            }
699        }
700    }
701}
702