BatteryStatsImpl.java revision 3001a035439d8134a7d70d796376d1dfbff3cdcd
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.internal.os;
18
19import android.os.BatteryStats;
20import android.os.NetStat;
21import android.os.Parcel;
22import android.os.ParcelFormatException;
23import android.os.Parcelable;
24import android.os.SystemClock;
25import android.util.Log;
26import android.util.SparseArray;
27
28import java.io.File;
29import java.io.FileInputStream;
30import java.io.FileOutputStream;
31import java.io.IOException;
32import java.util.ArrayList;
33import java.util.HashMap;
34import java.util.Map;
35
36/**
37 * All information we are collecting about things that can happen that impact
38 * battery life.  All times are represented in microseconds except where indicated
39 * otherwise.
40 */
41public final class BatteryStatsImpl extends BatteryStats {
42
43    private static final String TAG = "BatteryStatsImpl";
44
45    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
46    private static final int MAGIC = 0xBA757475; // 'BATSTATS'
47
48    // Current on-disk Parcel version
49    private static final int VERSION = 23;
50
51    private final File mFile;
52    private final File mBackupFile;
53
54    /**
55     * The statistics we have collected organized by uids.
56     */
57    final SparseArray<BatteryStatsImpl.Uid> mUidStats =
58        new SparseArray<BatteryStatsImpl.Uid>();
59
60    // A set of pools of currently active timers.  When a timer is queried, we will divide the
61    // elapsed time by the number of active timers to arrive at that timer's share of the time.
62    // In order to do this, we must refresh each timer whenever the number of active timers
63    // changes.
64    final ArrayList<Timer> mPartialTimers = new ArrayList<Timer>();
65    final ArrayList<Timer> mFullTimers = new ArrayList<Timer>();
66    final ArrayList<Timer> mWindowTimers = new ArrayList<Timer>();
67    final SparseArray<ArrayList<Timer>> mSensorTimers
68            = new SparseArray<ArrayList<Timer>>();
69
70    // These are the objects that will want to do something when the device
71    // is unplugged from power.
72    final ArrayList<Unpluggable> mUnpluggables = new ArrayList<Unpluggable>();
73
74    int mStartCount;
75
76    long mBatteryUptime;
77    long mBatteryLastUptime;
78    long mBatteryRealtime;
79    long mBatteryLastRealtime;
80
81    long mUptime;
82    long mUptimeStart;
83    long mLastUptime;
84    long mRealtime;
85    long mRealtimeStart;
86    long mLastRealtime;
87
88    boolean mScreenOn;
89    long mLastScreenOnTimeMillis;
90    long mBatteryScreenOnTimeMillis;
91    long mPluggedScreenOnTimeMillis;
92    /**
93     * These provide time bases that discount the time the device is plugged
94     * in to power.
95     */
96    boolean mOnBattery;
97    boolean mOnBatteryInternal;
98    long mTrackBatteryPastUptime;
99    long mTrackBatteryUptimeStart;
100    long mTrackBatteryPastRealtime;
101    long mTrackBatteryRealtimeStart;
102
103    long mUnpluggedBatteryUptime;
104    long mUnpluggedBatteryRealtime;
105
106    long mLastWriteTime = 0; // Milliseconds
107
108    // For debugging
109    public BatteryStatsImpl() {
110        mFile = mBackupFile = null;
111    }
112
113    public static interface Unpluggable {
114        void unplug(long batteryUptime, long batteryRealtime);
115        void plug(long batteryUptime, long batteryRealtime);
116    }
117
118    /**
119     * State for keeping track of timing information.
120     */
121    public static final class Timer extends BatteryStats.Timer implements Unpluggable {
122        final int mType;
123        final ArrayList<Timer> mTimerPool;
124
125        int mNesting;
126
127        int mCount;
128        int mLoadedCount;
129        int mLastCount;
130        int mUnpluggedCount;
131
132        // Times are in microseconds for better accuracy when dividing by the
133        // lock count, and are in "battery realtime" units.
134
135        long mTotalTime;
136        long mLoadedTotalTime;
137        long mLastTotalTime;
138        long mUpdateTime;
139
140        /**
141         * The value of mTotalTime when unplug() was last called, initially 0.
142         */
143        long mUnpluggedTotalTime;
144
145        Timer(int type, ArrayList<Timer> timerPool,
146                ArrayList<Unpluggable> unpluggables, Parcel in) {
147            mType = type;
148            mTimerPool = timerPool;
149            mCount = in.readInt();
150            mLoadedCount = in.readInt();
151            mLastCount = in.readInt();
152            mUnpluggedCount = in.readInt();
153            mTotalTime = in.readLong();
154            mLoadedTotalTime = in.readLong();
155            mLastTotalTime = in.readLong();
156            mUpdateTime = in.readLong();
157            mUnpluggedTotalTime = in.readLong();
158            unpluggables.add(this);
159        }
160
161        Timer(int type, ArrayList<Timer> timerPool,
162                ArrayList<Unpluggable> unpluggables) {
163            mType = type;
164            mTimerPool = timerPool;
165            unpluggables.add(this);
166        }
167
168        public void writeToParcel(Parcel out, long batteryRealtime) {
169            out.writeInt(mCount);
170            out.writeInt(mLoadedCount);
171            out.writeInt(mLastCount);
172            out.writeInt(mUnpluggedCount);
173            out.writeLong(computeRunTimeLocked(batteryRealtime));
174            out.writeLong(mLoadedTotalTime);
175            out.writeLong(mLastTotalTime);
176            out.writeLong(mUpdateTime);
177            out.writeLong(mUnpluggedTotalTime);
178        }
179
180        public void unplug(long batteryUptime, long batteryRealtime) {
181            mUnpluggedTotalTime = computeRunTimeLocked(batteryRealtime);
182            mUnpluggedCount = mCount;
183        }
184
185        public void plug(long batteryUptime, long batteryRealtime) {
186            if (mNesting > 0) {
187                mTotalTime = computeRunTimeLocked(batteryRealtime);
188                mUpdateTime = batteryRealtime;
189            }
190        }
191
192        /**
193         * Writes a possibly null Timer to a Parcel.
194         *
195         * @param out the Parcel to be written to.
196         * @param timer a Timer, or null.
197         */
198        public static void writeTimerToParcel(Parcel out, Timer timer,
199                long batteryRealtime) {
200            if (timer == null) {
201                out.writeInt(0); // indicates null
202                return;
203            }
204            out.writeInt(1); // indicates non-null
205
206            timer.writeToParcel(out, batteryRealtime);
207        }
208
209        @Override
210        public long getTotalTime(long now, int which) {
211            long val;
212            if (which == STATS_LAST) {
213                val = mLastTotalTime;
214            } else {
215                val = computeRunTimeLocked(now);
216                if (which == STATS_UNPLUGGED) {
217                    val -= mUnpluggedTotalTime;
218                } else if (which != STATS_TOTAL) {
219                    val -= mLoadedTotalTime;
220                }
221            }
222
223            return val;
224        }
225
226        @Override
227        public int getCount(int which) {
228            int val;
229            if (which == STATS_LAST) {
230                val = mLastCount;
231            } else {
232                val = mCount;
233                if (which == STATS_UNPLUGGED) {
234                    val -= mUnpluggedCount;
235                } else if (which != STATS_TOTAL) {
236                    val -= mLoadedCount;
237                }
238            }
239
240            return val;
241        }
242
243        public void logState() {
244            Log.i("foo", "mNesting=" + mNesting + " mCount=" + mCount
245                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
246                    + " mUnpluggedCount=" + mUnpluggedCount);
247            Log.i("foo", "mTotalTime=" + mTotalTime
248                    + " mLoadedTotalTime=" + mLoadedTotalTime);
249            Log.i("foo", "mLastTotalTime=" + mLastTotalTime
250                    + " mUpdateTime=" + mUpdateTime);
251        }
252
253        void startRunningLocked(BatteryStatsImpl stats) {
254            if (mNesting++ == 0) {
255                mUpdateTime = stats.getBatteryRealtimeLocked(
256                        SystemClock.elapsedRealtime() * 1000);
257                // Accumulate time to all currently active timers before adding
258                // this new one to the pool.
259                refreshTimersLocked(stats, mTimerPool);
260                // Add this timer to the active pool
261                mTimerPool.add(this);
262                // Increment the count
263                mCount++;
264            }
265        }
266
267        void stopRunningLocked(BatteryStatsImpl stats) {
268            // Ignore attempt to stop a timer that isn't running
269            if (mNesting == 0) {
270                return;
271            }
272            if (--mNesting == 0) {
273                // Accumulate time to all active counters, scaled by the total
274                // active in the pool, before taking this one out of the pool.
275                refreshTimersLocked(stats, mTimerPool);
276                // Remove this timer from the active pool
277                mTimerPool.remove(this);
278            }
279        }
280
281        // Update the total time for all other running Timers with the same type as this Timer
282        // due to a change in timer count
283        private static void refreshTimersLocked(final BatteryStatsImpl stats,
284                final ArrayList<Timer> pool) {
285            final long realtime = SystemClock.elapsedRealtime() * 1000;
286            final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
287            final int N = pool.size();
288            for (int i=N-1; i>= 0; i--) {
289                final Timer t = pool.get(i);
290                long heldTime = batteryRealtime - t.mUpdateTime;
291                if (heldTime > 0) {
292                    t.mTotalTime += heldTime / N;
293                }
294                t.mUpdateTime = batteryRealtime;
295            }
296        }
297
298        private long computeRunTimeLocked(long curBatteryRealtime) {
299            return mTotalTime + (mNesting > 0
300                    ? (curBatteryRealtime - mUpdateTime) / mTimerPool.size() : 0);
301        }
302
303        void writeSummaryFromParcelLocked(Parcel out, long curBatteryUptime) {
304            long runTime = computeRunTimeLocked(curBatteryUptime);
305            // Divide by 1000 for backwards compatibility
306            out.writeLong((runTime + 500) / 1000);
307            out.writeLong(((runTime - mLoadedTotalTime) + 500) / 1000);
308            out.writeInt(mCount);
309            out.writeInt(mCount - mLoadedCount);
310        }
311
312        void readSummaryFromParcelLocked(Parcel in) {
313            // Multiply by 1000 for backwards compatibility
314            mTotalTime = mLoadedTotalTime = in.readLong() * 1000;
315            mLastTotalTime = in.readLong();
316            mCount = mLoadedCount = in.readInt();
317            mLastCount = in.readInt();
318            mNesting = 0;
319        }
320    }
321
322    public void doUnplug(long batteryUptime, long batteryRealtime) {
323        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
324            Uid u = mUidStats.valueAt(iu);
325            u.mStartedTcpBytesReceived = NetStat.getUidRxBytes(u.mUid);
326            u.mStartedTcpBytesSent = NetStat.getUidTxBytes(u.mUid);
327            u.mTcpBytesReceivedAtLastUnplug = u.mCurrentTcpBytesReceived;
328            u.mTcpBytesSentAtLastUnplug = u.mCurrentTcpBytesSent;
329        }
330        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
331            mUnpluggables.get(i).unplug(batteryUptime, batteryRealtime);
332        }
333    }
334
335    public void doPlug(long batteryUptime, long batteryRealtime) {
336        for (int iu = mUidStats.size() - 1; iu >= 0; iu--) {
337            Uid u = mUidStats.valueAt(iu);
338            if (u.mStartedTcpBytesReceived >= 0) {
339                u.mCurrentTcpBytesReceived = u.computeCurrentTcpBytesReceived();
340                u.mStartedTcpBytesReceived = -1;
341            }
342            if (u.mStartedTcpBytesSent >= 0) {
343                u.mCurrentTcpBytesSent = u.computeCurrentTcpBytesSent();
344                u.mStartedTcpBytesSent = -1;
345            }
346        }
347        for (int i = mUnpluggables.size() - 1; i >= 0; i--) {
348            mUnpluggables.get(i).plug(batteryUptime, batteryRealtime);
349        }
350    }
351
352    public void noteStartGps(int uid) {
353        mUidStats.get(uid).noteStartGps();
354    }
355
356    public void noteStopGps(int uid) {
357        mUidStats.get(uid).noteStopGps();
358    }
359
360    /**
361     * When the device screen or battery state changes, update the appropriate "screen on time"
362     * counter.
363     */
364    private void updateScreenOnTimeLocked(boolean screenOn) {
365        if (!mScreenOn) {
366            Log.w(TAG, "updateScreenOnTime without mScreenOn, ignored");
367            return;
368        }
369        long now = SystemClock.elapsedRealtime();
370        long elapsed = now - mLastScreenOnTimeMillis;
371        if (mOnBattery) {
372            mBatteryScreenOnTimeMillis += elapsed;
373        } else {
374            mPluggedScreenOnTimeMillis += elapsed;
375        }
376        if (screenOn) {
377            mLastScreenOnTimeMillis = now;
378        }
379    }
380
381    public void noteScreenOnLocked() {
382        mScreenOn = true;
383        mLastScreenOnTimeMillis = SystemClock.elapsedRealtime();
384    }
385
386    public void noteScreenOffLocked() {
387        if (!mScreenOn) {
388            Log.w(TAG, "noteScreenOff without mScreenOn, ignored");
389            return;
390        }
391        updateScreenOnTimeLocked(false);
392        mScreenOn = false;
393    }
394
395    @Override public long getBatteryScreenOnTime() {
396        return mBatteryScreenOnTimeMillis;
397    }
398
399    @Override public long getPluggedScreenOnTime() {
400        return mPluggedScreenOnTimeMillis;
401    }
402
403    @Override public boolean getIsOnBattery() {
404        return mOnBattery;
405    }
406
407    @Override public SparseArray<? extends BatteryStats.Uid> getUidStats() {
408        return mUidStats;
409    }
410
411    /**
412     * The statistics associated with a particular uid.
413     */
414    public final class Uid extends BatteryStats.Uid {
415
416        final int mUid;
417        long mLoadedTcpBytesReceived;
418        long mLoadedTcpBytesSent;
419        long mCurrentTcpBytesReceived;
420        long mCurrentTcpBytesSent;
421        long mTcpBytesReceivedAtLastUnplug;
422        long mTcpBytesSentAtLastUnplug;
423
424        // These are not saved/restored when parcelling, since we want
425        // to return from the parcel with a snapshot of the state.
426        long mStartedTcpBytesReceived = -1;
427        long mStartedTcpBytesSent = -1;
428
429        /**
430         * The statistics we have collected for this uid's wake locks.
431         */
432        final HashMap<String, Wakelock> mWakelockStats = new HashMap<String, Wakelock>();
433
434        /**
435         * The statistics we have collected for this uid's sensor activations.
436         */
437        final HashMap<Integer, Sensor> mSensorStats = new HashMap<Integer, Sensor>();
438
439        /**
440         * The statistics we have collected for this uid's processes.
441         */
442        final HashMap<String, Proc> mProcessStats = new HashMap<String, Proc>();
443
444        /**
445         * The statistics we have collected for this uid's processes.
446         */
447        final HashMap<String, Pkg> mPackageStats = new HashMap<String, Pkg>();
448
449        public Uid(int uid) {
450            mUid = uid;
451        }
452
453        @Override
454        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
455            return mWakelockStats;
456        }
457
458        @Override
459        public Map<Integer, ? extends BatteryStats.Uid.Sensor> getSensorStats() {
460            return mSensorStats;
461        }
462
463        @Override
464        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
465            return mProcessStats;
466        }
467
468        @Override
469        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
470            return mPackageStats;
471        }
472
473        public int getUid() {
474            return mUid;
475        }
476
477        public long getTcpBytesReceived(int which) {
478            if (which == STATS_LAST) {
479                return mLoadedTcpBytesReceived;
480            } else {
481                long current = computeCurrentTcpBytesReceived();
482                if (which == STATS_UNPLUGGED) {
483                    current -= mTcpBytesReceivedAtLastUnplug;
484                } else if (which == STATS_TOTAL) {
485                    current += mLoadedTcpBytesReceived;
486                }
487                return current;
488            }
489        }
490
491        public long computeCurrentTcpBytesReceived() {
492            return mCurrentTcpBytesReceived + (mStartedTcpBytesReceived >= 0
493                    ? (NetStat.getUidRxBytes(mUid) - mStartedTcpBytesReceived) : 0);
494        }
495
496        public long getTcpBytesSent(int which) {
497            if (which == STATS_LAST) {
498                return mLoadedTcpBytesSent;
499            } else {
500                long current = computeCurrentTcpBytesSent();
501                if (which == STATS_UNPLUGGED) {
502                    current -= mTcpBytesSentAtLastUnplug;
503                } else if (which == STATS_TOTAL) {
504                    current += mLoadedTcpBytesSent;
505                }
506                return current;
507            }
508        }
509
510        public long computeCurrentTcpBytesSent() {
511            return mCurrentTcpBytesSent + (mStartedTcpBytesSent >= 0
512                    ? (NetStat.getUidTxBytes(mUid) - mStartedTcpBytesSent) : 0);
513        }
514
515        void writeToParcelLocked(Parcel out, long batteryRealtime) {
516            out.writeInt(mWakelockStats.size());
517            for (Map.Entry<String, Uid.Wakelock> wakelockEntry : mWakelockStats.entrySet()) {
518                out.writeString(wakelockEntry.getKey());
519                Uid.Wakelock wakelock = wakelockEntry.getValue();
520                wakelock.writeToParcelLocked(out, batteryRealtime);
521            }
522
523            out.writeInt(mSensorStats.size());
524            for (Map.Entry<Integer, Uid.Sensor> sensorEntry : mSensorStats.entrySet()) {
525                out.writeInt(sensorEntry.getKey());
526                Uid.Sensor sensor = sensorEntry.getValue();
527                sensor.writeToParcelLocked(out, batteryRealtime);
528            }
529
530            out.writeInt(mProcessStats.size());
531            for (Map.Entry<String, Uid.Proc> procEntry : mProcessStats.entrySet()) {
532                out.writeString(procEntry.getKey());
533                Uid.Proc proc = procEntry.getValue();
534                proc.writeToParcelLocked(out);
535            }
536
537            out.writeInt(mPackageStats.size());
538            for (Map.Entry<String, Uid.Pkg> pkgEntry : mPackageStats.entrySet()) {
539                out.writeString(pkgEntry.getKey());
540                Uid.Pkg pkg = pkgEntry.getValue();
541                pkg.writeToParcelLocked(out);
542            }
543
544            out.writeLong(mLoadedTcpBytesReceived);
545            out.writeLong(mLoadedTcpBytesSent);
546            out.writeLong(computeCurrentTcpBytesReceived());
547            out.writeLong(computeCurrentTcpBytesSent());
548            out.writeLong(mTcpBytesReceivedAtLastUnplug);
549            out.writeLong(mTcpBytesSentAtLastUnplug);
550        }
551
552        void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
553            int numWakelocks = in.readInt();
554            mWakelockStats.clear();
555            for (int j = 0; j < numWakelocks; j++) {
556                String wakelockName = in.readString();
557                Uid.Wakelock wakelock = new Wakelock();
558                wakelock.readFromParcelLocked(unpluggables, in);
559                mWakelockStats.put(wakelockName, wakelock);
560            }
561
562            int numSensors = in.readInt();
563            mSensorStats.clear();
564            for (int k = 0; k < numSensors; k++) {
565                int sensorNumber = in.readInt();
566                Uid.Sensor sensor = new Sensor(sensorNumber);
567                sensor.readFromParcelLocked(mUnpluggables, in);
568                mSensorStats.put(sensorNumber, sensor);
569            }
570
571            int numProcs = in.readInt();
572            mProcessStats.clear();
573            for (int k = 0; k < numProcs; k++) {
574                String processName = in.readString();
575                Uid.Proc proc = new Proc();
576                proc.readFromParcelLocked(in);
577                mProcessStats.put(processName, proc);
578            }
579
580            int numPkgs = in.readInt();
581            mPackageStats.clear();
582            for (int l = 0; l < numPkgs; l++) {
583                String packageName = in.readString();
584                Uid.Pkg pkg = new Pkg();
585                pkg.readFromParcelLocked(in);
586                mPackageStats.put(packageName, pkg);
587            }
588
589            mLoadedTcpBytesReceived = in.readLong();
590            mLoadedTcpBytesSent = in.readLong();
591            mCurrentTcpBytesReceived = in.readLong();
592            mCurrentTcpBytesSent = in.readLong();
593            mTcpBytesReceivedAtLastUnplug = in.readLong();
594            mTcpBytesSentAtLastUnplug = in.readLong();
595        }
596
597        /**
598         * The statistics associated with a particular wake lock.
599         */
600        public final class Wakelock extends BatteryStats.Uid.Wakelock {
601            /**
602             * How long (in ms) this uid has been keeping the device partially awake.
603             */
604            Timer mTimerPartial;
605
606            /**
607             * How long (in ms) this uid has been keeping the device fully awake.
608             */
609            Timer mTimerFull;
610
611            /**
612             * How long (in ms) this uid has had a window keeping the device awake.
613             */
614            Timer mTimerWindow;
615
616            /**
617             * Reads a possibly null Timer from a Parcel.  The timer is associated with the
618             * proper timer pool from the given BatteryStatsImpl object.
619             *
620             * @param in the Parcel to be read from.
621             * return a new Timer, or null.
622             */
623            private Timer readTimerFromParcel(int type, ArrayList<Timer> pool,
624                    ArrayList<Unpluggable> unpluggables, Parcel in) {
625                if (in.readInt() == 0) {
626                    return null;
627                }
628
629                return new Timer(type, pool, unpluggables, in);
630            }
631
632            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
633                mTimerPartial = readTimerFromParcel(WAKE_TYPE_PARTIAL,
634                        mPartialTimers, unpluggables, in);
635                mTimerFull = readTimerFromParcel(WAKE_TYPE_FULL,
636                        mFullTimers, unpluggables, in);
637                mTimerWindow = readTimerFromParcel(WAKE_TYPE_WINDOW,
638                        mWindowTimers, unpluggables, in);
639            }
640
641            void writeToParcelLocked(Parcel out, long batteryRealtime) {
642                Timer.writeTimerToParcel(out, mTimerPartial, batteryRealtime);
643                Timer.writeTimerToParcel(out, mTimerFull, batteryRealtime);
644                Timer.writeTimerToParcel(out, mTimerWindow, batteryRealtime);
645            }
646
647            @Override
648            public Timer getWakeTime(int type) {
649                switch (type) {
650                case WAKE_TYPE_FULL: return mTimerFull;
651                case WAKE_TYPE_PARTIAL: return mTimerPartial;
652                case WAKE_TYPE_WINDOW: return mTimerWindow;
653                default: throw new IllegalArgumentException("type = " + type);
654                }
655            }
656        }
657
658        public final class Sensor extends BatteryStats.Uid.Sensor {
659            final int mHandle;
660            Timer mTimer;
661
662            public Sensor(int handle) {
663                mHandle = handle;
664            }
665
666            private Timer readTimerFromParcel(ArrayList<Unpluggable> unpluggables,
667                    Parcel in) {
668                if (in.readInt() == 0) {
669                    return null;
670                }
671
672                ArrayList<Timer> pool = mSensorTimers.get(mHandle);
673                if (pool == null) {
674                    pool = new ArrayList<Timer>();
675                    mSensorTimers.put(mHandle, pool);
676                }
677                return new Timer(0, pool, unpluggables, in);
678            }
679
680            void readFromParcelLocked(ArrayList<Unpluggable> unpluggables, Parcel in) {
681                mTimer = readTimerFromParcel(unpluggables, in);
682            }
683
684            void writeToParcelLocked(Parcel out, long batteryRealtime) {
685                Timer.writeTimerToParcel(out, mTimer, batteryRealtime);
686            }
687
688            @Override
689            public Timer getSensorTime() {
690                return mTimer;
691            }
692
693            public int getHandle() {
694                return mHandle;
695            }
696        }
697
698        /**
699         * The statistics associated with a particular process.
700         */
701        public final class Proc extends BatteryStats.Uid.Proc implements Unpluggable {
702            /**
703             * Total time (in 1/100 sec) spent executing in user code.
704             */
705            long mUserTime;
706
707            /**
708             * Total time (in 1/100 sec) spent executing in kernel code.
709             */
710            long mSystemTime;
711
712            /**
713             * Number of times the process has been started.
714             */
715            int mStarts;
716
717            /**
718             * The amount of user time loaded from a previous save.
719             */
720            long mLoadedUserTime;
721
722            /**
723             * The amount of system time loaded from a previous save.
724             */
725            long mLoadedSystemTime;
726
727            /**
728             * The number of times the process has started from a previous save.
729             */
730            int mLoadedStarts;
731
732            /**
733             * The amount of user time loaded from the previous run.
734             */
735            long mLastUserTime;
736
737            /**
738             * The amount of system time loaded from the previous run.
739             */
740            long mLastSystemTime;
741
742            /**
743             * The number of times the process has started from the previous run.
744             */
745            int mLastStarts;
746
747            /**
748             * The amount of user time when last unplugged.
749             */
750            long mUnpluggedUserTime;
751
752            /**
753             * The amount of system time when last unplugged.
754             */
755            long mUnpluggedSystemTime;
756
757            /**
758             * The number of times the process has started before unplugged.
759             */
760            int mUnpluggedStarts;
761
762            Proc() {
763                mUnpluggables.add(this);
764            }
765
766            public void unplug(long batteryUptime, long batteryRealtime) {
767                mUnpluggedUserTime = mUserTime;
768                mUnpluggedSystemTime = mSystemTime;
769                mUnpluggedStarts = mStarts;
770            }
771
772            public void plug(long batteryUptime, long batteryRealtime) {
773            }
774
775            void writeToParcelLocked(Parcel out) {
776                out.writeLong(mUserTime);
777                out.writeLong(mSystemTime);
778                out.writeInt(mStarts);
779                out.writeLong(mLoadedUserTime);
780                out.writeLong(mLoadedSystemTime);
781                out.writeInt(mLoadedStarts);
782                out.writeLong(mLastUserTime);
783                out.writeLong(mLastSystemTime);
784                out.writeInt(mLastStarts);
785                out.writeLong(mUnpluggedUserTime);
786                out.writeLong(mUnpluggedSystemTime);
787                out.writeInt(mUnpluggedStarts);
788            }
789
790            void readFromParcelLocked(Parcel in) {
791                mUserTime = in.readLong();
792                mSystemTime = in.readLong();
793                mStarts = in.readInt();
794                mLoadedUserTime = in.readLong();
795                mLoadedSystemTime = in.readLong();
796                mLoadedStarts = in.readInt();
797                mLastUserTime = in.readLong();
798                mLastSystemTime = in.readLong();
799                mLastStarts = in.readInt();
800                mUnpluggedUserTime = in.readLong();
801                mUnpluggedSystemTime = in.readLong();
802                mUnpluggedStarts = in.readInt();
803            }
804
805            public BatteryStatsImpl getBatteryStats() {
806                return BatteryStatsImpl.this;
807            }
808
809            public void addCpuTimeLocked(int utime, int stime) {
810                mUserTime += utime;
811                mSystemTime += stime;
812            }
813
814            public void incStartsLocked() {
815                mStarts++;
816            }
817
818            @Override
819            public long getUserTime(int which) {
820                long val;
821                if (which == STATS_LAST) {
822                    val = mLastUserTime;
823                } else {
824                    val = mUserTime;
825                    if (which == STATS_CURRENT) {
826                        val -= mLoadedUserTime;
827                    } else if (which == STATS_UNPLUGGED) {
828                        val -= mUnpluggedUserTime;
829                    }
830                }
831                return val;
832            }
833
834            @Override
835            public long getSystemTime(int which) {
836                long val;
837                if (which == STATS_LAST) {
838                    val = mLastSystemTime;
839                } else {
840                    val = mSystemTime;
841                    if (which == STATS_CURRENT) {
842                        val -= mLoadedSystemTime;
843                    } else if (which == STATS_UNPLUGGED) {
844                        val -= mUnpluggedSystemTime;
845                    }
846                }
847                return val;
848            }
849
850            @Override
851            public int getStarts(int which) {
852                int val;
853                if (which == STATS_LAST) {
854                    val = mLastStarts;
855                } else {
856                    val = mStarts;
857                    if (which == STATS_CURRENT) {
858                        val -= mLoadedStarts;
859                    } else if (which == STATS_UNPLUGGED) {
860                        val -= mUnpluggedStarts;
861                    }
862                }
863                return val;
864            }
865        }
866
867        /**
868         * The statistics associated with a particular package.
869         */
870        public final class Pkg extends BatteryStats.Uid.Pkg implements Unpluggable {
871            /**
872             * Number of times this package has done something that could wake up the
873             * device from sleep.
874             */
875            int mWakeups;
876
877            /**
878             * Number of things that could wake up the device loaded from a
879             * previous save.
880             */
881            int mLoadedWakeups;
882
883            /**
884             * Number of things that could wake up the device as of the
885             * last run.
886             */
887            int mLastWakeups;
888
889            /**
890             * Number of things that could wake up the device as of the
891             * last run.
892             */
893            int mUnpluggedWakeups;
894
895            /**
896             * The statics we have collected for this package's services.
897             */
898            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
899
900            Pkg() {
901                mUnpluggables.add(this);
902            }
903
904            public void unplug(long batteryUptime, long batteryRealtime) {
905                mUnpluggedWakeups = mWakeups;
906            }
907
908            public void plug(long batteryUptime, long batteryRealtime) {
909            }
910
911            void readFromParcelLocked(Parcel in) {
912                mWakeups = in.readInt();
913                mLoadedWakeups = in.readInt();
914                mLastWakeups = in.readInt();
915                mUnpluggedWakeups = in.readInt();
916
917                int numServs = in.readInt();
918                mServiceStats.clear();
919                for (int m = 0; m < numServs; m++) {
920                    String serviceName = in.readString();
921                    Uid.Pkg.Serv serv = new Serv();
922                    mServiceStats.put(serviceName, serv);
923
924                    serv.readFromParcelLocked(in);
925                }
926            }
927
928            void writeToParcelLocked(Parcel out) {
929                out.writeInt(mWakeups);
930                out.writeInt(mLoadedWakeups);
931                out.writeInt(mLastWakeups);
932                out.writeInt(mUnpluggedWakeups);
933
934                out.writeInt(mServiceStats.size());
935                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
936                    out.writeString(servEntry.getKey());
937                    Uid.Pkg.Serv serv = servEntry.getValue();
938
939                    serv.writeToParcelLocked(out);
940                }
941            }
942
943            @Override
944            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
945                return mServiceStats;
946            }
947
948            @Override
949            public int getWakeups(int which) {
950                int val;
951                if (which == STATS_LAST) {
952                    val = mLastWakeups;
953                } else {
954                    val = mWakeups;
955                    if (which == STATS_CURRENT) {
956                        val -= mLoadedWakeups;
957                    } else if (which == STATS_UNPLUGGED) {
958                        val -= mUnpluggedWakeups;
959                    }
960                }
961
962                return val;
963            }
964
965            /**
966             * The statistics associated with a particular service.
967             */
968            public final class Serv extends BatteryStats.Uid.Pkg.Serv implements Unpluggable {
969                /**
970                 * Total time (ms in battery uptime) the service has been left started.
971                 */
972                long mStartTime;
973
974                /**
975                 * If service has been started and not yet stopped, this is
976                 * when it was started.
977                 */
978                long mRunningSince;
979
980                /**
981                 * True if we are currently running.
982                 */
983                boolean mRunning;
984
985                /**
986                 * Total number of times startService() has been called.
987                 */
988                int mStarts;
989
990                /**
991                 * Total time (ms in battery uptime) the service has been left launched.
992                 */
993                long mLaunchedTime;
994
995                /**
996                 * If service has been launched and not yet exited, this is
997                 * when it was launched (ms in battery uptime).
998                 */
999                long mLaunchedSince;
1000
1001                /**
1002                 * True if we are currently launched.
1003                 */
1004                boolean mLaunched;
1005
1006                /**
1007                 * Total number times the service has been launched.
1008                 */
1009                int mLaunches;
1010
1011                /**
1012                 * The amount of time spent started loaded from a previous save
1013                 * (ms in battery uptime).
1014                 */
1015                long mLoadedStartTime;
1016
1017                /**
1018                 * The number of starts loaded from a previous save.
1019                 */
1020                int mLoadedStarts;
1021
1022                /**
1023                 * The number of launches loaded from a previous save.
1024                 */
1025                int mLoadedLaunches;
1026
1027                /**
1028                 * The amount of time spent started as of the last run (ms
1029                 * in battery uptime).
1030                 */
1031                long mLastStartTime;
1032
1033                /**
1034                 * The number of starts as of the last run.
1035                 */
1036                int mLastStarts;
1037
1038                /**
1039                 * The number of launches as of the last run.
1040                 */
1041                int mLastLaunches;
1042
1043                /**
1044                 * The amount of time spent started when last unplugged (ms
1045                 * in battery uptime).
1046                 */
1047                long mUnpluggedStartTime;
1048
1049                /**
1050                 * The number of starts when last unplugged.
1051                 */
1052                int mUnpluggedStarts;
1053
1054                /**
1055                 * The number of launches when last unplugged.
1056                 */
1057                int mUnpluggedLaunches;
1058
1059                Serv() {
1060                    mUnpluggables.add(this);
1061                }
1062
1063                public void unplug(long batteryUptime, long batteryRealtime) {
1064                    mUnpluggedStartTime = getStartTimeToNowLocked(batteryUptime);
1065                    mUnpluggedStarts = mStarts;
1066                    mUnpluggedLaunches = mLaunches;
1067                }
1068
1069                public void plug(long batteryUptime, long batteryRealtime) {
1070                }
1071
1072                void readFromParcelLocked(Parcel in) {
1073                    mStartTime = in.readLong();
1074                    mRunningSince = in.readLong();
1075                    mRunning = in.readInt() != 0;
1076                    mStarts = in.readInt();
1077                    mLaunchedTime = in.readLong();
1078                    mLaunchedSince = in.readLong();
1079                    mLaunched = in.readInt() != 0;
1080                    mLaunches = in.readInt();
1081                    mLoadedStartTime = in.readLong();
1082                    mLoadedStarts = in.readInt();
1083                    mLoadedLaunches = in.readInt();
1084                    mLastStartTime = in.readLong();
1085                    mLastStarts = in.readInt();
1086                    mLastLaunches = in.readInt();
1087                    mUnpluggedStartTime = in.readLong();
1088                    mUnpluggedStarts = in.readInt();
1089                    mUnpluggedLaunches = in.readInt();
1090                }
1091
1092                void writeToParcelLocked(Parcel out) {
1093                    out.writeLong(mStartTime);
1094                    out.writeLong(mRunningSince);
1095                    out.writeInt(mRunning ? 1 : 0);
1096                    out.writeInt(mStarts);
1097                    out.writeLong(mLaunchedTime);
1098                    out.writeLong(mLaunchedSince);
1099                    out.writeInt(mLaunched ? 1 : 0);
1100                    out.writeInt(mLaunches);
1101                    out.writeLong(mLoadedStartTime);
1102                    out.writeInt(mLoadedStarts);
1103                    out.writeInt(mLoadedLaunches);
1104                    out.writeLong(mLastStartTime);
1105                    out.writeInt(mLastStarts);
1106                    out.writeInt(mLastLaunches);
1107                    out.writeLong(mUnpluggedStartTime);
1108                    out.writeInt(mUnpluggedStarts);
1109                    out.writeInt(mUnpluggedLaunches);
1110                }
1111
1112                long getLaunchTimeToNowLocked(long batteryUptime) {
1113                    if (!mLaunched) return mLaunchedTime;
1114                    return mLaunchedTime + batteryUptime - mLaunchedSince;
1115                }
1116
1117                long getStartTimeToNowLocked(long batteryUptime) {
1118                    if (!mRunning) return mStartTime;
1119                    return mStartTime + batteryUptime - mRunningSince;
1120                }
1121
1122                public void startLaunchedLocked() {
1123                    if (!mLaunched) {
1124                        mLaunches++;
1125                        mLaunchedSince = getBatteryUptimeLocked();
1126                        mLaunched = true;
1127                    }
1128                }
1129
1130                public void stopLaunchedLocked() {
1131                    if (mLaunched) {
1132                        long time = getBatteryUptimeLocked() - mLaunchedSince;
1133                        if (time > 0) {
1134                            mLaunchedTime += time;
1135                        } else {
1136                            mLaunches--;
1137                        }
1138                        mLaunched = false;
1139                    }
1140                }
1141
1142                public void startRunningLocked() {
1143                    if (!mRunning) {
1144                        mStarts++;
1145                        mRunningSince = getBatteryUptimeLocked();
1146                        mRunning = true;
1147                    }
1148                }
1149
1150                public void stopRunningLocked() {
1151                    if (mRunning) {
1152                        long time = getBatteryUptimeLocked() - mRunningSince;
1153                        if (time > 0) {
1154                            mStartTime += time;
1155                        } else {
1156                            mStarts--;
1157                        }
1158                        mRunning = false;
1159                    }
1160                }
1161
1162                public BatteryStatsImpl getBatteryStats() {
1163                    return BatteryStatsImpl.this;
1164                }
1165
1166                @Override
1167                public int getLaunches(int which) {
1168                    int val;
1169
1170                    if (which == STATS_LAST) {
1171                        val = mLastLaunches;
1172                    } else {
1173                        val = mLaunches;
1174                        if (which == STATS_CURRENT) {
1175                            val -= mLoadedLaunches;
1176                        } else if (which == STATS_UNPLUGGED) {
1177                            val -= mUnpluggedLaunches;
1178                        }
1179                    }
1180
1181                    return val;
1182                }
1183
1184                @Override
1185                public long getStartTime(long now, int which) {
1186                    long val;
1187                    if (which == STATS_LAST) {
1188                        val = mLastStartTime;
1189                    } else {
1190                        val = getStartTimeToNowLocked(now);
1191                        if (which == STATS_CURRENT) {
1192                            val -= mLoadedStartTime;
1193                        } else if (which == STATS_UNPLUGGED) {
1194                            val -= mUnpluggedStartTime;
1195                        }
1196                    }
1197
1198                    return val;
1199                }
1200
1201                @Override
1202                public int getStarts(int which) {
1203                    int val;
1204                    if (which == STATS_LAST) {
1205                        val = mLastStarts;
1206                    } else {
1207                        val = mStarts;
1208                        if (which == STATS_CURRENT) {
1209                            val -= mLoadedStarts;
1210                        } else if (which == STATS_UNPLUGGED) {
1211                            val -= mUnpluggedStarts;
1212                        }
1213                    }
1214
1215                    return val;
1216                }
1217            }
1218
1219            public BatteryStatsImpl getBatteryStats() {
1220                return BatteryStatsImpl.this;
1221            }
1222
1223            public void incWakeupsLocked() {
1224                mWakeups++;
1225            }
1226
1227            final Serv newServiceStatsLocked() {
1228                return new Serv();
1229            }
1230        }
1231
1232        /**
1233         * Retrieve the statistics object for a particular process, creating
1234         * if needed.
1235         */
1236        public Proc getProcessStatsLocked(String name) {
1237            Proc ps = mProcessStats.get(name);
1238            if (ps == null) {
1239                ps = new Proc();
1240                mProcessStats.put(name, ps);
1241            }
1242
1243            return ps;
1244        }
1245
1246        /**
1247         * Retrieve the statistics object for a particular service, creating
1248         * if needed.
1249         */
1250        public Pkg getPackageStatsLocked(String name) {
1251            Pkg ps = mPackageStats.get(name);
1252            if (ps == null) {
1253                ps = new Pkg();
1254                mPackageStats.put(name, ps);
1255            }
1256
1257            return ps;
1258        }
1259
1260        /**
1261         * Retrieve the statistics object for a particular service, creating
1262         * if needed.
1263         */
1264        public Pkg.Serv getServiceStatsLocked(String pkg, String serv) {
1265            Pkg ps = getPackageStatsLocked(pkg);
1266            Pkg.Serv ss = ps.mServiceStats.get(serv);
1267            if (ss == null) {
1268                ss = ps.newServiceStatsLocked();
1269                ps.mServiceStats.put(serv, ss);
1270            }
1271
1272            return ss;
1273        }
1274
1275        public Timer getWakeTimerLocked(String name, int type) {
1276            Wakelock wl = mWakelockStats.get(name);
1277            if (wl == null) {
1278                wl = new Wakelock();
1279                mWakelockStats.put(name, wl);
1280            }
1281            Timer t = null;
1282            switch (type) {
1283                case WAKE_TYPE_PARTIAL:
1284                    t = wl.mTimerPartial;
1285                    if (t == null) {
1286                        t = new Timer(WAKE_TYPE_PARTIAL, mPartialTimers, mUnpluggables);
1287                        wl.mTimerPartial = t;
1288                    }
1289                    return t;
1290                case WAKE_TYPE_FULL:
1291                    t = wl.mTimerFull;
1292                    if (t == null) {
1293                        t = new Timer(WAKE_TYPE_FULL, mFullTimers, mUnpluggables);
1294                        wl.mTimerFull = t;
1295                    }
1296                    return t;
1297                case WAKE_TYPE_WINDOW:
1298                    t = wl.mTimerWindow;
1299                    if (t == null) {
1300                        t = new Timer(WAKE_TYPE_WINDOW, mWindowTimers, mUnpluggables);
1301                        wl.mTimerWindow = t;
1302                    }
1303                    return t;
1304                default:
1305                    throw new IllegalArgumentException("type=" + type);
1306            }
1307        }
1308
1309        public Timer getSensorTimerLocked(int sensor, boolean create) {
1310            Sensor se = mSensorStats.get(sensor);
1311            if (se == null) {
1312                if (!create) {
1313                    return null;
1314                }
1315                se = new Sensor(sensor);
1316                mSensorStats.put(sensor, se);
1317            }
1318            Timer t = se.mTimer;
1319            if (t != null) {
1320                return t;
1321            }
1322            ArrayList<Timer> timers = mSensorTimers.get(sensor);
1323            if (timers == null) {
1324                timers = new ArrayList<Timer>();
1325                mSensorTimers.put(sensor, timers);
1326            }
1327            t = new Timer(BatteryStats.SENSOR, timers, mUnpluggables);
1328            se.mTimer = t;
1329            return t;
1330        }
1331
1332        public void noteStartWakeLocked(String name, int type) {
1333            Timer t = getWakeTimerLocked(name, type);
1334            if (t != null) {
1335                t.startRunningLocked(BatteryStatsImpl.this);
1336            }
1337        }
1338
1339        public void noteStopWakeLocked(String name, int type) {
1340            Timer t = getWakeTimerLocked(name, type);
1341            if (t != null) {
1342                t.stopRunningLocked(BatteryStatsImpl.this);
1343            }
1344        }
1345
1346        public void noteStartSensor(int sensor) {
1347            Timer t = getSensorTimerLocked(sensor, true);
1348            if (t != null) {
1349                t.startRunningLocked(BatteryStatsImpl.this);
1350            }
1351        }
1352
1353        public void noteStopSensor(int sensor) {
1354            // Don't create a timer if one doesn't already exist
1355            Timer t = getSensorTimerLocked(sensor, false);
1356            if (t != null) {
1357                t.stopRunningLocked(BatteryStatsImpl.this);
1358            }
1359        }
1360
1361        public void noteStartGps() {
1362            Timer t = getSensorTimerLocked(Sensor.GPS, true);
1363            if (t != null) {
1364                t.startRunningLocked(BatteryStatsImpl.this);
1365            }
1366        }
1367
1368        public void noteStopGps() {
1369            Timer t = getSensorTimerLocked(Sensor.GPS, false);
1370            if (t != null) {
1371                t.stopRunningLocked(BatteryStatsImpl.this);
1372            }
1373        }
1374
1375        public BatteryStatsImpl getBatteryStats() {
1376            return BatteryStatsImpl.this;
1377        }
1378    }
1379
1380    public BatteryStatsImpl(String filename) {
1381        mFile = new File(filename);
1382        mBackupFile = new File(filename + ".bak");
1383        mStartCount++;
1384        mOnBattery = mOnBatteryInternal = false;
1385        mTrackBatteryPastUptime = 0;
1386        mTrackBatteryPastRealtime = 0;
1387        mUptimeStart = mTrackBatteryUptimeStart = SystemClock.uptimeMillis() * 1000;
1388        mRealtimeStart = mTrackBatteryRealtimeStart = SystemClock.elapsedRealtime() * 1000;
1389        mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
1390        mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
1391    }
1392
1393    public BatteryStatsImpl(Parcel p) {
1394        mFile = mBackupFile = null;
1395        readFromParcel(p);
1396    }
1397
1398    @Override
1399    public int getStartCount() {
1400        return mStartCount;
1401    }
1402
1403    public boolean isOnBattery() {
1404        return mOnBattery;
1405    }
1406
1407    public void setOnBattery(boolean onBattery) {
1408        synchronized(this) {
1409            if (mOnBattery != onBattery) {
1410                if (mScreenOn) {
1411                    updateScreenOnTimeLocked(true);
1412                }
1413
1414                mOnBattery = mOnBatteryInternal = onBattery;
1415
1416                long uptime = SystemClock.uptimeMillis() * 1000;
1417                long mSecRealtime = SystemClock.elapsedRealtime();
1418                long realtime = mSecRealtime * 1000;
1419                if (onBattery) {
1420                    mTrackBatteryUptimeStart = uptime;
1421                    mTrackBatteryRealtimeStart = realtime;
1422                    mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
1423                    mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
1424                    doUnplug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
1425                } else {
1426                    mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart;
1427                    mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart;
1428                    doPlug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
1429                }
1430                if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) {
1431                    if (mFile != null) {
1432                        writeLocked();
1433                    }
1434                }
1435            }
1436        }
1437    }
1438
1439    public long getAwakeTimeBattery() {
1440        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
1441    }
1442
1443    public long getAwakeTimePlugged() {
1444        return (SystemClock.uptimeMillis() * 1000) - getAwakeTimeBattery();
1445    }
1446
1447    @Override
1448    public long computeUptime(long curTime, int which) {
1449        switch (which) {
1450        case STATS_TOTAL: return mUptime + (curTime-mUptimeStart);
1451        case STATS_LAST: return mLastUptime;
1452        case STATS_CURRENT: return (curTime-mUptimeStart);
1453        case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart);
1454        }
1455        return 0;
1456    }
1457
1458    @Override
1459    public long computeRealtime(long curTime, int which) {
1460        switch (which) {
1461        case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart);
1462        case STATS_LAST: return mLastRealtime;
1463        case STATS_CURRENT: return (curTime-mRealtimeStart);
1464        case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart);
1465        }
1466        return 0;
1467    }
1468
1469    @Override
1470    public long computeBatteryUptime(long curTime, int which) {
1471        long uptime = getBatteryUptime(curTime);
1472        switch (which) {
1473        case STATS_TOTAL:
1474            return mBatteryUptime + uptime;
1475        case STATS_LAST:
1476            return mBatteryLastUptime;
1477        case STATS_CURRENT:
1478            return uptime;
1479        case STATS_UNPLUGGED:
1480            return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime;
1481        }
1482        return 0;
1483    }
1484
1485    @Override
1486    public long computeBatteryRealtime(long curTime, int which) {
1487        switch (which) {
1488        case STATS_TOTAL:
1489            return mBatteryRealtime + getBatteryRealtimeLocked(curTime);
1490        case STATS_LAST:
1491            return mBatteryLastRealtime;
1492        case STATS_CURRENT:
1493            return getBatteryRealtimeLocked(curTime);
1494        case STATS_UNPLUGGED:
1495            return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime;
1496        }
1497        return 0;
1498    }
1499
1500    long getBatteryUptimeLocked(long curTime) {
1501        long time = mTrackBatteryPastUptime;
1502        if (mOnBatteryInternal) {
1503            time += curTime - mTrackBatteryUptimeStart;
1504        }
1505        return time;
1506    }
1507
1508    long getBatteryUptimeLocked() {
1509        return getBatteryUptime(SystemClock.uptimeMillis() * 1000);
1510    }
1511
1512    @Override
1513    public long getBatteryUptime(long curTime) {
1514        return getBatteryUptimeLocked(curTime);
1515    }
1516
1517    long getBatteryRealtimeLocked(long curTime) {
1518        long time = mTrackBatteryPastRealtime;
1519        if (mOnBatteryInternal) {
1520            time += curTime - mTrackBatteryRealtimeStart;
1521        }
1522        return time;
1523    }
1524
1525    @Override
1526    public long getBatteryRealtime(long curTime) {
1527        return getBatteryRealtimeLocked(curTime);
1528    }
1529
1530    /**
1531     * Retrieve the statistics object for a particular uid, creating if needed.
1532     */
1533    public Uid getUidStatsLocked(int uid) {
1534        Uid u = mUidStats.get(uid);
1535        if (u == null) {
1536            u = new Uid(uid);
1537            mUidStats.put(uid, u);
1538        }
1539        return u;
1540    }
1541
1542    /**
1543     * Remove the statistics object for a particular uid.
1544     */
1545    public void removeUidStatsLocked(int uid) {
1546        mUidStats.remove(uid);
1547    }
1548
1549    /**
1550     * Retrieve the statistics object for a particular process, creating
1551     * if needed.
1552     */
1553    public Uid.Proc getProcessStatsLocked(int uid, String name) {
1554        Uid u = getUidStatsLocked(uid);
1555        return u.getProcessStatsLocked(name);
1556    }
1557
1558    /**
1559     * Retrieve the statistics object for a particular process, creating
1560     * if needed.
1561     */
1562    public Uid.Pkg getPackageStatsLocked(int uid, String pkg) {
1563        Uid u = getUidStatsLocked(uid);
1564        return u.getPackageStatsLocked(pkg);
1565    }
1566
1567    /**
1568     * Retrieve the statistics object for a particular service, creating
1569     * if needed.
1570     */
1571    public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) {
1572        Uid u = getUidStatsLocked(uid);
1573        return u.getServiceStatsLocked(pkg, name);
1574    }
1575
1576    public void writeLocked() {
1577        if ((mFile == null) || (mBackupFile == null)) {
1578            Log.w("BatteryStats", "writeLocked: no file associated with this instance");
1579            return;
1580        }
1581
1582        // Keep the old file around until we know the new one has
1583        // been successfully written.
1584        if (mFile.exists()) {
1585            if (mBackupFile.exists()) {
1586                mBackupFile.delete();
1587            }
1588            mFile.renameTo(mBackupFile);
1589        }
1590
1591        try {
1592            FileOutputStream stream = new FileOutputStream(mFile);
1593            Parcel out = Parcel.obtain();
1594            writeSummaryToParcel(out);
1595            stream.write(out.marshall());
1596            out.recycle();
1597
1598            stream.flush();
1599            stream.close();
1600            mBackupFile.delete();
1601
1602            mLastWriteTime = SystemClock.elapsedRealtime();
1603        } catch (IOException e) {
1604            Log.e("BatteryStats", "Error writing battery statistics", e);
1605        }
1606    }
1607
1608    static byte[] readFully(FileInputStream stream) throws java.io.IOException {
1609        int pos = 0;
1610        int avail = stream.available();
1611        byte[] data = new byte[avail];
1612        while (true) {
1613            int amt = stream.read(data, pos, data.length-pos);
1614            //Log.i("foo", "Read " + amt + " bytes at " + pos
1615            //        + " of avail " + data.length);
1616            if (amt <= 0) {
1617                //Log.i("foo", "**** FINISHED READING: pos=" + pos
1618                //        + " len=" + data.length);
1619                return data;
1620            }
1621            pos += amt;
1622            avail = stream.available();
1623            if (avail > data.length-pos) {
1624                byte[] newData = new byte[pos+avail];
1625                System.arraycopy(data, 0, newData, 0, pos);
1626                data = newData;
1627            }
1628        }
1629    }
1630
1631    public void readLocked() {
1632        if ((mFile == null) || (mBackupFile == null)) {
1633            Log.w("BatteryStats", "readLocked: no file associated with this instance");
1634            return;
1635        }
1636
1637        mUidStats.clear();
1638
1639        FileInputStream stream = null;
1640        if (mBackupFile.exists()) {
1641            try {
1642                stream = new FileInputStream(mBackupFile);
1643            } catch (java.io.IOException e) {
1644                // We'll try for the normal settings file.
1645            }
1646        }
1647
1648        try {
1649            if (stream == null) {
1650                if (!mFile.exists()) {
1651                    return;
1652                }
1653                stream = new FileInputStream(mFile);
1654            }
1655
1656            byte[] raw = readFully(stream);
1657            Parcel in = Parcel.obtain();
1658            in.unmarshall(raw, 0, raw.length);
1659            in.setDataPosition(0);
1660            stream.close();
1661
1662            readSummaryFromParcel(in);
1663        } catch(java.io.IOException e) {
1664            Log.e("BatteryStats", "Error reading battery statistics", e);
1665        }
1666    }
1667
1668    public int describeContents() {
1669        return 0;
1670    }
1671
1672    private void readSummaryFromParcel(Parcel in) {
1673        final int version = in.readInt();
1674        if (version != VERSION) {
1675            Log.w("BatteryStats", "readFromParcel: version got " + version
1676                + ", expected " + VERSION + "; erasing old stats");
1677            return;
1678        }
1679
1680        mStartCount = in.readInt();
1681        mBatteryUptime = in.readLong();
1682        mBatteryLastUptime = in.readLong();
1683        mBatteryRealtime = in.readLong();
1684        mBatteryLastRealtime = in.readLong();
1685        mUptime = in.readLong();
1686        mLastUptime = in.readLong();
1687        mRealtime = in.readLong();
1688        mLastRealtime = in.readLong();
1689        mStartCount++;
1690
1691        mBatteryScreenOnTimeMillis = in.readLong();
1692        mPluggedScreenOnTimeMillis = in.readLong();
1693        mScreenOn = false;
1694
1695        final int NU = in.readInt();
1696        for (int iu = 0; iu < NU; iu++) {
1697            int uid = in.readInt();
1698            Uid u = new Uid(uid);
1699            mUidStats.put(uid, u);
1700
1701            int NW = in.readInt();
1702            for (int iw = 0; iw < NW; iw++) {
1703                String wlName = in.readString();
1704                if (in.readInt() != 0) {
1705                    u.getWakeTimerLocked(wlName, WAKE_TYPE_FULL).readSummaryFromParcelLocked(in);
1706                }
1707                if (in.readInt() != 0) {
1708                    u.getWakeTimerLocked(wlName, WAKE_TYPE_PARTIAL).readSummaryFromParcelLocked(in);
1709                }
1710                if (in.readInt() != 0) {
1711                    u.getWakeTimerLocked(wlName, WAKE_TYPE_WINDOW).readSummaryFromParcelLocked(in);
1712                }
1713            }
1714
1715            int NP = in.readInt();
1716            for (int is = 0; is < NP; is++) {
1717                int seNumber = in.readInt();
1718                if (in.readInt() != 0) {
1719                    u.getSensorTimerLocked(seNumber, true)
1720                            .readSummaryFromParcelLocked(in);
1721                }
1722            }
1723
1724            NP = in.readInt();
1725            for (int ip = 0; ip < NP; ip++) {
1726                String procName = in.readString();
1727                Uid.Proc p = u.getProcessStatsLocked(procName);
1728                p.mUserTime = p.mLoadedUserTime = in.readLong();
1729                p.mLastUserTime = in.readLong();
1730                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
1731                p.mLastSystemTime = in.readLong();
1732                p.mStarts = p.mLoadedStarts = in.readInt();
1733                p.mLastStarts = in.readInt();
1734            }
1735
1736            NP = in.readInt();
1737            for (int ip = 0; ip < NP; ip++) {
1738                String pkgName = in.readString();
1739                Uid.Pkg p = u.getPackageStatsLocked(pkgName);
1740                p.mWakeups = p.mLoadedWakeups = in.readInt();
1741                p.mLastWakeups = in.readInt();
1742                final int NS = in.readInt();
1743                for (int is = 0; is < NS; is++) {
1744                    String servName = in.readString();
1745                    Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
1746                    s.mStartTime = s.mLoadedStartTime = in.readLong();
1747                    s.mLastStartTime = in.readLong();
1748                    s.mStarts = s.mLoadedStarts = in.readInt();
1749                    s.mLastStarts = in.readInt();
1750                    s.mLaunches = s.mLoadedLaunches = in.readInt();
1751                    s.mLastLaunches = in.readInt();
1752                }
1753            }
1754
1755            u.mLoadedTcpBytesReceived = in.readLong();
1756            u.mLoadedTcpBytesSent = in.readLong();
1757        }
1758    }
1759
1760    /**
1761     * Writes a summary of the statistics to a Parcel, in a format suitable to be written to
1762     * disk.  This format does not allow a lossless round-trip.
1763     *
1764     * @param out the Parcel to be written to.
1765     */
1766    public void writeSummaryToParcel(Parcel out) {
1767        final long NOW = getBatteryUptimeLocked();
1768        final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
1769        final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
1770
1771        out.writeInt(VERSION);
1772
1773        out.writeInt(mStartCount);
1774        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_TOTAL));
1775        out.writeLong(computeBatteryUptime(NOW_SYS, STATS_CURRENT));
1776        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_TOTAL));
1777        out.writeLong(computeBatteryRealtime(NOWREAL_SYS, STATS_CURRENT));
1778        out.writeLong(computeUptime(NOW_SYS, STATS_TOTAL));
1779        out.writeLong(computeUptime(NOW_SYS, STATS_CURRENT));
1780        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL));
1781        out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT));
1782
1783        out.writeLong(mBatteryScreenOnTimeMillis);
1784        out.writeLong(mPluggedScreenOnTimeMillis);
1785
1786        final int NU = mUidStats.size();
1787        out.writeInt(NU);
1788        for (int iu = 0; iu < NU; iu++) {
1789            out.writeInt(mUidStats.keyAt(iu));
1790            Uid u = mUidStats.valueAt(iu);
1791
1792            int NW = u.mWakelockStats.size();
1793            out.writeInt(NW);
1794            if (NW > 0) {
1795                for (Map.Entry<String, BatteryStatsImpl.Uid.Wakelock> ent
1796                        : u.mWakelockStats.entrySet()) {
1797                    out.writeString(ent.getKey());
1798                    Uid.Wakelock wl = ent.getValue();
1799                    if (wl.mTimerFull != null) {
1800                        out.writeInt(1);
1801                        wl.mTimerFull.writeSummaryFromParcelLocked(out, NOW);
1802                    } else {
1803                        out.writeInt(0);
1804                    }
1805                    if (wl.mTimerPartial != null) {
1806                        out.writeInt(1);
1807                        wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOW);
1808                    } else {
1809                        out.writeInt(0);
1810                    }
1811                    if (wl.mTimerWindow != null) {
1812                        out.writeInt(1);
1813                        wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOW);
1814                    } else {
1815                        out.writeInt(0);
1816                    }
1817                }
1818            }
1819
1820            int NSE = u.mSensorStats.size();
1821            out.writeInt(NSE);
1822            if (NSE > 0) {
1823                for (Map.Entry<Integer, BatteryStatsImpl.Uid.Sensor> ent
1824                        : u.mSensorStats.entrySet()) {
1825                    out.writeInt(ent.getKey());
1826                    Uid.Sensor se = ent.getValue();
1827                    if (se.mTimer != null) {
1828                        out.writeInt(1);
1829                        se.mTimer.writeSummaryFromParcelLocked(out, NOW);
1830                    } else {
1831                        out.writeInt(0);
1832                    }
1833                }
1834            }
1835
1836            int NP = u.mProcessStats.size();
1837            out.writeInt(NP);
1838            if (NP > 0) {
1839                for (Map.Entry<String, BatteryStatsImpl.Uid.Proc> ent
1840                    : u.mProcessStats.entrySet()) {
1841                    out.writeString(ent.getKey());
1842                    Uid.Proc ps = ent.getValue();
1843                    out.writeLong(ps.mUserTime);
1844                    out.writeLong(ps.mUserTime - ps.mLoadedUserTime);
1845                    out.writeLong(ps.mSystemTime);
1846                    out.writeLong(ps.mSystemTime - ps.mLoadedSystemTime);
1847                    out.writeInt(ps.mStarts);
1848                    out.writeInt(ps.mStarts - ps.mLoadedStarts);
1849                }
1850            }
1851
1852            NP = u.mPackageStats.size();
1853            out.writeInt(NP);
1854            if (NP > 0) {
1855                for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg> ent
1856                    : u.mPackageStats.entrySet()) {
1857                    out.writeString(ent.getKey());
1858                    Uid.Pkg ps = ent.getValue();
1859                    out.writeInt(ps.mWakeups);
1860                    out.writeInt(ps.mWakeups - ps.mLoadedWakeups);
1861                    final int NS = ps.mServiceStats.size();
1862                    out.writeInt(NS);
1863                    if (NS > 0) {
1864                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
1865                                : ps.mServiceStats.entrySet()) {
1866                            out.writeString(sent.getKey());
1867                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
1868                            long time = ss.getStartTimeToNowLocked(NOW);
1869                            out.writeLong(time);
1870                            out.writeLong(time - ss.mLoadedStartTime);
1871                            out.writeInt(ss.mStarts);
1872                            out.writeInt(ss.mStarts - ss.mLoadedStarts);
1873                            out.writeInt(ss.mLaunches);
1874                            out.writeInt(ss.mLaunches - ss.mLoadedLaunches);
1875                        }
1876                    }
1877                }
1878            }
1879
1880            out.writeLong(u.getTcpBytesReceived(STATS_TOTAL));
1881            out.writeLong(u.getTcpBytesSent(STATS_TOTAL));
1882        }
1883    }
1884
1885    public void readFromParcel(Parcel in) {
1886        readFromParcelLocked(in);
1887    }
1888
1889    void readFromParcelLocked(Parcel in) {
1890        int magic = in.readInt();
1891        if (magic != MAGIC) {
1892            throw new ParcelFormatException("Bad magic number");
1893        }
1894
1895        mStartCount = in.readInt();
1896        mBatteryUptime = in.readLong();
1897        mBatteryLastUptime = in.readLong();
1898        mBatteryRealtime = in.readLong();
1899        mBatteryLastRealtime = in.readLong();
1900        mBatteryScreenOnTimeMillis = in.readLong();
1901        mPluggedScreenOnTimeMillis = in.readLong();
1902        mScreenOn = false;
1903        mUptime = in.readLong();
1904        mUptimeStart = in.readLong();
1905        mLastUptime = in.readLong();
1906        mRealtime = in.readLong();
1907        mRealtimeStart = in.readLong();
1908        mLastRealtime = in.readLong();
1909        mOnBattery = in.readInt() != 0;
1910        mOnBatteryInternal = false; // we are no longer really running.
1911        mTrackBatteryPastUptime = in.readLong();
1912        mTrackBatteryUptimeStart = in.readLong();
1913        mTrackBatteryPastRealtime = in.readLong();
1914        mTrackBatteryRealtimeStart = in.readLong();
1915        mLastWriteTime = in.readLong();
1916
1917        mPartialTimers.clear();
1918        mFullTimers.clear();
1919        mWindowTimers.clear();
1920
1921        int numUids = in.readInt();
1922        mUidStats.clear();
1923        for (int i = 0; i < numUids; i++) {
1924            int uid = in.readInt();
1925            Uid u = new Uid(uid);
1926            u.readFromParcelLocked(mUnpluggables, in);
1927            mUidStats.append(uid, u);
1928        }
1929    }
1930
1931    public void writeToParcel(Parcel out, int flags) {
1932        writeToParcelLocked(out, flags);
1933    }
1934
1935    @SuppressWarnings("unused")
1936    void writeToParcelLocked(Parcel out, int flags) {
1937        final long uSecUptime = SystemClock.uptimeMillis() * 1000;
1938        final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
1939        final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
1940        final long batteryRealtime = getBatteryRealtimeLocked(uSecRealtime);
1941
1942        out.writeInt(MAGIC);
1943        out.writeInt(mStartCount);
1944        out.writeLong(mBatteryUptime);
1945        out.writeLong(mBatteryLastUptime);
1946        out.writeLong(mBatteryRealtime);
1947        out.writeLong(mBatteryLastRealtime);
1948        out.writeLong(mBatteryScreenOnTimeMillis);
1949        out.writeLong(mPluggedScreenOnTimeMillis);
1950        out.writeLong(mUptime);
1951        out.writeLong(mUptimeStart);
1952        out.writeLong(mLastUptime);
1953        out.writeLong(mRealtime);
1954        out.writeLong(mRealtimeStart);
1955        out.writeLong(mLastRealtime);
1956        out.writeInt(mOnBattery ? 1 : 0);
1957        out.writeLong(mTrackBatteryPastUptime);
1958        out.writeLong(mTrackBatteryUptimeStart);
1959        out.writeLong(mTrackBatteryPastRealtime);
1960        out.writeLong(mTrackBatteryRealtimeStart);
1961        out.writeLong(mLastWriteTime);
1962
1963        int size = mUidStats.size();
1964        out.writeInt(size);
1965        for (int i = 0; i < size; i++) {
1966            out.writeInt(mUidStats.keyAt(i));
1967            Uid uid = mUidStats.valueAt(i);
1968
1969            uid.writeToParcelLocked(out, batteryRealtime);
1970        }
1971    }
1972
1973    public static final Parcelable.Creator<BatteryStatsImpl> CREATOR =
1974        new Parcelable.Creator<BatteryStatsImpl>() {
1975        public BatteryStatsImpl createFromParcel(Parcel in) {
1976            return new BatteryStatsImpl(in);
1977        }
1978
1979        public BatteryStatsImpl[] newArray(int size) {
1980            return new BatteryStatsImpl[size];
1981        }
1982    };
1983}
1984