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