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.SystemClock;
21 import android.os.UserHandle;
22 import android.service.procstats.ProcessStatsProto;
23 import android.util.ArrayMap;
24 import android.util.DebugUtils;
25 import android.util.Log;
26 import android.util.LongSparseArray;
27 import android.util.Slog;
28 import android.util.TimeUtils;
29 import android.util.proto.ProtoOutputStream;
30 import android.util.proto.ProtoUtils;
31 
32 import com.android.internal.app.procstats.ProcessStats.PackageState;
33 import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
34 import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
35 import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
36 import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
37 import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
38 import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
39 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM;
40 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE;
41 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM;
42 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
43 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
44 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
45 import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
46 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
47 import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
48 import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
49 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
50 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
51 import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
52 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
53 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
54 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
55 import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
56 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
57 import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
58 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
59 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
60 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
61 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
62 
63 import java.io.PrintWriter;
64 import java.util.Comparator;
65 import java.util.HashMap;
66 import java.util.Map;
67 
68 public 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 
add(long newPss, long newSamples)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      */
ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name)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      */
ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name, long now)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 
clone(long now)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 
getName()204     public String getName() {
205         return mName;
206     }
207 
getCommonProcess()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      */
makeStandalone()215     public void makeStandalone() {
216         mCommonProcess = this;
217     }
218 
getPackage()219     public String getPackage() {
220         return mPackage;
221     }
222 
getUid()223     public int getUid() {
224         return mUid;
225     }
226 
getVersion()227     public long getVersion() {
228         return mVersion;
229     }
230 
isMultiPackage()231     public boolean isMultiPackage() {
232         return mMultiPackage;
233     }
234 
setMultiPackage(boolean val)235     public void setMultiPackage(boolean val) {
236         mMultiPackage = val;
237     }
238 
getDurationsBucketCount()239     public int getDurationsBucketCount() {
240         return mDurations.getKeyCount();
241     }
242 
add(ProcessState other)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 
resetSafely(long now)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 
makeDead()264     public void makeDead() {
265         mDead = true;
266     }
267 
ensureNotDead()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 
writeToParcel(Parcel out, long now)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 
readFromParcel(Parcel in, boolean fully)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 
makeActive()316     public void makeActive() {
317         ensureNotDead();
318         mActive = true;
319     }
320 
makeInactive()321     public void makeInactive() {
322         mActive = false;
323     }
324 
isInUse()325     public boolean isInUse() {
326         return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
327                 || mCurState != STATE_NOTHING;
328     }
329 
isActive()330     public boolean isActive() {
331         return mActive;
332     }
333 
hasAnyData()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      */
setState(int state, int memFactor, long now, ArrayMap<String, ProcessStateHolder> pkgList)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 
setState(int state, long now)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 
commitStateTime(long now)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 
incActiveServices(String serviceName)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 
decActiveServices(String serviceName)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 
incStartedServices(int memFactor, long now, String serviceName)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 
decStartedServices(int memFactor, long now, String serviceName)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 
addPss(long pss, long uss, long rss, boolean always, int type, long duration, ArrayMap<String, ProcessStateHolder> pkgList)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 
reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList)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 
addCachedKill(int num, long minPss, long avgPss, long maxPss)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 
reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss)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 
pullFixedProc(String pkgName)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 
pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList, int index)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 
getDuration(int state, long now)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 
getPssSampleCount(int state)628     public long getPssSampleCount(int state) {
629         return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
630     }
631 
getPssMinimum(int state)632     public long getPssMinimum(int state) {
633         return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
634     }
635 
getPssAverage(int state)636     public long getPssAverage(int state) {
637         return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
638     }
639 
getPssMaximum(int state)640     public long getPssMaximum(int state) {
641         return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
642     }
643 
getPssUssMinimum(int state)644     public long getPssUssMinimum(int state) {
645         return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
646     }
647 
getPssUssAverage(int state)648     public long getPssUssAverage(int state) {
649         return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
650     }
651 
getPssUssMaximum(int state)652     public long getPssUssMaximum(int state) {
653         return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
654     }
655 
getPssRssMinimum(int state)656     public long getPssRssMinimum(int state) {
657         return mPssTable.getValueForId((byte)state, PSS_RSS_MINIMUM);
658     }
659 
getPssRssAverage(int state)660     public long getPssRssAverage(int state) {
661         return mPssTable.getValueForId((byte)state, PSS_RSS_AVERAGE);
662     }
663 
getPssRssMaximum(int state)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      */
aggregatePss(TotalMemoryUseCollection data, long now)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 
computeProcessTimeLocked(int[] screenStates, int[] memStates, int[] procStates, long now)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 
dumpSummary(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)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 
dumpProcessState(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)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 
dumpPss(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates)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 
dumpProcessSummaryDetails(PrintWriter pw, String prefix, String label, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime, boolean full)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 
dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll)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 
computeProcessData(ProcessStats.ProcessDataCollection data, long now)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 
dumpCsv(PrintWriter pw, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)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 
dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers, String itemName, long now)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 
dumpProcCheckin(PrintWriter pw, String procName, int uid, long now)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 
dumpAllStateCheckin(PrintWriter pw, long now)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 
dumpAllPssCheckin(PrintWriter pw)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
toString()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 
writeToProto(ProtoOutputStream proto, long fieldId, String procName, int uid, long now)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