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