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