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