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