1/*
2 * Copyright (C) 2013 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.app.procstats;
18
19import android.os.Parcel;
20import android.os.SystemClock;
21import android.os.UserHandle;
22import android.service.procstats.ProcessStatsProto;
23import android.util.ArrayMap;
24import android.util.DebugUtils;
25import android.util.Log;
26import android.util.LongSparseArray;
27import android.util.Slog;
28import android.util.TimeUtils;
29import android.util.proto.ProtoOutputStream;
30import android.util.proto.ProtoUtils;
31
32import com.android.internal.app.procstats.ProcessStats.PackageState;
33import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
34import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
35import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
36import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
37import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
38import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
39import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM;
40import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE;
41import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM;
42import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
43import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
44import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
45import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
46import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
47import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
48import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
49import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
50import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
51import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
52import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
53import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
54import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
55import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
56import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
57import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
58import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
59import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
60import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
61import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
62
63import java.io.PrintWriter;
64import java.util.Comparator;
65import java.util.HashMap;
66import java.util.Map;
67
68public final class ProcessState {
69    private static final String TAG = "ProcessStats";
70    private static final boolean DEBUG = false;
71    private static final boolean DEBUG_PARCEL = false;
72
73    // Map from process states to the states we track.
74    private static final int[] PROCESS_STATE_TO_STATE = new int[] {
75        STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
76        STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
77        STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
78        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
79        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
80        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
81        STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
82        STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
83        STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
84        STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
85        STATE_RECEIVER,                 // ActivityManager.PROCESS_STATE_RECEIVER
86        STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
87        STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
88        STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
89        STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
90        STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
91        STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
92        STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_RECENT
93        STATE_CACHED_EMPTY,             // ActivityManager.PROCESS_STATE_CACHED_EMPTY
94    };
95
96    public static final Comparator<ProcessState> COMPARATOR = new Comparator<ProcessState>() {
97            @Override
98            public int compare(ProcessState lhs, ProcessState rhs) {
99                if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
100                    return -1;
101                } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
102                    return 1;
103                }
104                return 0;
105            }
106        };
107
108    static class PssAggr {
109        long pss = 0;
110        long samples = 0;
111
112        void add(long newPss, long newSamples) {
113            pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
114                    / (samples+newSamples);
115            samples += newSamples;
116        }
117    }
118
119    // Used by reset to count rather than storing extra maps. Be careful.
120    public int tmpNumInUse;
121    public ProcessState tmpFoundSubProc;
122
123    private final ProcessStats mStats;
124    private final String mName;
125    private final String mPackage;
126    private final int mUid;
127    private final long mVersion;
128    private final DurationsTable mDurations;
129    private final PssTable mPssTable;
130
131    private ProcessState mCommonProcess;
132    private int mCurState = STATE_NOTHING;
133    private long mStartTime;
134
135    private int mLastPssState = STATE_NOTHING;
136    private long mLastPssTime;
137
138    private boolean mActive;
139    private int mNumActiveServices;
140    private int mNumStartedServices;
141
142    private int mNumExcessiveCpu;
143
144    private int mNumCachedKill;
145    private long mMinCachedKillPss;
146    private long mAvgCachedKillPss;
147    private long mMaxCachedKillPss;
148
149    private boolean mMultiPackage;
150    private boolean mDead;
151
152    // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
153    private long mTmpTotalTime;
154
155    /**
156     * Create a new top-level process state, for the initial case where there is only
157     * a single package running in a process.  The initial state is not running.
158     */
159    public ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name) {
160        mStats = processStats;
161        mName = name;
162        mCommonProcess = this;
163        mPackage = pkg;
164        mUid = uid;
165        mVersion = vers;
166        mDurations = new DurationsTable(processStats.mTableData);
167        mPssTable = new PssTable(processStats.mTableData);
168    }
169
170    /**
171     * Create a new per-package process state for an existing top-level process
172     * state.  The current running state of the top-level process is also copied,
173     * marked as started running at 'now'.
174     */
175    public ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name,
176            long now) {
177        mStats = commonProcess.mStats;
178        mName = name;
179        mCommonProcess = commonProcess;
180        mPackage = pkg;
181        mUid = uid;
182        mVersion = vers;
183        mCurState = commonProcess.mCurState;
184        mStartTime = now;
185        mDurations = new DurationsTable(commonProcess.mStats.mTableData);
186        mPssTable = new PssTable(commonProcess.mStats.mTableData);
187    }
188
189    public ProcessState clone(long now) {
190        ProcessState pnew = new ProcessState(this, mPackage, mUid, mVersion, mName, now);
191        pnew.mDurations.addDurations(mDurations);
192        pnew.mPssTable.copyFrom(mPssTable, PSS_COUNT);
193        pnew.mNumExcessiveCpu = mNumExcessiveCpu;
194        pnew.mNumCachedKill = mNumCachedKill;
195        pnew.mMinCachedKillPss = mMinCachedKillPss;
196        pnew.mAvgCachedKillPss = mAvgCachedKillPss;
197        pnew.mMaxCachedKillPss = mMaxCachedKillPss;
198        pnew.mActive = mActive;
199        pnew.mNumActiveServices = mNumActiveServices;
200        pnew.mNumStartedServices = mNumStartedServices;
201        return pnew;
202    }
203
204    public String getName() {
205        return mName;
206    }
207
208    public ProcessState getCommonProcess() {
209        return mCommonProcess;
210    }
211
212    /**
213     * Say that we are not part of a shared process, so mCommonProcess = this.
214     */
215    public void makeStandalone() {
216        mCommonProcess = this;
217    }
218
219    public String getPackage() {
220        return mPackage;
221    }
222
223    public int getUid() {
224        return mUid;
225    }
226
227    public long getVersion() {
228        return mVersion;
229    }
230
231    public boolean isMultiPackage() {
232        return mMultiPackage;
233    }
234
235    public void setMultiPackage(boolean val) {
236        mMultiPackage = val;
237    }
238
239    public int getDurationsBucketCount() {
240        return mDurations.getKeyCount();
241    }
242
243    public void add(ProcessState other) {
244        mDurations.addDurations(other.mDurations);
245        mPssTable.mergeStats(other.mPssTable);
246        mNumExcessiveCpu += other.mNumExcessiveCpu;
247        if (other.mNumCachedKill > 0) {
248            addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
249                    other.mAvgCachedKillPss, other.mMaxCachedKillPss);
250        }
251    }
252
253    public void resetSafely(long now) {
254        mDurations.resetTable();
255        mPssTable.resetTable();
256        mStartTime = now;
257        mLastPssState = STATE_NOTHING;
258        mLastPssTime = 0;
259        mNumExcessiveCpu = 0;
260        mNumCachedKill = 0;
261        mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
262    }
263
264    public void makeDead() {
265        mDead = true;
266    }
267
268    private void ensureNotDead() {
269        if (!mDead) {
270            return;
271        }
272        Slog.w(TAG, "ProcessState dead: name=" + mName
273                + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
274    }
275
276    public void writeToParcel(Parcel out, long now) {
277        out.writeInt(mMultiPackage ? 1 : 0);
278        mDurations.writeToParcel(out);
279        mPssTable.writeToParcel(out);
280        out.writeInt(0);  // was mNumExcessiveWake
281        out.writeInt(mNumExcessiveCpu);
282        out.writeInt(mNumCachedKill);
283        if (mNumCachedKill > 0) {
284            out.writeLong(mMinCachedKillPss);
285            out.writeLong(mAvgCachedKillPss);
286            out.writeLong(mMaxCachedKillPss);
287        }
288    }
289
290    public boolean readFromParcel(Parcel in, boolean fully) {
291        boolean multiPackage = in.readInt() != 0;
292        if (fully) {
293            mMultiPackage = multiPackage;
294        }
295        if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
296        if (!mDurations.readFromParcel(in)) {
297            return false;
298        }
299        if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
300        if (!mPssTable.readFromParcel(in)) {
301            return false;
302        }
303        in.readInt(); // was mNumExcessiveWake
304        mNumExcessiveCpu = in.readInt();
305        mNumCachedKill = in.readInt();
306        if (mNumCachedKill > 0) {
307            mMinCachedKillPss = in.readLong();
308            mAvgCachedKillPss = in.readLong();
309            mMaxCachedKillPss = in.readLong();
310        } else {
311            mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
312        }
313        return true;
314    }
315
316    public void makeActive() {
317        ensureNotDead();
318        mActive = true;
319    }
320
321    public void makeInactive() {
322        mActive = false;
323    }
324
325    public boolean isInUse() {
326        return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
327                || mCurState != STATE_NOTHING;
328    }
329
330    public boolean isActive() {
331        return mActive;
332    }
333
334    public boolean hasAnyData() {
335        return !(mDurations.getKeyCount() == 0
336                && mCurState == STATE_NOTHING
337                && mPssTable.getKeyCount() == 0);
338    }
339
340    /**
341     * Update the current state of the given list of processes.
342     *
343     * @param state Current ActivityManager.PROCESS_STATE_*
344     * @param memFactor Current mem factor constant.
345     * @param now Current time.
346     * @param pkgList Processes to update.
347     */
348    public void setState(int state, int memFactor, long now,
349            ArrayMap<String, ProcessStateHolder> pkgList) {
350        if (state < 0) {
351            state = mNumStartedServices > 0
352                    ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
353        } else {
354            state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
355        }
356
357        // First update the common process.
358        mCommonProcess.setState(state, now);
359
360        // If the common process is not multi-package, there is nothing else to do.
361        if (!mCommonProcess.mMultiPackage) {
362            return;
363        }
364
365        if (pkgList != null) {
366            for (int ip=pkgList.size()-1; ip>=0; ip--) {
367                pullFixedProc(pkgList, ip).setState(state, now);
368            }
369        }
370    }
371
372    public void setState(int state, long now) {
373        ensureNotDead();
374        if (!mDead && (mCurState != state)) {
375            //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
376            commitStateTime(now);
377            mCurState = state;
378        }
379    }
380
381    public void commitStateTime(long now) {
382        if (mCurState != STATE_NOTHING) {
383            long dur = now - mStartTime;
384            if (dur > 0) {
385                mDurations.addDuration(mCurState, dur);
386            }
387        }
388        mStartTime = now;
389    }
390
391    public void incActiveServices(String serviceName) {
392        if (DEBUG && "".equals(mName)) {
393            RuntimeException here = new RuntimeException("here");
394            here.fillInStackTrace();
395            Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
396                    + " to " + (mNumActiveServices+1), here);
397        }
398        if (mCommonProcess != this) {
399            mCommonProcess.incActiveServices(serviceName);
400        }
401        mNumActiveServices++;
402    }
403
404    public void decActiveServices(String serviceName) {
405        if (DEBUG && "".equals(mName)) {
406            RuntimeException here = new RuntimeException("here");
407            here.fillInStackTrace();
408            Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
409                    + " to " + (mNumActiveServices-1), here);
410        }
411        if (mCommonProcess != this) {
412            mCommonProcess.decActiveServices(serviceName);
413        }
414        mNumActiveServices--;
415        if (mNumActiveServices < 0) {
416            Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
417                    + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
418            mNumActiveServices = 0;
419        }
420    }
421
422    public void incStartedServices(int memFactor, long now, String serviceName) {
423        if (false) {
424            RuntimeException here = new RuntimeException("here");
425            here.fillInStackTrace();
426            Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
427                    + " to " + (mNumStartedServices+1), here);
428        }
429        if (mCommonProcess != this) {
430            mCommonProcess.incStartedServices(memFactor, now, serviceName);
431        }
432        mNumStartedServices++;
433        if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) {
434            setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
435        }
436    }
437
438    public void decStartedServices(int memFactor, long now, String serviceName) {
439        if (false) {
440            RuntimeException here = new RuntimeException("here");
441            here.fillInStackTrace();
442            Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
443                    + " to " + (mNumStartedServices-1), here);
444        }
445        if (mCommonProcess != this) {
446            mCommonProcess.decStartedServices(memFactor, now, serviceName);
447        }
448        mNumStartedServices--;
449        if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) {
450            setState(STATE_NOTHING, now);
451        } else if (mNumStartedServices < 0) {
452            Slog.wtfStack(TAG, "Proc started services underrun: pkg="
453                    + mPackage + " uid=" + mUid + " name=" + mName);
454            mNumStartedServices = 0;
455        }
456    }
457
458    public void addPss(long pss, long uss, long rss, boolean always, int type, long duration,
459            ArrayMap<String, ProcessStateHolder> pkgList) {
460        ensureNotDead();
461        switch (type) {
462            case ProcessStats.ADD_PSS_INTERNAL_SINGLE:
463                mStats.mInternalSinglePssCount++;
464                mStats.mInternalSinglePssTime += duration;
465                break;
466            case ProcessStats.ADD_PSS_INTERNAL_ALL_MEM:
467                mStats.mInternalAllMemPssCount++;
468                mStats.mInternalAllMemPssTime += duration;
469                break;
470            case ProcessStats.ADD_PSS_INTERNAL_ALL_POLL:
471                mStats.mInternalAllPollPssCount++;
472                mStats.mInternalAllPollPssTime += duration;
473                break;
474            case ProcessStats.ADD_PSS_EXTERNAL:
475                mStats.mExternalPssCount++;
476                mStats.mExternalPssTime += duration;
477                break;
478            case ProcessStats.ADD_PSS_EXTERNAL_SLOW:
479                mStats.mExternalSlowPssCount++;
480                mStats.mExternalSlowPssTime += duration;
481                break;
482        }
483        if (!always) {
484            if (mLastPssState == mCurState && SystemClock.uptimeMillis()
485                    < (mLastPssTime+(30*1000))) {
486                return;
487            }
488        }
489        mLastPssState = mCurState;
490        mLastPssTime = SystemClock.uptimeMillis();
491        if (mCurState != STATE_NOTHING) {
492            // First update the common process.
493            mCommonProcess.mPssTable.mergeStats(mCurState, 1, pss, pss, pss, uss, uss, uss,
494                    rss, rss, rss);
495
496            // If the common process is not multi-package, there is nothing else to do.
497            if (!mCommonProcess.mMultiPackage) {
498                return;
499            }
500
501            if (pkgList != null) {
502                for (int ip=pkgList.size()-1; ip>=0; ip--) {
503                    pullFixedProc(pkgList, ip).mPssTable.mergeStats(mCurState, 1,
504                            pss, pss, pss, uss, uss, uss, rss, rss, rss);
505                }
506            }
507        }
508    }
509
510    public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
511        ensureNotDead();
512        mCommonProcess.mNumExcessiveCpu++;
513        if (!mCommonProcess.mMultiPackage) {
514            return;
515        }
516
517        for (int ip=pkgList.size()-1; ip>=0; ip--) {
518            pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
519        }
520    }
521
522    private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
523        if (mNumCachedKill <= 0) {
524            mNumCachedKill = num;
525            mMinCachedKillPss = minPss;
526            mAvgCachedKillPss = avgPss;
527            mMaxCachedKillPss = maxPss;
528        } else {
529            if (minPss < mMinCachedKillPss) {
530                mMinCachedKillPss = minPss;
531            }
532            if (maxPss > mMaxCachedKillPss) {
533                mMaxCachedKillPss = maxPss;
534            }
535            mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
536                    / (mNumCachedKill+num) );
537            mNumCachedKill += num;
538        }
539    }
540
541    public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
542        ensureNotDead();
543        mCommonProcess.addCachedKill(1, pss, pss, pss);
544        if (!mCommonProcess.mMultiPackage) {
545            return;
546        }
547
548        for (int ip=pkgList.size()-1; ip>=0; ip--) {
549            pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
550        }
551    }
552
553    public ProcessState pullFixedProc(String pkgName) {
554        if (mMultiPackage) {
555            // The array map is still pointing to a common process state
556            // that is now shared across packages.  Update it to point to
557            // the new per-package state.
558            LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
559            if (vpkg == null) {
560                throw new IllegalStateException("Didn't find package " + pkgName
561                        + " / " + mUid);
562            }
563            PackageState pkg = vpkg.get(mVersion);
564            if (pkg == null) {
565                throw new IllegalStateException("Didn't find package " + pkgName
566                        + " / " + mUid + " vers " + mVersion);
567            }
568            ProcessState proc = pkg.mProcesses.get(mName);
569            if (proc == null) {
570                throw new IllegalStateException("Didn't create per-package process "
571                        + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
572            }
573            return proc;
574        }
575        return this;
576    }
577
578    private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
579            int index) {
580        ProcessStateHolder holder = pkgList.valueAt(index);
581        ProcessState proc = holder.state;
582        if (mDead && proc.mCommonProcess != proc) {
583            // Somehow we are contining to use a process state that is dead, because
584            // it was not being told it was active during the last commit.  We can recover
585            // from this by generating a fresh new state, but this is bad because we
586            // are losing whatever data we had in the old process state.
587            Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
588                    + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
589            proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
590                    proc.mName);
591        }
592        if (proc.mMultiPackage) {
593            // The array map is still pointing to a common process state
594            // that is now shared across packages.  Update it to point to
595            // the new per-package state.
596            LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
597                    proc.mUid);
598            if (vpkg == null) {
599                throw new IllegalStateException("No existing package "
600                        + pkgList.keyAt(index) + "/" + proc.mUid
601                        + " for multi-proc " + proc.mName);
602            }
603            PackageState pkg = vpkg.get(proc.mVersion);
604            if (pkg == null) {
605                throw new IllegalStateException("No existing package "
606                        + pkgList.keyAt(index) + "/" + proc.mUid
607                        + " for multi-proc " + proc.mName + " version " + proc.mVersion);
608            }
609            String savedName = proc.mName;
610            proc = pkg.mProcesses.get(proc.mName);
611            if (proc == null) {
612                throw new IllegalStateException("Didn't create per-package process "
613                        + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
614            }
615            holder.state = proc;
616        }
617        return proc;
618    }
619
620    public long getDuration(int state, long now) {
621        long time = mDurations.getValueForId((byte)state);
622        if (mCurState == state) {
623            time += now - mStartTime;
624        }
625        return time;
626    }
627
628    public long getPssSampleCount(int state) {
629        return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
630    }
631
632    public long getPssMinimum(int state) {
633        return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
634    }
635
636    public long getPssAverage(int state) {
637        return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
638    }
639
640    public long getPssMaximum(int state) {
641        return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
642    }
643
644    public long getPssUssMinimum(int state) {
645        return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
646    }
647
648    public long getPssUssAverage(int state) {
649        return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
650    }
651
652    public long getPssUssMaximum(int state) {
653        return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
654    }
655
656    public long getPssRssMinimum(int state) {
657        return mPssTable.getValueForId((byte)state, PSS_RSS_MINIMUM);
658    }
659
660    public long getPssRssAverage(int state) {
661        return mPssTable.getValueForId((byte)state, PSS_RSS_AVERAGE);
662    }
663
664    public long getPssRssMaximum(int state) {
665        return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
666    }
667
668    /**
669     * Sums up the PSS data and adds it to 'data'.
670     *
671     * @param data The aggregate data is added here.
672     * @param now SystemClock.uptimeMillis()
673     */
674    public void aggregatePss(TotalMemoryUseCollection data, long now) {
675        final PssAggr fgPss = new PssAggr();
676        final PssAggr bgPss = new PssAggr();
677        final PssAggr cachedPss = new PssAggr();
678        boolean havePss = false;
679        for (int i=0; i<mDurations.getKeyCount(); i++) {
680            final int key = mDurations.getKeyAt(i);
681            int type = SparseMappingTable.getIdFromKey(key);
682            int procState = type % STATE_COUNT;
683            long samples = getPssSampleCount(type);
684            if (samples > 0) {
685                long avg = getPssAverage(type);
686                havePss = true;
687                if (procState <= STATE_IMPORTANT_FOREGROUND) {
688                    fgPss.add(avg, samples);
689                } else if (procState <= STATE_RECEIVER) {
690                    bgPss.add(avg, samples);
691                } else {
692                    cachedPss.add(avg, samples);
693                }
694            }
695        }
696        if (!havePss) {
697            return;
698        }
699        boolean fgHasBg = false;
700        boolean fgHasCached = false;
701        boolean bgHasCached = false;
702        if (fgPss.samples < 3 && bgPss.samples > 0) {
703            fgHasBg = true;
704            fgPss.add(bgPss.pss, bgPss.samples);
705        }
706        if (fgPss.samples < 3 && cachedPss.samples > 0) {
707            fgHasCached = true;
708            fgPss.add(cachedPss.pss, cachedPss.samples);
709        }
710        if (bgPss.samples < 3 && cachedPss.samples > 0) {
711            bgHasCached = true;
712            bgPss.add(cachedPss.pss, cachedPss.samples);
713        }
714        if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
715            bgPss.add(fgPss.pss, fgPss.samples);
716        }
717        if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
718            cachedPss.add(bgPss.pss, bgPss.samples);
719        }
720        if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
721            cachedPss.add(fgPss.pss, fgPss.samples);
722        }
723        for (int i=0; i<mDurations.getKeyCount(); i++) {
724            final int key = mDurations.getKeyAt(i);
725            final int type = SparseMappingTable.getIdFromKey(key);
726            long time = mDurations.getValue(key);
727            if (mCurState == type) {
728                time += now - mStartTime;
729            }
730            final int procState = type % STATE_COUNT;
731            data.processStateTime[procState] += time;
732            long samples = getPssSampleCount(type);
733            long avg;
734            if (samples > 0) {
735                avg = getPssAverage(type);
736            } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
737                samples = fgPss.samples;
738                avg = fgPss.pss;
739            } else if (procState <= STATE_RECEIVER) {
740                samples = bgPss.samples;
741                avg = bgPss.pss;
742            } else {
743                samples = cachedPss.samples;
744                avg = cachedPss.pss;
745            }
746            double newAvg = ( (data.processStatePss[procState]
747                    * (double)data.processStateSamples[procState])
748                        + (avg*(double)samples)
749                    ) / (data.processStateSamples[procState]+samples);
750            data.processStatePss[procState] = (long)newAvg;
751            data.processStateSamples[procState] += samples;
752            data.processStateWeight[procState] += avg * (double)time;
753        }
754    }
755
756    public long computeProcessTimeLocked(int[] screenStates, int[] memStates,
757                int[] procStates, long now) {
758        long totalTime = 0;
759        for (int is=0; is<screenStates.length; is++) {
760            for (int im=0; im<memStates.length; im++) {
761                for (int ip=0; ip<procStates.length; ip++) {
762                    int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
763                            + procStates[ip];
764                    totalTime += getDuration(bucket, now);
765                }
766            }
767        }
768        mTmpTotalTime = totalTime;
769        return totalTime;
770    }
771
772    public void dumpSummary(PrintWriter pw, String prefix,
773            int[] screenStates, int[] memStates, int[] procStates,
774            long now, long totalTime) {
775        pw.print(prefix);
776        pw.print("* ");
777        pw.print(mName);
778        pw.print(" / ");
779        UserHandle.formatUid(pw, mUid);
780        pw.print(" / v");
781        pw.print(mVersion);
782        pw.println(":");
783        dumpProcessSummaryDetails(pw, prefix, "         TOTAL: ", screenStates, memStates,
784                procStates, now, totalTime, true);
785        dumpProcessSummaryDetails(pw, prefix, "    Persistent: ", screenStates, memStates,
786                new int[] { STATE_PERSISTENT }, now, totalTime, true);
787        dumpProcessSummaryDetails(pw, prefix, "           Top: ", screenStates, memStates,
788                new int[] {STATE_TOP}, now, totalTime, true);
789        dumpProcessSummaryDetails(pw, prefix, "        Imp Fg: ", screenStates, memStates,
790                new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true);
791        dumpProcessSummaryDetails(pw, prefix, "        Imp Bg: ", screenStates, memStates,
792                new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true);
793        dumpProcessSummaryDetails(pw, prefix, "        Backup: ", screenStates, memStates,
794                new int[] {STATE_BACKUP}, now, totalTime, true);
795        dumpProcessSummaryDetails(pw, prefix, "     Heavy Wgt: ", screenStates, memStates,
796                new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
797        dumpProcessSummaryDetails(pw, prefix, "       Service: ", screenStates, memStates,
798                new int[] {STATE_SERVICE}, now, totalTime, true);
799        dumpProcessSummaryDetails(pw, prefix, "    Service Rs: ", screenStates, memStates,
800                new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true);
801        dumpProcessSummaryDetails(pw, prefix, "      Receiver: ", screenStates, memStates,
802                new int[] {STATE_RECEIVER}, now, totalTime, true);
803        dumpProcessSummaryDetails(pw, prefix, "         Heavy: ", screenStates, memStates,
804                new int[] {STATE_HOME}, now, totalTime, true);
805        dumpProcessSummaryDetails(pw, prefix, "        (Home): ", screenStates, memStates,
806                new int[] {STATE_HOME}, now, totalTime, true);
807        dumpProcessSummaryDetails(pw, prefix, "    (Last Act): ", screenStates, memStates,
808                new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
809        dumpProcessSummaryDetails(pw, prefix, "      (Cached): ", screenStates, memStates,
810                new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT,
811                        STATE_CACHED_EMPTY}, now, totalTime, true);
812    }
813
814    public void dumpProcessState(PrintWriter pw, String prefix,
815            int[] screenStates, int[] memStates, int[] procStates, long now) {
816        long totalTime = 0;
817        int printedScreen = -1;
818        for (int is=0; is<screenStates.length; is++) {
819            int printedMem = -1;
820            for (int im=0; im<memStates.length; im++) {
821                for (int ip=0; ip<procStates.length; ip++) {
822                    final int iscreen = screenStates[is];
823                    final int imem = memStates[im];
824                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
825                    long time = mDurations.getValueForId((byte)bucket);
826                    String running = "";
827                    if (mCurState == bucket) {
828                        running = " (running)";
829                    }
830                    if (time != 0) {
831                        pw.print(prefix);
832                        if (screenStates.length > 1) {
833                            DumpUtils.printScreenLabel(pw, printedScreen != iscreen
834                                    ? iscreen : STATE_NOTHING);
835                            printedScreen = iscreen;
836                        }
837                        if (memStates.length > 1) {
838                            DumpUtils.printMemLabel(pw,
839                                    printedMem != imem ? imem : STATE_NOTHING, '/');
840                            printedMem = imem;
841                        }
842                        pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
843                        TimeUtils.formatDuration(time, pw); pw.println(running);
844                        totalTime += time;
845                    }
846                }
847            }
848        }
849        if (totalTime != 0) {
850            pw.print(prefix);
851            if (screenStates.length > 1) {
852                DumpUtils.printScreenLabel(pw, STATE_NOTHING);
853            }
854            if (memStates.length > 1) {
855                DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
856            }
857            pw.print("TOTAL  : ");
858            TimeUtils.formatDuration(totalTime, pw);
859            pw.println();
860        }
861    }
862
863    public void dumpPss(PrintWriter pw, String prefix,
864            int[] screenStates, int[] memStates, int[] procStates) {
865        boolean printedHeader = false;
866        int printedScreen = -1;
867        for (int is=0; is<screenStates.length; is++) {
868            int printedMem = -1;
869            for (int im=0; im<memStates.length; im++) {
870                for (int ip=0; ip<procStates.length; ip++) {
871                    final int iscreen = screenStates[is];
872                    final int imem = memStates[im];
873                    final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
874                    long count = getPssSampleCount(bucket);
875                    if (count > 0) {
876                        if (!printedHeader) {
877                            pw.print(prefix);
878                            pw.print("PSS/USS (");
879                            pw.print(mPssTable.getKeyCount());
880                            pw.println(" entries):");
881                            printedHeader = true;
882                        }
883                        pw.print(prefix);
884                        pw.print("  ");
885                        if (screenStates.length > 1) {
886                            DumpUtils.printScreenLabel(pw,
887                                    printedScreen != iscreen ? iscreen : STATE_NOTHING);
888                            printedScreen = iscreen;
889                        }
890                        if (memStates.length > 1) {
891                            DumpUtils.printMemLabel(pw,
892                                    printedMem != imem ? imem : STATE_NOTHING, '/');
893                            printedMem = imem;
894                        }
895                        pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": ");
896                        pw.print(count);
897                        pw.print(" samples ");
898                        DebugUtils.printSizeValue(pw, getPssMinimum(bucket) * 1024);
899                        pw.print(" ");
900                        DebugUtils.printSizeValue(pw, getPssAverage(bucket) * 1024);
901                        pw.print(" ");
902                        DebugUtils.printSizeValue(pw, getPssMaximum(bucket) * 1024);
903                        pw.print(" / ");
904                        DebugUtils.printSizeValue(pw, getPssUssMinimum(bucket) * 1024);
905                        pw.print(" ");
906                        DebugUtils.printSizeValue(pw, getPssUssAverage(bucket) * 1024);
907                        pw.print(" ");
908                        DebugUtils.printSizeValue(pw, getPssUssMaximum(bucket) * 1024);
909                        pw.print(" / ");
910                        DebugUtils.printSizeValue(pw, getPssRssMinimum(bucket) * 1024);
911                        pw.print(" ");
912                        DebugUtils.printSizeValue(pw, getPssRssAverage(bucket) * 1024);
913                        pw.print(" ");
914                        DebugUtils.printSizeValue(pw, getPssRssMaximum(bucket) * 1024);
915                        pw.println();
916                    }
917                }
918            }
919        }
920        if (mNumExcessiveCpu != 0) {
921            pw.print(prefix); pw.print("Killed for excessive CPU use: ");
922                    pw.print(mNumExcessiveCpu); pw.println(" times");
923        }
924        if (mNumCachedKill != 0) {
925            pw.print(prefix); pw.print("Killed from cached state: ");
926                    pw.print(mNumCachedKill); pw.print(" times from pss ");
927                    DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-");
928                    DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-");
929                    DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println();
930        }
931    }
932
933    private void dumpProcessSummaryDetails(PrintWriter pw, String prefix,
934            String label, int[] screenStates, int[] memStates, int[] procStates,
935            long now, long totalTime, boolean full) {
936        ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
937                screenStates, memStates, procStates);
938        computeProcessData(totals, now);
939        final double percentage = (double) totals.totalTime / (double) totalTime * 100;
940        // We don't print percentages < .01, so just drop those.
941        if (percentage >= 0.005 || totals.numPss != 0) {
942            if (prefix != null) {
943                pw.print(prefix);
944            }
945            if (label != null) {
946                pw.print(label);
947            }
948            totals.print(pw, totalTime, full);
949            if (prefix != null) {
950                pw.println();
951            }
952        }
953    }
954
955    public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) {
956        if (dumpAll) {
957            pw.print(prefix); pw.print("myID=");
958                    pw.print(Integer.toHexString(System.identityHashCode(this)));
959                    pw.print(" mCommonProcess=");
960                    pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess)));
961                    pw.print(" mPackage="); pw.println(mPackage);
962            if (mMultiPackage) {
963                pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage);
964            }
965            if (this != mCommonProcess) {
966                pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName);
967                        pw.print("/"); pw.print(mCommonProcess.mUid);
968                        pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
969            }
970        }
971        if (mActive) {
972            pw.print(prefix); pw.print("mActive="); pw.println(mActive);
973        }
974        if (mDead) {
975            pw.print(prefix); pw.print("mDead="); pw.println(mDead);
976        }
977        if (mNumActiveServices != 0 || mNumStartedServices != 0) {
978            pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices);
979                    pw.print(" mNumStartedServices=");
980                    pw.println(mNumStartedServices);
981        }
982    }
983
984    public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) {
985        data.totalTime = 0;
986        data.numPss = data.minPss = data.avgPss = data.maxPss =
987                data.minUss = data.avgUss = data.maxUss =
988                data.minRss = data.avgRss = data.maxRss = 0;
989        for (int is=0; is<data.screenStates.length; is++) {
990            for (int im=0; im<data.memStates.length; im++) {
991                for (int ip=0; ip<data.procStates.length; ip++) {
992                    int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
993                            + data.procStates[ip];
994                    data.totalTime += getDuration(bucket, now);
995                    long samples = getPssSampleCount(bucket);
996                    if (samples > 0) {
997                        long minPss = getPssMinimum(bucket);
998                        long avgPss = getPssAverage(bucket);
999                        long maxPss = getPssMaximum(bucket);
1000                        long minUss = getPssUssMinimum(bucket);
1001                        long avgUss = getPssUssAverage(bucket);
1002                        long maxUss = getPssUssMaximum(bucket);
1003                        long minRss = getPssRssMinimum(bucket);
1004                        long avgRss = getPssRssAverage(bucket);
1005                        long maxRss = getPssRssMaximum(bucket);
1006                        if (data.numPss == 0) {
1007                            data.minPss = minPss;
1008                            data.avgPss = avgPss;
1009                            data.maxPss = maxPss;
1010                            data.minUss = minUss;
1011                            data.avgUss = avgUss;
1012                            data.maxUss = maxUss;
1013                            data.minRss = minRss;
1014                            data.avgRss = avgRss;
1015                            data.maxRss = maxRss;
1016                        } else {
1017                            if (minPss < data.minPss) {
1018                                data.minPss = minPss;
1019                            }
1020                            data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
1021                                    + (avgPss*(double)samples)) / (data.numPss+samples) );
1022                            if (maxPss > data.maxPss) {
1023                                data.maxPss = maxPss;
1024                            }
1025                            if (minUss < data.minUss) {
1026                                data.minUss = minUss;
1027                            }
1028                            data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
1029                                    + (avgUss*(double)samples)) / (data.numPss+samples) );
1030                            if (maxUss > data.maxUss) {
1031                                data.maxUss = maxUss;
1032                            }
1033                            if (minRss < data.minRss) {
1034                                data.minRss = minRss;
1035                            }
1036                            data.avgRss = (long)( ((data.avgRss*(double)data.numPss)
1037                                    + (avgRss*(double)samples)) / (data.numPss+samples) );
1038                            if (maxRss > data.maxRss) {
1039                                data.maxRss = maxRss;
1040                            }
1041                        }
1042                        data.numPss += samples;
1043                    }
1044                }
1045            }
1046        }
1047    }
1048
1049    public void dumpCsv(PrintWriter pw,
1050            boolean sepScreenStates, int[] screenStates, boolean sepMemStates,
1051            int[] memStates, boolean sepProcStates, int[] procStates, long now) {
1052        final int NSS = sepScreenStates ? screenStates.length : 1;
1053        final int NMS = sepMemStates ? memStates.length : 1;
1054        final int NPS = sepProcStates ? procStates.length : 1;
1055        for (int iss=0; iss<NSS; iss++) {
1056            for (int ims=0; ims<NMS; ims++) {
1057                for (int ips=0; ips<NPS; ips++) {
1058                    final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
1059                    final int vsmem = sepMemStates ? memStates[ims] : 0;
1060                    final int vsproc = sepProcStates ? procStates[ips] : 0;
1061                    final int NSA = sepScreenStates ? 1 : screenStates.length;
1062                    final int NMA = sepMemStates ? 1 : memStates.length;
1063                    final int NPA = sepProcStates ? 1 : procStates.length;
1064                    long totalTime = 0;
1065                    for (int isa=0; isa<NSA; isa++) {
1066                        for (int ima=0; ima<NMA; ima++) {
1067                            for (int ipa=0; ipa<NPA; ipa++) {
1068                                final int vascreen = sepScreenStates ? 0 : screenStates[isa];
1069                                final int vamem = sepMemStates ? 0 : memStates[ima];
1070                                final int vaproc = sepProcStates ? 0 : procStates[ipa];
1071                                final int bucket = ((vsscreen + vascreen + vsmem + vamem)
1072                                        * STATE_COUNT) + vsproc + vaproc;
1073                                totalTime += getDuration(bucket, now);
1074                            }
1075                        }
1076                    }
1077                    pw.print(DumpUtils.CSV_SEP);
1078                    pw.print(totalTime);
1079                }
1080            }
1081        }
1082    }
1083
1084    public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers,
1085            String itemName, long now) {
1086        pw.print("pkgproc,");
1087        pw.print(pkgName);
1088        pw.print(",");
1089        pw.print(uid);
1090        pw.print(",");
1091        pw.print(vers);
1092        pw.print(",");
1093        pw.print(DumpUtils.collapseString(pkgName, itemName));
1094        dumpAllStateCheckin(pw, now);
1095        pw.println();
1096        if (mPssTable.getKeyCount() > 0) {
1097            pw.print("pkgpss,");
1098            pw.print(pkgName);
1099            pw.print(",");
1100            pw.print(uid);
1101            pw.print(",");
1102            pw.print(vers);
1103            pw.print(",");
1104            pw.print(DumpUtils.collapseString(pkgName, itemName));
1105            dumpAllPssCheckin(pw);
1106            pw.println();
1107        }
1108        if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1109            pw.print("pkgkills,");
1110            pw.print(pkgName);
1111            pw.print(",");
1112            pw.print(uid);
1113            pw.print(",");
1114            pw.print(vers);
1115            pw.print(",");
1116            pw.print(DumpUtils.collapseString(pkgName, itemName));
1117            pw.print(",");
1118            pw.print("0"); // was mNumExcessiveWake
1119            pw.print(",");
1120            pw.print(mNumExcessiveCpu);
1121            pw.print(",");
1122            pw.print(mNumCachedKill);
1123            pw.print(",");
1124            pw.print(mMinCachedKillPss);
1125            pw.print(":");
1126            pw.print(mAvgCachedKillPss);
1127            pw.print(":");
1128            pw.print(mMaxCachedKillPss);
1129            pw.println();
1130        }
1131    }
1132
1133    public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) {
1134        if (mDurations.getKeyCount() > 0) {
1135            pw.print("proc,");
1136            pw.print(procName);
1137            pw.print(",");
1138            pw.print(uid);
1139            dumpAllStateCheckin(pw, now);
1140            pw.println();
1141        }
1142        if (mPssTable.getKeyCount() > 0) {
1143            pw.print("pss,");
1144            pw.print(procName);
1145            pw.print(",");
1146            pw.print(uid);
1147            dumpAllPssCheckin(pw);
1148            pw.println();
1149        }
1150        if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1151            pw.print("kills,");
1152            pw.print(procName);
1153            pw.print(",");
1154            pw.print(uid);
1155            pw.print(",");
1156            pw.print("0"); // was mNumExcessiveWake
1157            pw.print(",");
1158            pw.print(mNumExcessiveCpu);
1159            pw.print(",");
1160            pw.print(mNumCachedKill);
1161            pw.print(",");
1162            pw.print(mMinCachedKillPss);
1163            pw.print(":");
1164            pw.print(mAvgCachedKillPss);
1165            pw.print(":");
1166            pw.print(mMaxCachedKillPss);
1167            pw.println();
1168        }
1169    }
1170
1171    public void dumpAllStateCheckin(PrintWriter pw, long now) {
1172        boolean didCurState = false;
1173        for (int i=0; i<mDurations.getKeyCount(); i++) {
1174            final int key = mDurations.getKeyAt(i);
1175            final int type = SparseMappingTable.getIdFromKey(key);
1176            long time = mDurations.getValue(key);
1177            if (mCurState == type) {
1178                didCurState = true;
1179                time += now - mStartTime;
1180            }
1181            DumpUtils.printProcStateTagAndValue(pw, type, time);
1182        }
1183        if (!didCurState && mCurState != STATE_NOTHING) {
1184            DumpUtils.printProcStateTagAndValue(pw, mCurState, now - mStartTime);
1185        }
1186    }
1187
1188    public void dumpAllPssCheckin(PrintWriter pw) {
1189        final int N = mPssTable.getKeyCount();
1190        for (int i=0; i<N; i++) {
1191            final int key = mPssTable.getKeyAt(i);
1192            final int type = SparseMappingTable.getIdFromKey(key);
1193            pw.print(',');
1194            DumpUtils.printProcStateTag(pw, type);
1195            pw.print(':');
1196            pw.print(mPssTable.getValue(key, PSS_SAMPLE_COUNT));
1197            pw.print(':');
1198            pw.print(mPssTable.getValue(key, PSS_MINIMUM));
1199            pw.print(':');
1200            pw.print(mPssTable.getValue(key, PSS_AVERAGE));
1201            pw.print(':');
1202            pw.print(mPssTable.getValue(key, PSS_MAXIMUM));
1203            pw.print(':');
1204            pw.print(mPssTable.getValue(key, PSS_USS_MINIMUM));
1205            pw.print(':');
1206            pw.print(mPssTable.getValue(key, PSS_USS_AVERAGE));
1207            pw.print(':');
1208            pw.print(mPssTable.getValue(key, PSS_USS_MAXIMUM));
1209            pw.print(':');
1210            pw.print(mPssTable.getValue(key, PSS_RSS_MINIMUM));
1211            pw.print(':');
1212            pw.print(mPssTable.getValue(key, PSS_RSS_AVERAGE));
1213            pw.print(':');
1214            pw.print(mPssTable.getValue(key, PSS_RSS_MAXIMUM));
1215        }
1216    }
1217
1218    @Override
1219    public String toString() {
1220        StringBuilder sb = new StringBuilder(128);
1221        sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
1222                .append(" ").append(mName).append("/").append(mUid)
1223                .append(" pkg=").append(mPackage);
1224        if (mMultiPackage) sb.append(" (multi)");
1225        if (mCommonProcess != this) sb.append(" (sub)");
1226        sb.append("}");
1227        return sb.toString();
1228    }
1229
1230    public void writeToProto(ProtoOutputStream proto, long fieldId,
1231            String procName, int uid, long now) {
1232        final long token = proto.start(fieldId);
1233        proto.write(ProcessStatsProto.PROCESS, procName);
1234        proto.write(ProcessStatsProto.UID, uid);
1235        if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) {
1236            final long killToken = proto.start(ProcessStatsProto.KILL);
1237            proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu);
1238            proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill);
1239            ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS,
1240                    mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss);
1241            proto.end(killToken);
1242        }
1243
1244        // Group proc stats by type (screen state + mem state + process state)
1245        Map<Integer, Long> durationByState = new HashMap<>();
1246        boolean didCurState = false;
1247        for (int i=0; i<mDurations.getKeyCount(); i++) {
1248            final int key = mDurations.getKeyAt(i);
1249            final int type = SparseMappingTable.getIdFromKey(key);
1250            long time = mDurations.getValue(key);
1251            if (mCurState == type) {
1252                didCurState = true;
1253                time += now - mStartTime;
1254            }
1255            durationByState.put(type, time);
1256        }
1257        if (!didCurState && mCurState != STATE_NOTHING) {
1258            durationByState.put(mCurState, now - mStartTime);
1259        }
1260
1261        for (int i=0; i<mPssTable.getKeyCount(); i++) {
1262            final int key = mPssTable.getKeyAt(i);
1263            final int type = SparseMappingTable.getIdFromKey(key);
1264            if (!durationByState.containsKey(type)) {
1265                // state without duration should not have stats!
1266                continue;
1267            }
1268            final long stateToken = proto.start(ProcessStatsProto.STATES);
1269            DumpUtils.printProcStateTagProto(proto,
1270                    ProcessStatsProto.State.SCREEN_STATE,
1271                    ProcessStatsProto.State.MEMORY_STATE,
1272                    ProcessStatsProto.State.PROCESS_STATE,
1273                    type);
1274
1275            long duration = durationByState.get(type);
1276            durationByState.remove(type); // remove the key since it is already being dumped.
1277            proto.write(ProcessStatsProto.State.DURATION_MS, duration);
1278
1279            proto.write(ProcessStatsProto.State.SAMPLE_SIZE, mPssTable.getValue(key, PSS_SAMPLE_COUNT));
1280            ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.PSS,
1281                    mPssTable.getValue(key, PSS_MINIMUM),
1282                    mPssTable.getValue(key, PSS_AVERAGE),
1283                    mPssTable.getValue(key, PSS_MAXIMUM));
1284            ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.USS,
1285                    mPssTable.getValue(key, PSS_USS_MINIMUM),
1286                    mPssTable.getValue(key, PSS_USS_AVERAGE),
1287                    mPssTable.getValue(key, PSS_USS_MAXIMUM));
1288            ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.State.RSS,
1289                    mPssTable.getValue(key, PSS_RSS_MINIMUM),
1290                    mPssTable.getValue(key, PSS_RSS_AVERAGE),
1291                    mPssTable.getValue(key, PSS_RSS_MAXIMUM));
1292
1293            proto.end(stateToken);
1294        }
1295
1296        for (Map.Entry<Integer, Long> entry : durationByState.entrySet()) {
1297            final long stateToken = proto.start(ProcessStatsProto.STATES);
1298            DumpUtils.printProcStateTagProto(proto,
1299                    ProcessStatsProto.State.SCREEN_STATE,
1300                    ProcessStatsProto.State.MEMORY_STATE,
1301                    ProcessStatsProto.State.PROCESS_STATE,
1302                    entry.getKey());
1303            proto.write(ProcessStatsProto.State.DURATION_MS, entry.getValue());
1304            proto.end(stateToken);
1305        }
1306        proto.end(token);
1307    }
1308}
1309