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