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