• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE;
20 import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT;
21 import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM;
22 import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM;
23 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE;
24 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM;
25 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM;
26 import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT;
27 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE;
28 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM;
29 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM;
30 import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP;
31 import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_FGS;
32 import static com.android.internal.app.procstats.ProcessStats.STATE_BOUND_TOP;
33 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED;
34 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
35 import static com.android.internal.app.procstats.ProcessStats.STATE_FGS;
36 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
37 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
38 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
39 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
40 import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
41 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
42 import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
43 import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
44 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
45 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
46 import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
47 
48 import android.os.Parcel;
49 import android.os.SystemClock;
50 import android.os.UserHandle;
51 import android.service.procstats.ProcessStatsProto;
52 import android.service.procstats.ProcessStatsStateProto;
53 import android.text.TextUtils;
54 import android.util.ArrayMap;
55 import android.util.ArraySet;
56 import android.util.DebugUtils;
57 import android.util.Log;
58 import android.util.LongSparseArray;
59 import android.util.Slog;
60 import android.util.SparseArray;
61 import android.util.SparseLongArray;
62 import android.util.TimeUtils;
63 import android.util.proto.ProtoOutputStream;
64 import android.util.proto.ProtoUtils;
65 
66 import com.android.internal.app.ProcessMap;
67 import com.android.internal.app.procstats.AssociationState.SourceKey;
68 import com.android.internal.app.procstats.AssociationState.SourceState;
69 import com.android.internal.app.procstats.ProcessStats.PackageState;
70 import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
71 import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
72 
73 import java.io.PrintWriter;
74 import java.util.Comparator;
75 import java.util.concurrent.TimeUnit;
76 
77 public final class ProcessState {
78     private static final String TAG = "ProcessStats";
79     private static final boolean DEBUG = false;
80     private static final boolean DEBUG_PARCEL = false;
81 
82     // Map from process states to the states we track.
83     static final int[] PROCESS_STATE_TO_STATE = new int[] {
84         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
85         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
86         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
87         STATE_BOUND_TOP,                // ActivityManager.PROCESS_STATE_BOUND_TOP
88         STATE_FGS,                      // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
89         STATE_BOUND_FGS,                // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
90         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
91         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
92         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
93         STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
94         STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
95         STATE_RECEIVER,                 // ActivityManager.PROCESS_STATE_RECEIVER
96         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
97         STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
98         STATE_HOME,                     // ActivityManager.PROCESS_STATE_HOME
99         STATE_LAST_ACTIVITY,            // ActivityManager.PROCESS_STATE_LAST_ACTIVITY
100         STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
101         STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
102         STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_RECENT
103         STATE_CACHED,                   // ActivityManager.PROCESS_STATE_CACHED_EMPTY
104     };
105 
106     public static final Comparator<ProcessState> COMPARATOR = new Comparator<ProcessState>() {
107             @Override
108             public int compare(ProcessState lhs, ProcessState rhs) {
109                 if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) {
110                     return -1;
111                 } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) {
112                     return 1;
113                 }
114                 return 0;
115             }
116         };
117 
118     static class PssAggr {
119         long pss = 0;
120         long samples = 0;
121 
add(long newPss, long newSamples)122         void add(long newPss, long newSamples) {
123             pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) )
124                     / (samples+newSamples);
125             samples += newSamples;
126         }
127     }
128 
129     // Used by reset to count rather than storing extra maps. Be careful.
130     public int tmpNumInUse;
131     public ProcessState tmpFoundSubProc;
132 
133     private final ProcessStats mStats;
134     private final String mName;
135     private final String mPackage;
136     private final int mUid;
137     private final long mVersion;
138     private final DurationsTable mDurations;
139     private final PssTable mPssTable;
140     private final long[] mTotalRunningPss = new long[ProcessStats.PSS_COUNT];
141 
142     private ProcessState mCommonProcess;
143     private int mCurCombinedState = STATE_NOTHING;
144     private long mStartTime;
145 
146     private int mLastPssState = STATE_NOTHING;
147     private long mLastPssTime;
148 
149     private long mTotalRunningStartTime;
150     private long mTotalRunningDuration;
151 
152     private boolean mActive;
153     private int mNumActiveServices;
154     private int mNumStartedServices;
155 
156     private int mNumExcessiveCpu;
157 
158     private int mNumCachedKill;
159     private long mMinCachedKillPss;
160     private long mAvgCachedKillPss;
161     private long mMaxCachedKillPss;
162 
163     private boolean mMultiPackage;
164     private boolean mDead;
165 
166     // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
167     private long mTmpTotalTime;
168 
169     /**
170      * The combined source states which has or had an association with this process.
171      */
172     ArrayMap<SourceKey, SourceState> mCommonSources;
173 
174     /**
175      * Create a new top-level process state, for the initial case where there is only
176      * a single package running in a process.  The initial state is not running.
177      */
ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name)178     public ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name) {
179         mStats = processStats;
180         mName = name;
181         mCommonProcess = this;
182         mPackage = pkg;
183         mUid = uid;
184         mVersion = vers;
185         mDurations = new DurationsTable(processStats.mTableData);
186         mPssTable = new PssTable(processStats.mTableData);
187     }
188 
189     /**
190      * Create a new per-package process state for an existing top-level process
191      * state.  The current running state of the top-level process is also copied,
192      * marked as started running at 'now'.
193      */
ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name, long now)194     public ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name,
195             long now) {
196         mStats = commonProcess.mStats;
197         mName = name;
198         mCommonProcess = commonProcess;
199         mPackage = pkg;
200         mUid = uid;
201         mVersion = vers;
202         mCurCombinedState = commonProcess.mCurCombinedState;
203         mStartTime = now;
204         if (mCurCombinedState != STATE_NOTHING) {
205             mTotalRunningStartTime = now;
206         }
207         mDurations = new DurationsTable(commonProcess.mStats.mTableData);
208         mPssTable = new PssTable(commonProcess.mStats.mTableData);
209     }
210 
clone(long now)211     public ProcessState clone(long now) {
212         ProcessState pnew = new ProcessState(this, mPackage, mUid, mVersion, mName, now);
213         pnew.mDurations.addDurations(mDurations);
214         pnew.mPssTable.copyFrom(mPssTable, PSS_COUNT);
215         System.arraycopy(mTotalRunningPss, 0, pnew.mTotalRunningPss, 0, ProcessStats.PSS_COUNT);
216         pnew.mTotalRunningDuration = getTotalRunningDuration(now);
217         pnew.mNumExcessiveCpu = mNumExcessiveCpu;
218         pnew.mNumCachedKill = mNumCachedKill;
219         pnew.mMinCachedKillPss = mMinCachedKillPss;
220         pnew.mAvgCachedKillPss = mAvgCachedKillPss;
221         pnew.mMaxCachedKillPss = mMaxCachedKillPss;
222         pnew.mActive = mActive;
223         pnew.mNumActiveServices = mNumActiveServices;
224         pnew.mNumStartedServices = mNumStartedServices;
225         return pnew;
226     }
227 
getName()228     public String getName() {
229         return mName;
230     }
231 
getCommonProcess()232     public ProcessState getCommonProcess() {
233         return mCommonProcess;
234     }
235 
236     /**
237      * Say that we are not part of a shared process, so mCommonProcess = this.
238      */
makeStandalone()239     public void makeStandalone() {
240         mCommonProcess = this;
241     }
242 
getPackage()243     public String getPackage() {
244         return mPackage;
245     }
246 
getUid()247     public int getUid() {
248         return mUid;
249     }
250 
getVersion()251     public long getVersion() {
252         return mVersion;
253     }
254 
isMultiPackage()255     public boolean isMultiPackage() {
256         return mMultiPackage;
257     }
258 
setMultiPackage(boolean val)259     public void setMultiPackage(boolean val) {
260         mMultiPackage = val;
261     }
262 
getDurationsBucketCount()263     public int getDurationsBucketCount() {
264         return mDurations.getKeyCount();
265     }
266 
add(ProcessState other)267     public void add(ProcessState other) {
268         mDurations.addDurations(other.mDurations);
269         mPssTable.mergeStats(other.mPssTable);
270         // Note that we don't touch mTotalRunningPss, because in current use
271         // 'other' is older stats that are being added in to these newer ones.
272         // So the newer ones keep track of the total running time, which is always
273         // the right thing over whatever was in older stats.
274         mNumExcessiveCpu += other.mNumExcessiveCpu;
275         if (other.mNumCachedKill > 0) {
276             addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
277                     other.mAvgCachedKillPss, other.mMaxCachedKillPss);
278         }
279         if (other.mCommonSources != null) {
280             if (mCommonSources == null) {
281                 mCommonSources = new ArrayMap<>();
282             }
283             int size = other.mCommonSources.size();
284             for (int i = 0; i < size; i++) {
285                 final SourceKey key = other.mCommonSources.keyAt(i);
286                 SourceState state = mCommonSources.get(key);
287                 if (state == null) {
288                     state = new SourceState(mStats, null, this, key);
289                     mCommonSources.put(key, state);
290                 }
291                 state.add(other.mCommonSources.valueAt(i));
292             }
293         }
294     }
295 
resetSafely(long now)296     public void resetSafely(long now) {
297         mDurations.resetTable();
298         mPssTable.resetTable();
299         mStartTime = now;
300         mLastPssState = STATE_NOTHING;
301         mLastPssTime = 0;
302         mNumExcessiveCpu = 0;
303         mNumCachedKill = 0;
304         mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
305         // Reset the combine source state.
306         if (mCommonSources != null) {
307             for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) {
308                 final SourceState state = mCommonSources.valueAt(ip);
309                 if (state.isInUse()) {
310                     state.resetSafely(now);
311                 } else {
312                     mCommonSources.removeAt(ip);
313                 }
314             }
315         }
316     }
317 
makeDead()318     public void makeDead() {
319         mDead = true;
320     }
321 
ensureNotDead()322     private void ensureNotDead() {
323         if (!mDead) {
324             return;
325         }
326         Slog.w(TAG, "ProcessState dead: name=" + mName
327                 + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
328     }
329 
writeToParcel(Parcel out, long now)330     public void writeToParcel(Parcel out, long now) {
331         out.writeInt(mMultiPackage ? 1 : 0);
332         mDurations.writeToParcel(out);
333         mPssTable.writeToParcel(out);
334         for (int i = 0; i < ProcessStats.PSS_COUNT; i++) {
335             out.writeLong(mTotalRunningPss[i]);
336         }
337         out.writeLong(getTotalRunningDuration(now));
338         out.writeInt(0);  // was mNumExcessiveWake
339         out.writeInt(mNumExcessiveCpu);
340         out.writeInt(mNumCachedKill);
341         if (mNumCachedKill > 0) {
342             out.writeLong(mMinCachedKillPss);
343             out.writeLong(mAvgCachedKillPss);
344             out.writeLong(mMaxCachedKillPss);
345         }
346         // The combined source state of all associations.
347         final int numOfSources = mCommonSources != null ? mCommonSources.size() : 0;
348         out.writeInt(numOfSources);
349         for (int i = 0; i < numOfSources; i++) {
350             final SourceKey key = mCommonSources.keyAt(i);
351             final SourceState src = mCommonSources.valueAt(i);
352             key.writeToParcel(mStats, out);
353             src.writeToParcel(out, 0);
354         }
355     }
356 
readFromParcel(Parcel in, int version, boolean fully)357     boolean readFromParcel(Parcel in, int version, boolean fully) {
358         boolean multiPackage = in.readInt() != 0;
359         if (fully) {
360             mMultiPackage = multiPackage;
361         }
362         if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table...");
363         if (!mDurations.readFromParcel(in)) {
364             return false;
365         }
366         if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table...");
367         if (!mPssTable.readFromParcel(in)) {
368             return false;
369         }
370         for (int i = 0; i < ProcessStats.PSS_COUNT; i++) {
371             mTotalRunningPss[i] = in.readLong();
372         }
373         mTotalRunningDuration = in.readLong();
374         in.readInt(); // was mNumExcessiveWake
375         mNumExcessiveCpu = in.readInt();
376         mNumCachedKill = in.readInt();
377         if (mNumCachedKill > 0) {
378             mMinCachedKillPss = in.readLong();
379             mAvgCachedKillPss = in.readLong();
380             mMaxCachedKillPss = in.readLong();
381         } else {
382             mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
383         }
384 
385         // The combined source state of all associations.
386         final int numOfSources = in.readInt();
387         if (numOfSources > 0) {
388             mCommonSources = new ArrayMap<>(numOfSources);
389             for (int i = 0; i < numOfSources; i++) {
390                 final SourceKey key = new SourceKey(mStats, in, version);
391                 final SourceState src = new SourceState(mStats, null, this, key);
392                 src.readFromParcel(in);
393                 mCommonSources.put(key, src);
394             }
395         }
396 
397         return true;
398     }
399 
makeActive()400     public void makeActive() {
401         ensureNotDead();
402         mActive = true;
403     }
404 
makeInactive()405     public void makeInactive() {
406         mActive = false;
407     }
408 
isInUse()409     public boolean isInUse() {
410         return mActive || mNumActiveServices > 0 || mNumStartedServices > 0
411                 || mCurCombinedState != STATE_NOTHING;
412     }
413 
isActive()414     public boolean isActive() {
415         return mActive;
416     }
417 
hasAnyData()418     public boolean hasAnyData() {
419         return !(mDurations.getKeyCount() == 0
420                 && mCurCombinedState == STATE_NOTHING
421                 && mPssTable.getKeyCount() == 0
422                 && mTotalRunningPss[PSS_SAMPLE_COUNT] == 0);
423     }
424 
425     /**
426      * Update the current state of the given list of processes.
427      *
428      * @param state Current ActivityManager.PROCESS_STATE_*
429      * @param memFactor Current mem factor constant.
430      * @param now Current time.
431      * @param pkgList Processes to update.
432      */
setState(int state, int memFactor, long now, ArrayMap<String, ProcessStateHolder> pkgList)433     public void setState(int state, int memFactor, long now,
434             ArrayMap<String, ProcessStateHolder> pkgList) {
435         if (state < 0) {
436             state = mNumStartedServices > 0
437                     ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING;
438         } else {
439             state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT);
440         }
441 
442         // First update the common process.
443         mCommonProcess.setCombinedState(state, now);
444 
445         // If the common process is not multi-package, there is nothing else to do.
446         if (!mCommonProcess.mMultiPackage) {
447             return;
448         }
449 
450         if (pkgList != null) {
451             for (int ip=pkgList.size()-1; ip>=0; ip--) {
452                 pullFixedProc(pkgList, ip).setCombinedState(state, now);
453             }
454         }
455     }
456 
setCombinedState(int state, long now)457     public void setCombinedState(int state, long now) {
458         ensureNotDead();
459         if (!mDead && (mCurCombinedState != state)) {
460             //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
461             commitStateTime(now);
462             if (state == STATE_NOTHING) {
463                 // We are transitioning to a no longer running state... stop counting run time.
464                 mTotalRunningDuration += now - mTotalRunningStartTime;
465                 mTotalRunningStartTime = 0;
466             } else if (mCurCombinedState == STATE_NOTHING) {
467                 // We previously weren't running...  now starting again, clear out total
468                 // running info.
469                 mTotalRunningDuration = 0;
470                 mTotalRunningStartTime = now;
471                 for (int i = ProcessStats.PSS_COUNT - 1; i >= 0; i--) {
472                     mTotalRunningPss[i] = 0;
473                 }
474             }
475             mCurCombinedState = state;
476             final UidState uidState = mStats.mUidStates.get(mUid);
477             if (uidState != null) {
478                 uidState.updateCombinedState(state, now);
479             }
480         }
481     }
482 
getCombinedState()483     public int getCombinedState() {
484         return mCurCombinedState;
485     }
486 
commitStateTime(long now)487     public void commitStateTime(long now) {
488         if (mCurCombinedState != STATE_NOTHING) {
489             long dur = now - mStartTime;
490             if (dur > 0) {
491                 mDurations.addDuration(mCurCombinedState, dur);
492             }
493             mTotalRunningDuration += now - mTotalRunningStartTime;
494             mTotalRunningStartTime = now;
495         }
496         mStartTime = now;
497         if (mCommonSources != null) {
498             for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) {
499                 final SourceState src = mCommonSources.valueAt(ip);
500                 src.commitStateTime(now);
501             }
502         }
503     }
504 
incActiveServices(String serviceName)505     public void incActiveServices(String serviceName) {
506         if (DEBUG && "".equals(mName)) {
507             RuntimeException here = new RuntimeException("here");
508             here.fillInStackTrace();
509             Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
510                     + " to " + (mNumActiveServices+1), here);
511         }
512         if (mCommonProcess != this) {
513             mCommonProcess.incActiveServices(serviceName);
514         }
515         mNumActiveServices++;
516     }
517 
decActiveServices(String serviceName)518     public void decActiveServices(String serviceName) {
519         if (DEBUG && "".equals(mName)) {
520             RuntimeException here = new RuntimeException("here");
521             here.fillInStackTrace();
522             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
523                     + " to " + (mNumActiveServices-1), here);
524         }
525         if (mCommonProcess != this) {
526             mCommonProcess.decActiveServices(serviceName);
527         }
528         mNumActiveServices--;
529         if (mNumActiveServices < 0) {
530             Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
531                     + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
532             mNumActiveServices = 0;
533         }
534     }
535 
incStartedServices(int memFactor, long now, String serviceName)536     public void incStartedServices(int memFactor, long now, String serviceName) {
537         if (false) {
538             RuntimeException here = new RuntimeException("here");
539             here.fillInStackTrace();
540             Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
541                     + " to " + (mNumStartedServices+1), here);
542         }
543         if (mCommonProcess != this) {
544             mCommonProcess.incStartedServices(memFactor, now, serviceName);
545         }
546         mNumStartedServices++;
547         if (mNumStartedServices == 1 && mCurCombinedState == STATE_NOTHING) {
548             setCombinedState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
549         }
550     }
551 
decStartedServices(int memFactor, long now, String serviceName)552     public void decStartedServices(int memFactor, long now, String serviceName) {
553         if (false) {
554             RuntimeException here = new RuntimeException("here");
555             here.fillInStackTrace();
556             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
557                     + " to " + (mNumStartedServices-1), here);
558         }
559         if (mCommonProcess != this) {
560             mCommonProcess.decStartedServices(memFactor, now, serviceName);
561         }
562         mNumStartedServices--;
563         if (mNumStartedServices == 0 && (mCurCombinedState %STATE_COUNT) == STATE_SERVICE_RESTARTING) {
564             setCombinedState(STATE_NOTHING, now);
565         } else if (mNumStartedServices < 0) {
566             Slog.wtfStack(TAG, "Proc started services underrun: pkg="
567                     + mPackage + " uid=" + mUid + " name=" + mName);
568             mNumStartedServices = 0;
569         }
570     }
571 
addPss(long pss, long uss, long rss, boolean always, int type, long duration, ArrayMap<String, ProcessStateHolder> pkgList)572     public void addPss(long pss, long uss, long rss, boolean always, int type, long duration,
573             ArrayMap<String, ProcessStateHolder> pkgList) {
574         ensureNotDead();
575         switch (type) {
576             case ProcessStats.ADD_PSS_INTERNAL_SINGLE:
577                 mStats.mInternalSinglePssCount++;
578                 mStats.mInternalSinglePssTime += duration;
579                 break;
580             case ProcessStats.ADD_PSS_INTERNAL_ALL_MEM:
581                 mStats.mInternalAllMemPssCount++;
582                 mStats.mInternalAllMemPssTime += duration;
583                 break;
584             case ProcessStats.ADD_PSS_INTERNAL_ALL_POLL:
585                 mStats.mInternalAllPollPssCount++;
586                 mStats.mInternalAllPollPssTime += duration;
587                 break;
588             case ProcessStats.ADD_PSS_EXTERNAL:
589                 mStats.mExternalPssCount++;
590                 mStats.mExternalPssTime += duration;
591                 break;
592             case ProcessStats.ADD_PSS_EXTERNAL_SLOW:
593                 mStats.mExternalSlowPssCount++;
594                 mStats.mExternalSlowPssTime += duration;
595                 break;
596         }
597         if (!always) {
598             if (mLastPssState == mCurCombinedState && SystemClock.uptimeMillis()
599                     < (mLastPssTime+(30*1000))) {
600                 return;
601             }
602         }
603         mLastPssState = mCurCombinedState;
604         mLastPssTime = SystemClock.uptimeMillis();
605         if (mCurCombinedState != STATE_NOTHING) {
606             // First update the common process.
607             mCommonProcess.mPssTable.mergeStats(mCurCombinedState, 1, pss, pss, pss, uss, uss, uss,
608                     rss, rss, rss);
609             PssTable.mergeStats(mCommonProcess.mTotalRunningPss, 0, 1, pss, pss, pss, uss, uss, uss,
610                     rss, rss, rss);
611 
612             // If the common process is not multi-package, there is nothing else to do.
613             if (!mCommonProcess.mMultiPackage) {
614                 return;
615             }
616 
617             if (pkgList != null) {
618                 for (int ip=pkgList.size()-1; ip>=0; ip--) {
619                     ProcessState fixedProc = pullFixedProc(pkgList, ip);
620                     fixedProc.mPssTable.mergeStats(mCurCombinedState, 1,
621                             pss, pss, pss, uss, uss, uss, rss, rss, rss);
622                     PssTable.mergeStats(fixedProc.mTotalRunningPss, 0, 1,
623                             pss, pss, pss, uss, uss, uss, rss, rss, rss);
624                 }
625             }
626         }
627     }
628 
reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList)629     public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
630         ensureNotDead();
631         mCommonProcess.mNumExcessiveCpu++;
632         if (!mCommonProcess.mMultiPackage) {
633             return;
634         }
635 
636         for (int ip=pkgList.size()-1; ip>=0; ip--) {
637             pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
638         }
639     }
640 
addCachedKill(int num, long minPss, long avgPss, long maxPss)641     private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
642         if (mNumCachedKill <= 0) {
643             mNumCachedKill = num;
644             mMinCachedKillPss = minPss;
645             mAvgCachedKillPss = avgPss;
646             mMaxCachedKillPss = maxPss;
647         } else {
648             if (minPss < mMinCachedKillPss) {
649                 mMinCachedKillPss = minPss;
650             }
651             if (maxPss > mMaxCachedKillPss) {
652                 mMaxCachedKillPss = maxPss;
653             }
654             mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
655                     / (mNumCachedKill+num) );
656             mNumCachedKill += num;
657         }
658     }
659 
reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss)660     public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
661         ensureNotDead();
662         mCommonProcess.addCachedKill(1, pss, pss, pss);
663         if (!mCommonProcess.mMultiPackage) {
664             return;
665         }
666 
667         for (int ip=pkgList.size()-1; ip>=0; ip--) {
668             pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
669         }
670     }
671 
pullFixedProc(String pkgName)672     public ProcessState pullFixedProc(String pkgName) {
673         if (mMultiPackage) {
674             // The array map is still pointing to a common process state
675             // that is now shared across packages.  Update it to point to
676             // the new per-package state.
677             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
678             if (vpkg == null) {
679                 throw new IllegalStateException("Didn't find package " + pkgName
680                         + " / " + mUid);
681             }
682             PackageState pkg = vpkg.get(mVersion);
683             if (pkg == null) {
684                 throw new IllegalStateException("Didn't find package " + pkgName
685                         + " / " + mUid + " vers " + mVersion);
686             }
687             ProcessState proc = pkg.mProcesses.get(mName);
688             if (proc == null) {
689                 throw new IllegalStateException("Didn't create per-package process "
690                         + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
691             }
692             return proc;
693         }
694         return this;
695     }
696 
pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList, int index)697     private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
698             int index) {
699         ProcessStateHolder holder = pkgList.valueAt(index);
700         ProcessState proc = holder.state;
701         if (mDead && proc.mCommonProcess != proc) {
702             // Somehow we are continuing to use a process state that is dead, because
703             // it was not being told it was active during the last commit.  We can recover
704             // from this by generating a fresh new state, but this is bad because we
705             // are losing whatever data we had in the old process state.
706             Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
707                     + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
708             proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
709                     proc.mName);
710         }
711         if (proc.mMultiPackage) {
712             // The array map is still pointing to a common process state
713             // that is now shared across packages.  Update it to point to
714             // the new per-package state.
715             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
716                     proc.mUid);
717             if (vpkg == null) {
718                 throw new IllegalStateException("No existing package "
719                         + pkgList.keyAt(index) + "/" + proc.mUid
720                         + " for multi-proc " + proc.mName);
721             }
722             PackageState expkg = vpkg.get(proc.mVersion);
723             if (expkg == null) {
724                 throw new IllegalStateException("No existing package "
725                         + pkgList.keyAt(index) + "/" + proc.mUid
726                         + " for multi-proc " + proc.mName + " version " + proc.mVersion);
727             }
728             String savedName = proc.mName;
729             proc = expkg.mProcesses.get(proc.mName);
730             if (proc == null) {
731                 throw new IllegalStateException("Didn't create per-package process "
732                         + savedName + " in pkg " + expkg.mPackageName + "/" + expkg.mUid);
733             }
734             holder.state = proc;
735         }
736         return proc;
737     }
738 
getTotalRunningDuration(long now)739     public long getTotalRunningDuration(long now) {
740         return mTotalRunningDuration +
741                 (mTotalRunningStartTime != 0 ? (now - mTotalRunningStartTime) : 0);
742     }
743 
getDuration(int state, long now)744     public long getDuration(int state, long now) {
745         long time = mDurations.getValueForId((byte)state);
746         if (mCurCombinedState == state) {
747             time += now - mStartTime;
748         }
749         return time;
750     }
751 
getPssSampleCount(int state)752     public long getPssSampleCount(int state) {
753         return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
754     }
755 
getPssMinimum(int state)756     public long getPssMinimum(int state) {
757         return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
758     }
759 
getPssAverage(int state)760     public long getPssAverage(int state) {
761         return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
762     }
763 
getPssMaximum(int state)764     public long getPssMaximum(int state) {
765         return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
766     }
767 
getPssUssMinimum(int state)768     public long getPssUssMinimum(int state) {
769         return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
770     }
771 
getPssUssAverage(int state)772     public long getPssUssAverage(int state) {
773         return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
774     }
775 
getPssUssMaximum(int state)776     public long getPssUssMaximum(int state) {
777         return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
778     }
779 
getPssRssMinimum(int state)780     public long getPssRssMinimum(int state) {
781         return mPssTable.getValueForId((byte)state, PSS_RSS_MINIMUM);
782     }
783 
getPssRssAverage(int state)784     public long getPssRssAverage(int state) {
785         return mPssTable.getValueForId((byte)state, PSS_RSS_AVERAGE);
786     }
787 
getPssRssMaximum(int state)788     public long getPssRssMaximum(int state) {
789         return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
790     }
791 
getOrCreateSourceState(SourceKey key)792     SourceState getOrCreateSourceState(SourceKey key) {
793         if (mCommonSources == null) {
794             mCommonSources = new ArrayMap<>();
795         }
796         SourceState state = mCommonSources.get(key);
797         if (state == null) {
798             state = new SourceState(mStats, null, this, key);
799             mCommonSources.put(key, state);
800         }
801         return state;
802     }
803 
804     /**
805      * Sums up the PSS data and adds it to 'data'.
806      *
807      * @param data The aggregate data is added here.
808      * @param now SystemClock.uptimeMillis()
809      */
aggregatePss(TotalMemoryUseCollection data, long now)810     public void aggregatePss(TotalMemoryUseCollection data, long now) {
811         final PssAggr fgPss = new PssAggr();
812         final PssAggr bgPss = new PssAggr();
813         final PssAggr cachedPss = new PssAggr();
814         boolean havePss = false;
815         for (int i=0; i<mDurations.getKeyCount(); i++) {
816             final int key = mDurations.getKeyAt(i);
817             int type = SparseMappingTable.getIdFromKey(key);
818             int procState = type % STATE_COUNT;
819             long samples = getPssSampleCount(type);
820             if (samples > 0) {
821                 long avg = getPssAverage(type);
822                 havePss = true;
823                 if (procState <= STATE_IMPORTANT_FOREGROUND) {
824                     fgPss.add(avg, samples);
825                 } else if (procState <= STATE_RECEIVER) {
826                     bgPss.add(avg, samples);
827                 } else {
828                     cachedPss.add(avg, samples);
829                 }
830             }
831         }
832         if (!havePss) {
833             return;
834         }
835         boolean fgHasBg = false;
836         boolean fgHasCached = false;
837         boolean bgHasCached = false;
838         if (fgPss.samples < 3 && bgPss.samples > 0) {
839             fgHasBg = true;
840             fgPss.add(bgPss.pss, bgPss.samples);
841         }
842         if (fgPss.samples < 3 && cachedPss.samples > 0) {
843             fgHasCached = true;
844             fgPss.add(cachedPss.pss, cachedPss.samples);
845         }
846         if (bgPss.samples < 3 && cachedPss.samples > 0) {
847             bgHasCached = true;
848             bgPss.add(cachedPss.pss, cachedPss.samples);
849         }
850         if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
851             bgPss.add(fgPss.pss, fgPss.samples);
852         }
853         if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
854             cachedPss.add(bgPss.pss, bgPss.samples);
855         }
856         if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
857             cachedPss.add(fgPss.pss, fgPss.samples);
858         }
859         for (int i=0; i<mDurations.getKeyCount(); i++) {
860             final int key = mDurations.getKeyAt(i);
861             final int type = SparseMappingTable.getIdFromKey(key);
862             long time = mDurations.getValue(key);
863             if (mCurCombinedState == type) {
864                 time += now - mStartTime;
865             }
866             final int procState = type % STATE_COUNT;
867             data.processStateTime[procState] += time;
868             long samples = getPssSampleCount(type);
869             long avg;
870             if (samples > 0) {
871                 avg = getPssAverage(type);
872             } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
873                 samples = fgPss.samples;
874                 avg = fgPss.pss;
875             } else if (procState <= STATE_RECEIVER) {
876                 samples = bgPss.samples;
877                 avg = bgPss.pss;
878             } else {
879                 samples = cachedPss.samples;
880                 avg = cachedPss.pss;
881             }
882             double newAvg = ( (data.processStatePss[procState]
883                     * (double)data.processStateSamples[procState])
884                         + (avg*(double)samples)
885                     ) / (data.processStateSamples[procState]+samples);
886             data.processStatePss[procState] = (long)newAvg;
887             data.processStateSamples[procState] += samples;
888             data.processStateWeight[procState] += avg * (double)time;
889         }
890     }
891 
computeProcessTimeLocked(int[] screenStates, int[] memStates, int[] procStates, long now)892     public long computeProcessTimeLocked(int[] screenStates, int[] memStates,
893                 int[] procStates, long now) {
894         long totalTime = 0;
895         for (int is=0; is<screenStates.length; is++) {
896             for (int im=0; im<memStates.length; im++) {
897                 for (int ip=0; ip<procStates.length; ip++) {
898                     int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
899                             + procStates[ip];
900                     totalTime += getDuration(bucket, now);
901                 }
902             }
903         }
904         mTmpTotalTime = totalTime;
905         return totalTime;
906     }
907 
dumpSummary(PrintWriter pw, String prefix, String header, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)908     public void dumpSummary(PrintWriter pw, String prefix, String header,
909             int[] screenStates, int[] memStates, int[] procStates,
910             long now, long totalTime) {
911         pw.print(prefix);
912         pw.print("* ");
913         if (header != null) {
914             pw.print(header);
915         }
916         pw.print(mName);
917         pw.print(" / ");
918         UserHandle.formatUid(pw, mUid);
919         pw.print(" / v");
920         pw.print(mVersion);
921         pw.println(":");
922         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABEL_TOTAL,
923                 screenStates, memStates, procStates, now, totalTime, true);
924         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_PERSISTENT],
925                 screenStates, memStates, new int[] { STATE_PERSISTENT }, now, totalTime, true);
926         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_TOP],
927                 screenStates, memStates, new int[] {STATE_TOP}, now, totalTime, true);
928         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_TOP],
929                 screenStates, memStates, new int[] { STATE_BOUND_TOP }, now, totalTime,
930                 true);
931         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_FGS],
932                 screenStates, memStates, new int[] { STATE_BOUND_FGS }, now, totalTime,
933                 true);
934         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_FGS],
935                 screenStates, memStates, new int[] { STATE_FGS}, now, totalTime,
936                 true);
937         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_FOREGROUND],
938                 screenStates, memStates, new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime,
939                 true);
940         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_BACKGROUND],
941                 screenStates, memStates, new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime,
942                 true);
943         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BACKUP],
944                 screenStates, memStates, new int[] {STATE_BACKUP}, now, totalTime, true);
945         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE],
946                 screenStates, memStates, new int[] {STATE_SERVICE}, now, totalTime, true);
947         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE_RESTARTING],
948                 screenStates, memStates, new int[] {STATE_SERVICE_RESTARTING}, now, totalTime,
949                 true);
950         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_RECEIVER],
951                 screenStates, memStates, new int[] {STATE_RECEIVER}, now, totalTime, true);
952         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HEAVY_WEIGHT],
953                 screenStates, memStates, new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
954         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HOME],
955                 screenStates, memStates, new int[] {STATE_HOME}, now, totalTime, true);
956         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_LAST_ACTIVITY],
957                 screenStates, memStates, new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
958     }
959 
dumpProcessState(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)960     public void dumpProcessState(PrintWriter pw, String prefix,
961             int[] screenStates, int[] memStates, int[] procStates, long now) {
962         long totalTime = 0;
963         int printedScreen = -1;
964         for (int is=0; is<screenStates.length; is++) {
965             int printedMem = -1;
966             for (int im=0; im<memStates.length; im++) {
967                 for (int ip=0; ip<procStates.length; ip++) {
968                     final int iscreen = screenStates[is];
969                     final int imem = memStates[im];
970                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
971                     long time = mDurations.getValueForId((byte)bucket);
972                     String running = "";
973                     if (mCurCombinedState == bucket) {
974                         running = " (running)";
975                         time += now - mStartTime;
976                     }
977                     if (time != 0) {
978                         pw.print(prefix);
979                         if (screenStates.length > 1) {
980                             DumpUtils.printScreenLabel(pw, printedScreen != iscreen
981                                     ? iscreen : STATE_NOTHING);
982                             printedScreen = iscreen;
983                         }
984                         if (memStates.length > 1) {
985                             DumpUtils.printMemLabel(pw,
986                                     printedMem != imem ? imem : STATE_NOTHING, '/');
987                             printedMem = imem;
988                         }
989                         pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": ");
990                         TimeUtils.formatDuration(time, pw); pw.println(running);
991                         totalTime += time;
992                     }
993                 }
994             }
995         }
996         if (totalTime != 0) {
997             pw.print(prefix);
998             if (screenStates.length > 1) {
999                 DumpUtils.printScreenLabel(pw, STATE_NOTHING);
1000             }
1001             if (memStates.length > 1) {
1002                 DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
1003             }
1004             pw.print(DumpUtils.STATE_LABEL_TOTAL);
1005             pw.print(": ");
1006             TimeUtils.formatDuration(totalTime, pw);
1007             pw.println();
1008         }
1009     }
1010 
dumpPss(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)1011     public void dumpPss(PrintWriter pw, String prefix,
1012             int[] screenStates, int[] memStates, int[] procStates, long now) {
1013         boolean printedHeader = false;
1014         int printedScreen = -1;
1015         for (int is=0; is<screenStates.length; is++) {
1016             int printedMem = -1;
1017             for (int im=0; im<memStates.length; im++) {
1018                 for (int ip=0; ip<procStates.length; ip++) {
1019                     final int iscreen = screenStates[is];
1020                     final int imem = memStates[im];
1021                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
1022                     final int key = mPssTable.getKey((byte)bucket);
1023                     if (key == SparseMappingTable.INVALID_KEY) {
1024                         continue;
1025                     }
1026                     final long[] table = mPssTable.getArrayForKey(key);
1027                     final int tableOffset = SparseMappingTable.getIndexFromKey(key);
1028                     if (!printedHeader) {
1029                         pw.print(prefix);
1030                         pw.print("PSS/USS (");
1031                         pw.print(mPssTable.getKeyCount());
1032                         pw.println(" entries):");
1033                         printedHeader = true;
1034                     }
1035                     pw.print(prefix);
1036                     pw.print("  ");
1037                     if (screenStates.length > 1) {
1038                         DumpUtils.printScreenLabel(pw,
1039                                 printedScreen != iscreen ? iscreen : STATE_NOTHING);
1040                         printedScreen = iscreen;
1041                     }
1042                     if (memStates.length > 1) {
1043                         DumpUtils.printMemLabel(pw,
1044                                 printedMem != imem ? imem : STATE_NOTHING, '/');
1045                         printedMem = imem;
1046                     }
1047                     pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": ");
1048                     dumpPssSamples(pw, table, tableOffset);
1049                     pw.println();
1050                 }
1051             }
1052         }
1053         final long totalRunningDuration = getTotalRunningDuration(now);
1054         if (totalRunningDuration != 0) {
1055             pw.print(prefix);
1056             pw.print("Cur time ");
1057             TimeUtils.formatDuration(totalRunningDuration, pw);
1058             if (mTotalRunningStartTime != 0) {
1059                 pw.print(" (running)");
1060             }
1061             if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1062                 pw.print(": ");
1063                 dumpPssSamples(pw, mTotalRunningPss, 0);
1064             }
1065             pw.println();
1066         }
1067         if (mNumExcessiveCpu != 0) {
1068             pw.print(prefix); pw.print("Killed for excessive CPU use: ");
1069                     pw.print(mNumExcessiveCpu); pw.println(" times");
1070         }
1071         if (mNumCachedKill != 0) {
1072             pw.print(prefix); pw.print("Killed from cached state: ");
1073                     pw.print(mNumCachedKill); pw.print(" times from pss ");
1074                     DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-");
1075                     DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-");
1076                     DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println();
1077         }
1078     }
1079 
dumpPssSamples(PrintWriter pw, long[] table, int offset)1080     public static void dumpPssSamples(PrintWriter pw, long[] table, int offset) {
1081         DebugUtils.printSizeValue(pw, table[offset + PSS_MINIMUM] * 1024);
1082         pw.print("-");
1083         DebugUtils.printSizeValue(pw, table[offset + PSS_AVERAGE] * 1024);
1084         pw.print("-");
1085         DebugUtils.printSizeValue(pw, table[offset + PSS_MAXIMUM] * 1024);
1086         pw.print("/");
1087         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MINIMUM] * 1024);
1088         pw.print("-");
1089         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_AVERAGE] * 1024);
1090         pw.print("-");
1091         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MAXIMUM] * 1024);
1092         pw.print("/");
1093         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MINIMUM] * 1024);
1094         pw.print("-");
1095         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_AVERAGE] * 1024);
1096         pw.print("-");
1097         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MAXIMUM] * 1024);
1098         pw.print(" over ");
1099         pw.print(table[offset + PSS_SAMPLE_COUNT]);
1100     }
1101 
dumpProcessSummaryDetails(PrintWriter pw, String prefix, String label, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime, boolean full)1102     private void dumpProcessSummaryDetails(PrintWriter pw, String prefix,
1103             String label, int[] screenStates, int[] memStates, int[] procStates,
1104             long now, long totalTime, boolean full) {
1105         ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
1106                 screenStates, memStates, procStates);
1107         computeProcessData(totals, now);
1108         final double percentage = (double) totals.totalTime / (double) totalTime * 100;
1109         // We don't print percentages < .01, so just drop those.
1110         if (percentage >= 0.005 || totals.numPss != 0) {
1111             if (prefix != null) {
1112                 pw.print(prefix);
1113             }
1114             if (label != null) {
1115                 pw.print("  ");
1116                 pw.print(label);
1117                 pw.print(": ");
1118             }
1119             totals.print(pw, totalTime, full);
1120             if (prefix != null) {
1121                 pw.println();
1122             }
1123         }
1124     }
1125 
dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage, long totalTime, long now, boolean dumpAll)1126     void dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage,
1127             long totalTime, long now, boolean dumpAll) {
1128         if (dumpAll) {
1129             pw.print(prefix); pw.print("myID=");
1130                     pw.print(Integer.toHexString(System.identityHashCode(this)));
1131                     pw.print(" mCommonProcess=");
1132                     pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess)));
1133                     pw.print(" mPackage="); pw.println(mPackage);
1134             if (mMultiPackage) {
1135                 pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage);
1136             }
1137             if (this != mCommonProcess) {
1138                 pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName);
1139                         pw.print("/"); pw.print(mCommonProcess.mUid);
1140                         pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
1141             }
1142             if (mCommonSources != null) {
1143                 pw.print(prefix); pw.println("Aggregated Association Sources:");
1144                 AssociationState.dumpSources(
1145                         pw, prefix + "  ", prefix + "    ", prefix + "        ",
1146                         AssociationState.createSortedAssociations(now, totalTime, mCommonSources),
1147                         now, totalTime, reqPackage, true, dumpAll);
1148             }
1149         }
1150         if (mActive) {
1151             pw.print(prefix); pw.print("mActive="); pw.println(mActive);
1152         }
1153         if (mDead) {
1154             pw.print(prefix); pw.print("mDead="); pw.println(mDead);
1155         }
1156         if (mNumActiveServices != 0 || mNumStartedServices != 0) {
1157             pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices);
1158                     pw.print(" mNumStartedServices=");
1159                     pw.println(mNumStartedServices);
1160         }
1161     }
1162 
computeProcessData(ProcessStats.ProcessDataCollection data, long now)1163     public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) {
1164         data.totalTime = 0;
1165         data.numPss = data.minPss = data.avgPss = data.maxPss =
1166                 data.minUss = data.avgUss = data.maxUss =
1167                 data.minRss = data.avgRss = data.maxRss = 0;
1168         for (int is=0; is<data.screenStates.length; is++) {
1169             for (int im=0; im<data.memStates.length; im++) {
1170                 for (int ip=0; ip<data.procStates.length; ip++) {
1171                     int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
1172                             + data.procStates[ip];
1173                     data.totalTime += getDuration(bucket, now);
1174                     long samples = getPssSampleCount(bucket);
1175                     if (samples > 0) {
1176                         long minPss = getPssMinimum(bucket);
1177                         long avgPss = getPssAverage(bucket);
1178                         long maxPss = getPssMaximum(bucket);
1179                         long minUss = getPssUssMinimum(bucket);
1180                         long avgUss = getPssUssAverage(bucket);
1181                         long maxUss = getPssUssMaximum(bucket);
1182                         long minRss = getPssRssMinimum(bucket);
1183                         long avgRss = getPssRssAverage(bucket);
1184                         long maxRss = getPssRssMaximum(bucket);
1185                         if (data.numPss == 0) {
1186                             data.minPss = minPss;
1187                             data.avgPss = avgPss;
1188                             data.maxPss = maxPss;
1189                             data.minUss = minUss;
1190                             data.avgUss = avgUss;
1191                             data.maxUss = maxUss;
1192                             data.minRss = minRss;
1193                             data.avgRss = avgRss;
1194                             data.maxRss = maxRss;
1195                         } else {
1196                             if (minPss < data.minPss) {
1197                                 data.minPss = minPss;
1198                             }
1199                             data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
1200                                     + (avgPss*(double)samples)) / (data.numPss+samples) );
1201                             if (maxPss > data.maxPss) {
1202                                 data.maxPss = maxPss;
1203                             }
1204                             if (minUss < data.minUss) {
1205                                 data.minUss = minUss;
1206                             }
1207                             data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
1208                                     + (avgUss*(double)samples)) / (data.numPss+samples) );
1209                             if (maxUss > data.maxUss) {
1210                                 data.maxUss = maxUss;
1211                             }
1212                             if (minRss < data.minRss) {
1213                                 data.minRss = minRss;
1214                             }
1215                             data.avgRss = (long)( ((data.avgRss*(double)data.numPss)
1216                                     + (avgRss*(double)samples)) / (data.numPss+samples) );
1217                             if (maxRss > data.maxRss) {
1218                                 data.maxRss = maxRss;
1219                             }
1220                         }
1221                         data.numPss += samples;
1222                     }
1223                 }
1224             }
1225         }
1226     }
1227 
dumpCsv(PrintWriter pw, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)1228     public void dumpCsv(PrintWriter pw,
1229             boolean sepScreenStates, int[] screenStates, boolean sepMemStates,
1230             int[] memStates, boolean sepProcStates, int[] procStates, long now) {
1231         final int NSS = sepScreenStates ? screenStates.length : 1;
1232         final int NMS = sepMemStates ? memStates.length : 1;
1233         final int NPS = sepProcStates ? procStates.length : 1;
1234         for (int iss=0; iss<NSS; iss++) {
1235             for (int ims=0; ims<NMS; ims++) {
1236                 for (int ips=0; ips<NPS; ips++) {
1237                     final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
1238                     final int vsmem = sepMemStates ? memStates[ims] : 0;
1239                     final int vsproc = sepProcStates ? procStates[ips] : 0;
1240                     final int NSA = sepScreenStates ? 1 : screenStates.length;
1241                     final int NMA = sepMemStates ? 1 : memStates.length;
1242                     final int NPA = sepProcStates ? 1 : procStates.length;
1243                     long totalTime = 0;
1244                     for (int isa=0; isa<NSA; isa++) {
1245                         for (int ima=0; ima<NMA; ima++) {
1246                             for (int ipa=0; ipa<NPA; ipa++) {
1247                                 final int vascreen = sepScreenStates ? 0 : screenStates[isa];
1248                                 final int vamem = sepMemStates ? 0 : memStates[ima];
1249                                 final int vaproc = sepProcStates ? 0 : procStates[ipa];
1250                                 final int bucket = ((vsscreen + vascreen + vsmem + vamem)
1251                                         * STATE_COUNT) + vsproc + vaproc;
1252                                 totalTime += getDuration(bucket, now);
1253                             }
1254                         }
1255                     }
1256                     pw.print(DumpUtils.CSV_SEP);
1257                     pw.print(totalTime);
1258                 }
1259             }
1260         }
1261     }
1262 
dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers, String itemName, long now)1263     public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers,
1264             String itemName, long now) {
1265         pw.print("pkgproc,");
1266         pw.print(pkgName);
1267         pw.print(",");
1268         pw.print(uid);
1269         pw.print(",");
1270         pw.print(vers);
1271         pw.print(",");
1272         pw.print(DumpUtils.collapseString(pkgName, itemName));
1273         dumpAllStateCheckin(pw, now);
1274         pw.println();
1275         if (mPssTable.getKeyCount() > 0) {
1276             pw.print("pkgpss,");
1277             pw.print(pkgName);
1278             pw.print(",");
1279             pw.print(uid);
1280             pw.print(",");
1281             pw.print(vers);
1282             pw.print(",");
1283             pw.print(DumpUtils.collapseString(pkgName, itemName));
1284             dumpAllPssCheckin(pw);
1285             pw.println();
1286         }
1287         if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1288             pw.print("pkgrun,");
1289             pw.print(pkgName);
1290             pw.print(",");
1291             pw.print(uid);
1292             pw.print(",");
1293             pw.print(vers);
1294             pw.print(",");
1295             pw.print(DumpUtils.collapseString(pkgName, itemName));
1296             pw.print(",");
1297             pw.print(getTotalRunningDuration(now));
1298             pw.print(",");
1299             dumpPssSamplesCheckin(pw, mTotalRunningPss, 0);
1300             pw.println();
1301         }
1302         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1303             pw.print("pkgkills,");
1304             pw.print(pkgName);
1305             pw.print(",");
1306             pw.print(uid);
1307             pw.print(",");
1308             pw.print(vers);
1309             pw.print(",");
1310             pw.print(DumpUtils.collapseString(pkgName, itemName));
1311             pw.print(",");
1312             pw.print("0"); // was mNumExcessiveWake
1313             pw.print(",");
1314             pw.print(mNumExcessiveCpu);
1315             pw.print(",");
1316             pw.print(mNumCachedKill);
1317             pw.print(",");
1318             pw.print(mMinCachedKillPss);
1319             pw.print(":");
1320             pw.print(mAvgCachedKillPss);
1321             pw.print(":");
1322             pw.print(mMaxCachedKillPss);
1323             pw.println();
1324         }
1325     }
1326 
dumpProcCheckin(PrintWriter pw, String procName, int uid, long now)1327     public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) {
1328         if (mDurations.getKeyCount() > 0) {
1329             pw.print("proc,");
1330             pw.print(procName);
1331             pw.print(",");
1332             pw.print(uid);
1333             dumpAllStateCheckin(pw, now);
1334             pw.println();
1335         }
1336         if (mPssTable.getKeyCount() > 0) {
1337             pw.print("pss,");
1338             pw.print(procName);
1339             pw.print(",");
1340             pw.print(uid);
1341             dumpAllPssCheckin(pw);
1342             pw.println();
1343         }
1344         if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1345             pw.print("procrun,");
1346             pw.print(procName);
1347             pw.print(",");
1348             pw.print(uid);
1349             pw.print(",");
1350             pw.print(getTotalRunningDuration(now));
1351             pw.print(",");
1352             dumpPssSamplesCheckin(pw, mTotalRunningPss, 0);
1353             pw.println();
1354         }
1355         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1356             pw.print("kills,");
1357             pw.print(procName);
1358             pw.print(",");
1359             pw.print(uid);
1360             pw.print(",");
1361             pw.print("0"); // was mNumExcessiveWake
1362             pw.print(",");
1363             pw.print(mNumExcessiveCpu);
1364             pw.print(",");
1365             pw.print(mNumCachedKill);
1366             pw.print(",");
1367             pw.print(mMinCachedKillPss);
1368             pw.print(":");
1369             pw.print(mAvgCachedKillPss);
1370             pw.print(":");
1371             pw.print(mMaxCachedKillPss);
1372             pw.println();
1373         }
1374     }
1375 
dumpAllStateCheckin(PrintWriter pw, long now)1376     public void dumpAllStateCheckin(PrintWriter pw, long now) {
1377         boolean didCurState = false;
1378         for (int i=0; i<mDurations.getKeyCount(); i++) {
1379             final int key = mDurations.getKeyAt(i);
1380             final int type = SparseMappingTable.getIdFromKey(key);
1381             long time = mDurations.getValue(key);
1382             if (mCurCombinedState == type) {
1383                 didCurState = true;
1384                 time += now - mStartTime;
1385             }
1386             DumpUtils.printProcStateTagAndValue(pw, type, time);
1387         }
1388         if (!didCurState && mCurCombinedState != STATE_NOTHING) {
1389             DumpUtils.printProcStateTagAndValue(pw, mCurCombinedState, now - mStartTime);
1390         }
1391     }
1392 
dumpAllPssCheckin(PrintWriter pw)1393     public void dumpAllPssCheckin(PrintWriter pw) {
1394         final int N = mPssTable.getKeyCount();
1395         for (int i=0; i<N; i++) {
1396             final int key = mPssTable.getKeyAt(i);
1397             final int type = SparseMappingTable.getIdFromKey(key);
1398             pw.print(',');
1399             DumpUtils.printProcStateTag(pw, type);
1400             pw.print(':');
1401             dumpPssSamplesCheckin(pw, mPssTable.getArrayForKey(key),
1402                     SparseMappingTable.getIndexFromKey(key));
1403         }
1404     }
1405 
dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset)1406     public static void dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset) {
1407         pw.print(table[offset + PSS_SAMPLE_COUNT]);
1408         pw.print(':');
1409         pw.print(table[offset + PSS_MINIMUM]);
1410         pw.print(':');
1411         pw.print(table[offset + PSS_AVERAGE]);
1412         pw.print(':');
1413         pw.print(table[offset + PSS_MAXIMUM]);
1414         pw.print(':');
1415         pw.print(table[offset + PSS_USS_MINIMUM]);
1416         pw.print(':');
1417         pw.print(table[offset + PSS_USS_AVERAGE]);
1418         pw.print(':');
1419         pw.print(table[offset + PSS_USS_MAXIMUM]);
1420         pw.print(':');
1421         pw.print(table[offset + PSS_RSS_MINIMUM]);
1422         pw.print(':');
1423         pw.print(table[offset + PSS_RSS_AVERAGE]);
1424         pw.print(':');
1425         pw.print(table[offset + PSS_RSS_MAXIMUM]);
1426     }
1427 
1428     @Override
toString()1429     public String toString() {
1430         StringBuilder sb = new StringBuilder(128);
1431         sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
1432                 .append(" ").append(mName).append("/").append(mUid)
1433                 .append(" pkg=").append(mPackage);
1434         if (mMultiPackage) sb.append(" (multi)");
1435         if (mCommonProcess != this) sb.append(" (sub)");
1436         sb.append("}");
1437         return sb.toString();
1438     }
1439 
dumpDebug(ProtoOutputStream proto, long fieldId, String procName, int uid, long now)1440     public void dumpDebug(ProtoOutputStream proto, long fieldId,
1441             String procName, int uid, long now) {
1442         final long token = proto.start(fieldId);
1443         proto.write(ProcessStatsProto.PROCESS, procName);
1444         proto.write(ProcessStatsProto.UID, uid);
1445         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) {
1446             final long killToken = proto.start(ProcessStatsProto.KILL);
1447             proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu);
1448             proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill);
1449             ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS,
1450                     mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss);
1451             proto.end(killToken);
1452         }
1453 
1454         // Group proc stats by type (screen state + mem state + process state)
1455         SparseLongArray durationByState = new SparseLongArray();
1456         boolean didCurState = false;
1457         for (int i=0; i<mDurations.getKeyCount(); i++) {
1458             final int key = mDurations.getKeyAt(i);
1459             final int type = SparseMappingTable.getIdFromKey(key);
1460             long time = mDurations.getValue(key);
1461             if (mCurCombinedState == type) {
1462                 didCurState = true;
1463                 time += now - mStartTime;
1464             }
1465             durationByState.put(type, time);
1466         }
1467         if (!didCurState && mCurCombinedState != STATE_NOTHING) {
1468             durationByState.put(mCurCombinedState, now - mStartTime);
1469         }
1470 
1471         for (int i=0; i<mPssTable.getKeyCount(); i++) {
1472             final int key = mPssTable.getKeyAt(i);
1473             final int type = SparseMappingTable.getIdFromKey(key);
1474             if (durationByState.indexOfKey(type) < 0) {
1475                 // state without duration should not have stats!
1476                 continue;
1477             }
1478             final long stateToken = proto.start(ProcessStatsProto.STATES);
1479             DumpUtils.printProcStateTagProto(proto,
1480                     ProcessStatsStateProto.SCREEN_STATE,
1481                     ProcessStatsStateProto.MEMORY_STATE,
1482                     ProcessStatsStateProto.PROCESS_STATE,
1483                     type);
1484 
1485             long duration = durationByState.get(type);
1486             durationByState.delete(type); // remove the key since it is already being dumped.
1487             proto.write(ProcessStatsStateProto.DURATION_MS, duration);
1488 
1489             mPssTable.writeStatsToProtoForKey(proto, key);
1490 
1491             proto.end(stateToken);
1492         }
1493 
1494         for (int i = 0; i < durationByState.size(); i++) {
1495             final long stateToken = proto.start(ProcessStatsProto.STATES);
1496             DumpUtils.printProcStateTagProto(proto,
1497                     ProcessStatsStateProto.SCREEN_STATE,
1498                     ProcessStatsStateProto.MEMORY_STATE,
1499                     ProcessStatsStateProto.PROCESS_STATE,
1500                     durationByState.keyAt(i));
1501             proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.valueAt(i));
1502             proto.end(stateToken);
1503         }
1504 
1505         final long totalRunningDuration = getTotalRunningDuration(now);
1506         if (totalRunningDuration > 0) {
1507             final long stateToken = proto.start(ProcessStatsProto.TOTAL_RUNNING_STATE);
1508             proto.write(ProcessStatsStateProto.DURATION_MS, totalRunningDuration);
1509             if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1510                 PssTable.writeStatsToProto(proto, mTotalRunningPss, 0);
1511             }
1512             proto.end(stateToken);
1513         }
1514 
1515         proto.end(token);
1516     }
1517 
1518     /**
1519      * Assume the atom already includes a UID field, write the process name only if
1520      * it's different from the package name; and only write the suffix if possible.
1521      */
writeCompressedProcessName(final ProtoOutputStream proto, final long fieldId, final String procName, final String packageName, final boolean sharedUid)1522     static void writeCompressedProcessName(final ProtoOutputStream proto, final long fieldId,
1523             final String procName, final String packageName, final boolean sharedUid) {
1524         if (sharedUid) {
1525             // This UID has multiple packages running, write the full process name here
1526             proto.write(fieldId, procName);
1527             return;
1528         }
1529         if (TextUtils.equals(procName, packageName)) {
1530             // Same name, don't bother to write the process name here.
1531             return;
1532         }
1533         if (procName.startsWith(packageName)) {
1534             final int pkgLength = packageName.length();
1535             if (procName.charAt(pkgLength) == ':') {
1536                 // Only write the suffix starting with ':'
1537                 proto.write(fieldId, procName.substring(pkgLength));
1538                 return;
1539             }
1540         }
1541         // Write the full process name
1542         proto.write(fieldId, procName);
1543     }
1544 
1545     /** Dumps the duration of each state to statsEventOutput. */
dumpStateDurationToStatsd( int atomTag, ProcessStats processStats, StatsEventOutput statsEventOutput)1546     public void dumpStateDurationToStatsd(
1547             int atomTag, ProcessStats processStats, StatsEventOutput statsEventOutput) {
1548         long topMs = 0;
1549         long fgsMs = 0;
1550         long boundTopMs = 0;
1551         long boundFgsMs = 0;
1552         long importantForegroundMs = 0;
1553         long cachedMs = 0;
1554         long frozenMs = 0;
1555         long otherMs = 0;
1556         for (int i = 0, size = mDurations.getKeyCount(); i < size; i++) {
1557             final int key = mDurations.getKeyAt(i);
1558             final int type = SparseMappingTable.getIdFromKey(key);
1559             int procStateIndex = type % STATE_COUNT;
1560             long duration = mDurations.getValue(key);
1561             switch (procStateIndex) {
1562                 case STATE_TOP:
1563                     topMs += duration;
1564                     break;
1565                 case STATE_BOUND_FGS:
1566                     boundFgsMs += duration;
1567                     break;
1568                 case STATE_BOUND_TOP:
1569                     boundTopMs += duration;
1570                     break;
1571                 case STATE_FGS:
1572                     fgsMs += duration;
1573                     break;
1574                 case STATE_IMPORTANT_FOREGROUND:
1575                 case STATE_IMPORTANT_BACKGROUND:
1576                     importantForegroundMs += duration;
1577                     break;
1578                 case STATE_BACKUP:
1579                 case STATE_SERVICE:
1580                 case STATE_SERVICE_RESTARTING:
1581                 case STATE_RECEIVER:
1582                 case STATE_HEAVY_WEIGHT:
1583                 case STATE_HOME:
1584                 case STATE_LAST_ACTIVITY:
1585                 case STATE_PERSISTENT:
1586                     otherMs += duration;
1587                     break;
1588                 case STATE_CACHED:
1589                     cachedMs += duration;
1590                     break;
1591                     // TODO (b/261910877) Add support for tracking frozenMs.
1592             }
1593         }
1594         statsEventOutput.write(
1595                 atomTag,
1596                 getUid(),
1597                 getName(),
1598                 (int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodStartUptime),
1599                 (int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodEndUptime),
1600                 (int)
1601                         TimeUnit.MILLISECONDS.toSeconds(
1602                                 processStats.mTimePeriodEndUptime
1603                                         - processStats.mTimePeriodStartUptime),
1604                 (int) TimeUnit.MILLISECONDS.toSeconds(topMs),
1605                 (int) TimeUnit.MILLISECONDS.toSeconds(fgsMs),
1606                 (int) TimeUnit.MILLISECONDS.toSeconds(boundTopMs),
1607                 (int) TimeUnit.MILLISECONDS.toSeconds(boundFgsMs),
1608                 (int) TimeUnit.MILLISECONDS.toSeconds(importantForegroundMs),
1609                 (int) TimeUnit.MILLISECONDS.toSeconds(cachedMs),
1610                 (int) TimeUnit.MILLISECONDS.toSeconds(frozenMs),
1611                 (int) TimeUnit.MILLISECONDS.toSeconds(otherMs));
1612     }
1613 
1614     /** Similar to {@code #dumpDebug}, but with a reduced/aggregated subset of states. */
dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId, String procName, int uid, long now, final ProcessMap<ArraySet<PackageState>> procToPkgMap, final SparseArray<ArraySet<String>> uidToPkgMap)1615     public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
1616             String procName, int uid, long now,
1617             final ProcessMap<ArraySet<PackageState>> procToPkgMap,
1618             final SparseArray<ArraySet<String>> uidToPkgMap) {
1619         // Group proc stats by aggregated type (only screen state + process state)
1620         SparseLongArray durationByState = new SparseLongArray();
1621         boolean didCurState = false;
1622         for (int i = 0; i < mDurations.getKeyCount(); i++) {
1623             final int key = mDurations.getKeyAt(i);
1624             final int type = SparseMappingTable.getIdFromKey(key);
1625             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type);
1626             if ((type % STATE_COUNT) == STATE_SERVICE_RESTARTING) {
1627                 // Skip restarting service state -- that is not actually a running process.
1628                 continue;
1629             }
1630 
1631             long time = mDurations.getValue(key);
1632             if (mCurCombinedState == type) {
1633                 didCurState = true;
1634                 time += now - mStartTime;
1635             }
1636             int index = durationByState.indexOfKey(aggregatedType);
1637             if (index >= 0) {
1638                 durationByState.put(aggregatedType, time + durationByState.valueAt(index));
1639             } else {
1640                 durationByState.put(aggregatedType, time);
1641             }
1642         }
1643         if (!didCurState && mCurCombinedState != STATE_NOTHING
1644                 && (mCurCombinedState % STATE_COUNT) != STATE_SERVICE_RESTARTING) {
1645             // Skip restarting service state -- that is not actually a running process.
1646             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(mCurCombinedState);
1647             int index = durationByState.indexOfKey(aggregatedType);
1648             if (index >= 0) {
1649                 durationByState.put(aggregatedType,
1650                         (now - mStartTime) + durationByState.valueAt(index));
1651             } else {
1652                 durationByState.put(aggregatedType, now - mStartTime);
1653             }
1654         }
1655 
1656         // Now we have total durations, aggregate the RSS values
1657         SparseLongArray meanRssByState = new SparseLongArray();
1658         SparseLongArray maxRssByState = new SparseLongArray();
1659         // compute weighted averages and max-of-max
1660         for (int i = 0; i < mPssTable.getKeyCount(); i++) {
1661             final int key = mPssTable.getKeyAt(i);
1662             final int type = SparseMappingTable.getIdFromKey(key);
1663             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type);
1664             if (durationByState.indexOfKey(aggregatedType) < 0) {
1665                 // state without duration should not have stats!
1666                 continue;
1667             }
1668 
1669             long[] rssMeanAndMax = mPssTable.getRssMeanAndMax(key);
1670 
1671             // compute mean * duration, then store sum of that in meanRssByState
1672             long meanTimesDuration = rssMeanAndMax[0] * mDurations.getValueForId((byte) type);
1673             if (meanRssByState.indexOfKey(aggregatedType) >= 0) {
1674                 meanRssByState.put(aggregatedType,
1675                         meanTimesDuration + meanRssByState.get(aggregatedType));
1676             } else {
1677                 meanRssByState.put(aggregatedType, meanTimesDuration);
1678             }
1679 
1680             // accumulate max-of-maxes in maxRssByState
1681             if (maxRssByState.indexOfKey(aggregatedType) >= 0
1682                     && maxRssByState.get(aggregatedType) < rssMeanAndMax[1]) {
1683                 maxRssByState.put(aggregatedType, rssMeanAndMax[1]);
1684             } else if (maxRssByState.indexOfKey(aggregatedType) < 0) {
1685                 maxRssByState.put(aggregatedType, rssMeanAndMax[1]);
1686             }
1687         }
1688 
1689         // divide the means by the durations to get the weighted mean-of-means
1690         for (int i = 0; i < durationByState.size(); i++) {
1691             int aggregatedKey = durationByState.keyAt(i);
1692             if (meanRssByState.indexOfKey(aggregatedKey) < 0) {
1693                 // these data structures should be consistent
1694                 continue;
1695             }
1696             final long duration = durationByState.get(aggregatedKey);
1697             meanRssByState.put(aggregatedKey,
1698                     duration > 0 ? (meanRssByState.get(aggregatedKey) / duration)
1699                             : meanRssByState.get(aggregatedKey));
1700         }
1701 
1702         // build the output
1703         final long token = proto.start(fieldId);
1704         writeCompressedProcessName(proto, ProcessStatsProto.PROCESS, procName, mPackage,
1705                 mMultiPackage || (uidToPkgMap.get(mUid).size() > 1));
1706         proto.write(ProcessStatsProto.UID, uid);
1707 
1708         for (int i = 0; i < durationByState.size(); i++) {
1709             final long stateToken = proto.start(ProcessStatsProto.STATES);
1710 
1711             final int aggregatedKey = durationByState.keyAt(i);
1712 
1713             DumpUtils.printAggregatedProcStateTagProto(proto,
1714                     ProcessStatsStateProto.SCREEN_STATE,
1715                     ProcessStatsStateProto.PROCESS_STATE_AGGREGATED,
1716                     aggregatedKey);
1717             proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.get(aggregatedKey));
1718 
1719             ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.RSS,
1720                     0, /* do not output a minimum value */
1721                     0, /* do not output an average value */
1722                     0, /* do not output a max value */
1723                     (int) meanRssByState.get(aggregatedKey),
1724                     (int) maxRssByState.get(aggregatedKey));
1725 
1726             proto.end(stateToken);
1727         }
1728 
1729         mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
1730                 now, this, uidToPkgMap);
1731         proto.end(token);
1732     }
1733 }
1734