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