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