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