• 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_TOP_OR_FGS;
32 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY;
33 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT;
34 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY;
35 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
36 import static com.android.internal.app.procstats.ProcessStats.STATE_FGS;
37 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT;
38 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME;
39 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND;
40 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND;
41 import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY;
42 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
43 import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT;
44 import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER;
45 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE;
46 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING;
47 import static com.android.internal.app.procstats.ProcessStats.STATE_TOP;
48 
49 import android.os.Parcel;
50 import android.os.SystemClock;
51 import android.os.UserHandle;
52 import android.service.procstats.ProcessStatsProto;
53 import android.service.procstats.ProcessStatsStateProto;
54 import android.text.TextUtils;
55 import android.util.ArrayMap;
56 import android.util.ArraySet;
57 import android.util.DebugUtils;
58 import android.util.Log;
59 import android.util.LongSparseArray;
60 import android.util.Slog;
61 import android.util.SparseArray;
62 import android.util.SparseLongArray;
63 import android.util.TimeUtils;
64 import android.util.proto.ProtoOutputStream;
65 import android.util.proto.ProtoUtils;
66 
67 import com.android.internal.app.ProcessMap;
68 import com.android.internal.app.procstats.AssociationState.SourceKey;
69 import com.android.internal.app.procstats.AssociationState.SourceState;
70 import com.android.internal.app.procstats.ProcessStats.PackageState;
71 import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
72 import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
73 
74 import java.io.PrintWriter;
75 import java.util.Comparator;
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_OR_FGS,         // ActivityManager.PROCESS_STATE_BOUND_TOP
88         STATE_FGS,                      // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
89         STATE_BOUND_TOP_OR_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_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY
101         STATE_CACHED_ACTIVITY_CLIENT,   // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT
102         STATE_CACHED_ACTIVITY,          // ActivityManager.PROCESS_STATE_CACHED_RECENT
103         STATE_CACHED_EMPTY,             // 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         }
477     }
478 
getCombinedState()479     public int getCombinedState() {
480         return mCurCombinedState;
481     }
482 
commitStateTime(long now)483     public void commitStateTime(long now) {
484         if (mCurCombinedState != STATE_NOTHING) {
485             long dur = now - mStartTime;
486             if (dur > 0) {
487                 mDurations.addDuration(mCurCombinedState, dur);
488             }
489             mTotalRunningDuration += now - mTotalRunningStartTime;
490             mTotalRunningStartTime = now;
491         }
492         mStartTime = now;
493         if (mCommonSources != null) {
494             for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) {
495                 final SourceState src = mCommonSources.valueAt(ip);
496                 src.commitStateTime(now);
497             }
498         }
499     }
500 
incActiveServices(String serviceName)501     public void incActiveServices(String serviceName) {
502         if (DEBUG && "".equals(mName)) {
503             RuntimeException here = new RuntimeException("here");
504             here.fillInStackTrace();
505             Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName
506                     + " to " + (mNumActiveServices+1), here);
507         }
508         if (mCommonProcess != this) {
509             mCommonProcess.incActiveServices(serviceName);
510         }
511         mNumActiveServices++;
512     }
513 
decActiveServices(String serviceName)514     public void decActiveServices(String serviceName) {
515         if (DEBUG && "".equals(mName)) {
516             RuntimeException here = new RuntimeException("here");
517             here.fillInStackTrace();
518             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
519                     + " to " + (mNumActiveServices-1), here);
520         }
521         if (mCommonProcess != this) {
522             mCommonProcess.decActiveServices(serviceName);
523         }
524         mNumActiveServices--;
525         if (mNumActiveServices < 0) {
526             Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage
527                     + " uid=" + mUid + " proc=" + mName + " service=" + serviceName);
528             mNumActiveServices = 0;
529         }
530     }
531 
incStartedServices(int memFactor, long now, String serviceName)532     public void incStartedServices(int memFactor, long now, String serviceName) {
533         if (false) {
534             RuntimeException here = new RuntimeException("here");
535             here.fillInStackTrace();
536             Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName
537                     + " to " + (mNumStartedServices+1), here);
538         }
539         if (mCommonProcess != this) {
540             mCommonProcess.incStartedServices(memFactor, now, serviceName);
541         }
542         mNumStartedServices++;
543         if (mNumStartedServices == 1 && mCurCombinedState == STATE_NOTHING) {
544             setCombinedState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now);
545         }
546     }
547 
decStartedServices(int memFactor, long now, String serviceName)548     public void decStartedServices(int memFactor, long now, String serviceName) {
549         if (false) {
550             RuntimeException here = new RuntimeException("here");
551             here.fillInStackTrace();
552             Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName
553                     + " to " + (mNumStartedServices-1), here);
554         }
555         if (mCommonProcess != this) {
556             mCommonProcess.decStartedServices(memFactor, now, serviceName);
557         }
558         mNumStartedServices--;
559         if (mNumStartedServices == 0 && (mCurCombinedState %STATE_COUNT) == STATE_SERVICE_RESTARTING) {
560             setCombinedState(STATE_NOTHING, now);
561         } else if (mNumStartedServices < 0) {
562             Slog.wtfStack(TAG, "Proc started services underrun: pkg="
563                     + mPackage + " uid=" + mUid + " name=" + mName);
564             mNumStartedServices = 0;
565         }
566     }
567 
addPss(long pss, long uss, long rss, boolean always, int type, long duration, ArrayMap<String, ProcessStateHolder> pkgList)568     public void addPss(long pss, long uss, long rss, boolean always, int type, long duration,
569             ArrayMap<String, ProcessStateHolder> pkgList) {
570         ensureNotDead();
571         switch (type) {
572             case ProcessStats.ADD_PSS_INTERNAL_SINGLE:
573                 mStats.mInternalSinglePssCount++;
574                 mStats.mInternalSinglePssTime += duration;
575                 break;
576             case ProcessStats.ADD_PSS_INTERNAL_ALL_MEM:
577                 mStats.mInternalAllMemPssCount++;
578                 mStats.mInternalAllMemPssTime += duration;
579                 break;
580             case ProcessStats.ADD_PSS_INTERNAL_ALL_POLL:
581                 mStats.mInternalAllPollPssCount++;
582                 mStats.mInternalAllPollPssTime += duration;
583                 break;
584             case ProcessStats.ADD_PSS_EXTERNAL:
585                 mStats.mExternalPssCount++;
586                 mStats.mExternalPssTime += duration;
587                 break;
588             case ProcessStats.ADD_PSS_EXTERNAL_SLOW:
589                 mStats.mExternalSlowPssCount++;
590                 mStats.mExternalSlowPssTime += duration;
591                 break;
592         }
593         if (!always) {
594             if (mLastPssState == mCurCombinedState && SystemClock.uptimeMillis()
595                     < (mLastPssTime+(30*1000))) {
596                 return;
597             }
598         }
599         mLastPssState = mCurCombinedState;
600         mLastPssTime = SystemClock.uptimeMillis();
601         if (mCurCombinedState != STATE_NOTHING) {
602             // First update the common process.
603             mCommonProcess.mPssTable.mergeStats(mCurCombinedState, 1, pss, pss, pss, uss, uss, uss,
604                     rss, rss, rss);
605             PssTable.mergeStats(mCommonProcess.mTotalRunningPss, 0, 1, pss, pss, pss, uss, uss, uss,
606                     rss, rss, rss);
607 
608             // If the common process is not multi-package, there is nothing else to do.
609             if (!mCommonProcess.mMultiPackage) {
610                 return;
611             }
612 
613             if (pkgList != null) {
614                 for (int ip=pkgList.size()-1; ip>=0; ip--) {
615                     ProcessState fixedProc = pullFixedProc(pkgList, ip);
616                     fixedProc.mPssTable.mergeStats(mCurCombinedState, 1,
617                             pss, pss, pss, uss, uss, uss, rss, rss, rss);
618                     PssTable.mergeStats(fixedProc.mTotalRunningPss, 0, 1,
619                             pss, pss, pss, uss, uss, uss, rss, rss, rss);
620                 }
621             }
622         }
623     }
624 
reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList)625     public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) {
626         ensureNotDead();
627         mCommonProcess.mNumExcessiveCpu++;
628         if (!mCommonProcess.mMultiPackage) {
629             return;
630         }
631 
632         for (int ip=pkgList.size()-1; ip>=0; ip--) {
633             pullFixedProc(pkgList, ip).mNumExcessiveCpu++;
634         }
635     }
636 
addCachedKill(int num, long minPss, long avgPss, long maxPss)637     private void addCachedKill(int num, long minPss, long avgPss, long maxPss) {
638         if (mNumCachedKill <= 0) {
639             mNumCachedKill = num;
640             mMinCachedKillPss = minPss;
641             mAvgCachedKillPss = avgPss;
642             mMaxCachedKillPss = maxPss;
643         } else {
644             if (minPss < mMinCachedKillPss) {
645                 mMinCachedKillPss = minPss;
646             }
647             if (maxPss > mMaxCachedKillPss) {
648                 mMaxCachedKillPss = maxPss;
649             }
650             mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss)
651                     / (mNumCachedKill+num) );
652             mNumCachedKill += num;
653         }
654     }
655 
reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss)656     public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
657         ensureNotDead();
658         mCommonProcess.addCachedKill(1, pss, pss, pss);
659         if (!mCommonProcess.mMultiPackage) {
660             return;
661         }
662 
663         for (int ip=pkgList.size()-1; ip>=0; ip--) {
664             pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
665         }
666     }
667 
pullFixedProc(String pkgName)668     public ProcessState pullFixedProc(String pkgName) {
669         if (mMultiPackage) {
670             // The array map is still pointing to a common process state
671             // that is now shared across packages.  Update it to point to
672             // the new per-package state.
673             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
674             if (vpkg == null) {
675                 throw new IllegalStateException("Didn't find package " + pkgName
676                         + " / " + mUid);
677             }
678             PackageState pkg = vpkg.get(mVersion);
679             if (pkg == null) {
680                 throw new IllegalStateException("Didn't find package " + pkgName
681                         + " / " + mUid + " vers " + mVersion);
682             }
683             ProcessState proc = pkg.mProcesses.get(mName);
684             if (proc == null) {
685                 throw new IllegalStateException("Didn't create per-package process "
686                         + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
687             }
688             return proc;
689         }
690         return this;
691     }
692 
pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList, int index)693     private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
694             int index) {
695         ProcessStateHolder holder = pkgList.valueAt(index);
696         ProcessState proc = holder.state;
697         if (mDead && proc.mCommonProcess != proc) {
698             // Somehow we are continuing to use a process state that is dead, because
699             // it was not being told it was active during the last commit.  We can recover
700             // from this by generating a fresh new state, but this is bad because we
701             // are losing whatever data we had in the old process state.
702             Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
703                     + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
704             proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
705                     proc.mName);
706         }
707         if (proc.mMultiPackage) {
708             // The array map is still pointing to a common process state
709             // that is now shared across packages.  Update it to point to
710             // the new per-package state.
711             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
712                     proc.mUid);
713             if (vpkg == null) {
714                 throw new IllegalStateException("No existing package "
715                         + pkgList.keyAt(index) + "/" + proc.mUid
716                         + " for multi-proc " + proc.mName);
717             }
718             PackageState expkg = vpkg.get(proc.mVersion);
719             if (expkg == null) {
720                 throw new IllegalStateException("No existing package "
721                         + pkgList.keyAt(index) + "/" + proc.mUid
722                         + " for multi-proc " + proc.mName + " version " + proc.mVersion);
723             }
724             String savedName = proc.mName;
725             proc = expkg.mProcesses.get(proc.mName);
726             if (proc == null) {
727                 throw new IllegalStateException("Didn't create per-package process "
728                         + savedName + " in pkg " + expkg.mPackageName + "/" + expkg.mUid);
729             }
730             holder.state = proc;
731         }
732         return proc;
733     }
734 
getTotalRunningDuration(long now)735     public long getTotalRunningDuration(long now) {
736         return mTotalRunningDuration +
737                 (mTotalRunningStartTime != 0 ? (now - mTotalRunningStartTime) : 0);
738     }
739 
getDuration(int state, long now)740     public long getDuration(int state, long now) {
741         long time = mDurations.getValueForId((byte)state);
742         if (mCurCombinedState == state) {
743             time += now - mStartTime;
744         }
745         return time;
746     }
747 
getPssSampleCount(int state)748     public long getPssSampleCount(int state) {
749         return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
750     }
751 
getPssMinimum(int state)752     public long getPssMinimum(int state) {
753         return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
754     }
755 
getPssAverage(int state)756     public long getPssAverage(int state) {
757         return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
758     }
759 
getPssMaximum(int state)760     public long getPssMaximum(int state) {
761         return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
762     }
763 
getPssUssMinimum(int state)764     public long getPssUssMinimum(int state) {
765         return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
766     }
767 
getPssUssAverage(int state)768     public long getPssUssAverage(int state) {
769         return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
770     }
771 
getPssUssMaximum(int state)772     public long getPssUssMaximum(int state) {
773         return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
774     }
775 
getPssRssMinimum(int state)776     public long getPssRssMinimum(int state) {
777         return mPssTable.getValueForId((byte)state, PSS_RSS_MINIMUM);
778     }
779 
getPssRssAverage(int state)780     public long getPssRssAverage(int state) {
781         return mPssTable.getValueForId((byte)state, PSS_RSS_AVERAGE);
782     }
783 
getPssRssMaximum(int state)784     public long getPssRssMaximum(int state) {
785         return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
786     }
787 
getOrCreateSourceState(SourceKey key)788     SourceState getOrCreateSourceState(SourceKey key) {
789         if (mCommonSources == null) {
790             mCommonSources = new ArrayMap<>();
791         }
792         SourceState state = mCommonSources.get(key);
793         if (state == null) {
794             state = new SourceState(mStats, null, this, key);
795             mCommonSources.put(key, state);
796         }
797         return state;
798     }
799 
800     /**
801      * Sums up the PSS data and adds it to 'data'.
802      *
803      * @param data The aggregate data is added here.
804      * @param now SystemClock.uptimeMillis()
805      */
aggregatePss(TotalMemoryUseCollection data, long now)806     public void aggregatePss(TotalMemoryUseCollection data, long now) {
807         final PssAggr fgPss = new PssAggr();
808         final PssAggr bgPss = new PssAggr();
809         final PssAggr cachedPss = new PssAggr();
810         boolean havePss = false;
811         for (int i=0; i<mDurations.getKeyCount(); i++) {
812             final int key = mDurations.getKeyAt(i);
813             int type = SparseMappingTable.getIdFromKey(key);
814             int procState = type % STATE_COUNT;
815             long samples = getPssSampleCount(type);
816             if (samples > 0) {
817                 long avg = getPssAverage(type);
818                 havePss = true;
819                 if (procState <= STATE_IMPORTANT_FOREGROUND) {
820                     fgPss.add(avg, samples);
821                 } else if (procState <= STATE_RECEIVER) {
822                     bgPss.add(avg, samples);
823                 } else {
824                     cachedPss.add(avg, samples);
825                 }
826             }
827         }
828         if (!havePss) {
829             return;
830         }
831         boolean fgHasBg = false;
832         boolean fgHasCached = false;
833         boolean bgHasCached = false;
834         if (fgPss.samples < 3 && bgPss.samples > 0) {
835             fgHasBg = true;
836             fgPss.add(bgPss.pss, bgPss.samples);
837         }
838         if (fgPss.samples < 3 && cachedPss.samples > 0) {
839             fgHasCached = true;
840             fgPss.add(cachedPss.pss, cachedPss.samples);
841         }
842         if (bgPss.samples < 3 && cachedPss.samples > 0) {
843             bgHasCached = true;
844             bgPss.add(cachedPss.pss, cachedPss.samples);
845         }
846         if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
847             bgPss.add(fgPss.pss, fgPss.samples);
848         }
849         if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
850             cachedPss.add(bgPss.pss, bgPss.samples);
851         }
852         if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
853             cachedPss.add(fgPss.pss, fgPss.samples);
854         }
855         for (int i=0; i<mDurations.getKeyCount(); i++) {
856             final int key = mDurations.getKeyAt(i);
857             final int type = SparseMappingTable.getIdFromKey(key);
858             long time = mDurations.getValue(key);
859             if (mCurCombinedState == type) {
860                 time += now - mStartTime;
861             }
862             final int procState = type % STATE_COUNT;
863             data.processStateTime[procState] += time;
864             long samples = getPssSampleCount(type);
865             long avg;
866             if (samples > 0) {
867                 avg = getPssAverage(type);
868             } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
869                 samples = fgPss.samples;
870                 avg = fgPss.pss;
871             } else if (procState <= STATE_RECEIVER) {
872                 samples = bgPss.samples;
873                 avg = bgPss.pss;
874             } else {
875                 samples = cachedPss.samples;
876                 avg = cachedPss.pss;
877             }
878             double newAvg = ( (data.processStatePss[procState]
879                     * (double)data.processStateSamples[procState])
880                         + (avg*(double)samples)
881                     ) / (data.processStateSamples[procState]+samples);
882             data.processStatePss[procState] = (long)newAvg;
883             data.processStateSamples[procState] += samples;
884             data.processStateWeight[procState] += avg * (double)time;
885         }
886     }
887 
computeProcessTimeLocked(int[] screenStates, int[] memStates, int[] procStates, long now)888     public long computeProcessTimeLocked(int[] screenStates, int[] memStates,
889                 int[] procStates, long now) {
890         long totalTime = 0;
891         for (int is=0; is<screenStates.length; is++) {
892             for (int im=0; im<memStates.length; im++) {
893                 for (int ip=0; ip<procStates.length; ip++) {
894                     int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
895                             + procStates[ip];
896                     totalTime += getDuration(bucket, now);
897                 }
898             }
899         }
900         mTmpTotalTime = totalTime;
901         return totalTime;
902     }
903 
dumpSummary(PrintWriter pw, String prefix, String header, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)904     public void dumpSummary(PrintWriter pw, String prefix, String header,
905             int[] screenStates, int[] memStates, int[] procStates,
906             long now, long totalTime) {
907         pw.print(prefix);
908         pw.print("* ");
909         if (header != null) {
910             pw.print(header);
911         }
912         pw.print(mName);
913         pw.print(" / ");
914         UserHandle.formatUid(pw, mUid);
915         pw.print(" / v");
916         pw.print(mVersion);
917         pw.println(":");
918         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABEL_TOTAL,
919                 screenStates, memStates, procStates, now, totalTime, true);
920         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_PERSISTENT],
921                 screenStates, memStates, new int[] { STATE_PERSISTENT }, now, totalTime, true);
922         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_TOP],
923                 screenStates, memStates, new int[] {STATE_TOP}, now, totalTime, true);
924         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_TOP_OR_FGS],
925                 screenStates, memStates, new int[] { STATE_BOUND_TOP_OR_FGS}, now, totalTime,
926                 true);
927         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_FGS],
928                 screenStates, memStates, new int[] { STATE_FGS}, now, totalTime,
929                 true);
930         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_FOREGROUND],
931                 screenStates, memStates, new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime,
932                 true);
933         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_BACKGROUND],
934                 screenStates, memStates, new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime,
935                 true);
936         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BACKUP],
937                 screenStates, memStates, new int[] {STATE_BACKUP}, now, totalTime, true);
938         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE],
939                 screenStates, memStates, new int[] {STATE_SERVICE}, now, totalTime, true);
940         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE_RESTARTING],
941                 screenStates, memStates, new int[] {STATE_SERVICE_RESTARTING}, now, totalTime,
942                 true);
943         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_RECEIVER],
944                 screenStates, memStates, new int[] {STATE_RECEIVER}, now, totalTime, true);
945         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HEAVY_WEIGHT],
946                 screenStates, memStates, new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
947         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HOME],
948                 screenStates, memStates, new int[] {STATE_HOME}, now, totalTime, true);
949         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_LAST_ACTIVITY],
950                 screenStates, memStates, new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
951         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABEL_CACHED,
952                 screenStates, memStates, new int[] {STATE_CACHED_ACTIVITY,
953                         STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY}, now, totalTime, true);
954     }
955 
dumpProcessState(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)956     public void dumpProcessState(PrintWriter pw, String prefix,
957             int[] screenStates, int[] memStates, int[] procStates, long now) {
958         long totalTime = 0;
959         int printedScreen = -1;
960         for (int is=0; is<screenStates.length; is++) {
961             int printedMem = -1;
962             for (int im=0; im<memStates.length; im++) {
963                 for (int ip=0; ip<procStates.length; ip++) {
964                     final int iscreen = screenStates[is];
965                     final int imem = memStates[im];
966                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
967                     long time = mDurations.getValueForId((byte)bucket);
968                     String running = "";
969                     if (mCurCombinedState == bucket) {
970                         running = " (running)";
971                         time += now - mStartTime;
972                     }
973                     if (time != 0) {
974                         pw.print(prefix);
975                         if (screenStates.length > 1) {
976                             DumpUtils.printScreenLabel(pw, printedScreen != iscreen
977                                     ? iscreen : STATE_NOTHING);
978                             printedScreen = iscreen;
979                         }
980                         if (memStates.length > 1) {
981                             DumpUtils.printMemLabel(pw,
982                                     printedMem != imem ? imem : STATE_NOTHING, '/');
983                             printedMem = imem;
984                         }
985                         pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": ");
986                         TimeUtils.formatDuration(time, pw); pw.println(running);
987                         totalTime += time;
988                     }
989                 }
990             }
991         }
992         if (totalTime != 0) {
993             pw.print(prefix);
994             if (screenStates.length > 1) {
995                 DumpUtils.printScreenLabel(pw, STATE_NOTHING);
996             }
997             if (memStates.length > 1) {
998                 DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
999             }
1000             pw.print(DumpUtils.STATE_LABEL_TOTAL);
1001             pw.print(": ");
1002             TimeUtils.formatDuration(totalTime, pw);
1003             pw.println();
1004         }
1005     }
1006 
dumpPss(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)1007     public void dumpPss(PrintWriter pw, String prefix,
1008             int[] screenStates, int[] memStates, int[] procStates, long now) {
1009         boolean printedHeader = false;
1010         int printedScreen = -1;
1011         for (int is=0; is<screenStates.length; is++) {
1012             int printedMem = -1;
1013             for (int im=0; im<memStates.length; im++) {
1014                 for (int ip=0; ip<procStates.length; ip++) {
1015                     final int iscreen = screenStates[is];
1016                     final int imem = memStates[im];
1017                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
1018                     final int key = mPssTable.getKey((byte)bucket);
1019                     if (key == SparseMappingTable.INVALID_KEY) {
1020                         continue;
1021                     }
1022                     final long[] table = mPssTable.getArrayForKey(key);
1023                     final int tableOffset = SparseMappingTable.getIndexFromKey(key);
1024                     if (!printedHeader) {
1025                         pw.print(prefix);
1026                         pw.print("PSS/USS (");
1027                         pw.print(mPssTable.getKeyCount());
1028                         pw.println(" entries):");
1029                         printedHeader = true;
1030                     }
1031                     pw.print(prefix);
1032                     pw.print("  ");
1033                     if (screenStates.length > 1) {
1034                         DumpUtils.printScreenLabel(pw,
1035                                 printedScreen != iscreen ? iscreen : STATE_NOTHING);
1036                         printedScreen = iscreen;
1037                     }
1038                     if (memStates.length > 1) {
1039                         DumpUtils.printMemLabel(pw,
1040                                 printedMem != imem ? imem : STATE_NOTHING, '/');
1041                         printedMem = imem;
1042                     }
1043                     pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": ");
1044                     dumpPssSamples(pw, table, tableOffset);
1045                     pw.println();
1046                 }
1047             }
1048         }
1049         final long totalRunningDuration = getTotalRunningDuration(now);
1050         if (totalRunningDuration != 0) {
1051             pw.print(prefix);
1052             pw.print("Cur time ");
1053             TimeUtils.formatDuration(totalRunningDuration, pw);
1054             if (mTotalRunningStartTime != 0) {
1055                 pw.print(" (running)");
1056             }
1057             if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1058                 pw.print(": ");
1059                 dumpPssSamples(pw, mTotalRunningPss, 0);
1060             }
1061             pw.println();
1062         }
1063         if (mNumExcessiveCpu != 0) {
1064             pw.print(prefix); pw.print("Killed for excessive CPU use: ");
1065                     pw.print(mNumExcessiveCpu); pw.println(" times");
1066         }
1067         if (mNumCachedKill != 0) {
1068             pw.print(prefix); pw.print("Killed from cached state: ");
1069                     pw.print(mNumCachedKill); pw.print(" times from pss ");
1070                     DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-");
1071                     DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-");
1072                     DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println();
1073         }
1074     }
1075 
dumpPssSamples(PrintWriter pw, long[] table, int offset)1076     public static void dumpPssSamples(PrintWriter pw, long[] table, int offset) {
1077         DebugUtils.printSizeValue(pw, table[offset + PSS_MINIMUM] * 1024);
1078         pw.print("-");
1079         DebugUtils.printSizeValue(pw, table[offset + PSS_AVERAGE] * 1024);
1080         pw.print("-");
1081         DebugUtils.printSizeValue(pw, table[offset + PSS_MAXIMUM] * 1024);
1082         pw.print("/");
1083         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MINIMUM] * 1024);
1084         pw.print("-");
1085         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_AVERAGE] * 1024);
1086         pw.print("-");
1087         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MAXIMUM] * 1024);
1088         pw.print("/");
1089         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MINIMUM] * 1024);
1090         pw.print("-");
1091         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_AVERAGE] * 1024);
1092         pw.print("-");
1093         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MAXIMUM] * 1024);
1094         pw.print(" over ");
1095         pw.print(table[offset + PSS_SAMPLE_COUNT]);
1096     }
1097 
dumpProcessSummaryDetails(PrintWriter pw, String prefix, String label, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime, boolean full)1098     private void dumpProcessSummaryDetails(PrintWriter pw, String prefix,
1099             String label, int[] screenStates, int[] memStates, int[] procStates,
1100             long now, long totalTime, boolean full) {
1101         ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
1102                 screenStates, memStates, procStates);
1103         computeProcessData(totals, now);
1104         final double percentage = (double) totals.totalTime / (double) totalTime * 100;
1105         // We don't print percentages < .01, so just drop those.
1106         if (percentage >= 0.005 || totals.numPss != 0) {
1107             if (prefix != null) {
1108                 pw.print(prefix);
1109             }
1110             if (label != null) {
1111                 pw.print("  ");
1112                 pw.print(label);
1113                 pw.print(": ");
1114             }
1115             totals.print(pw, totalTime, full);
1116             if (prefix != null) {
1117                 pw.println();
1118             }
1119         }
1120     }
1121 
dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage, long totalTime, long now, boolean dumpAll)1122     void dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage,
1123             long totalTime, long now, boolean dumpAll) {
1124         if (dumpAll) {
1125             pw.print(prefix); pw.print("myID=");
1126                     pw.print(Integer.toHexString(System.identityHashCode(this)));
1127                     pw.print(" mCommonProcess=");
1128                     pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess)));
1129                     pw.print(" mPackage="); pw.println(mPackage);
1130             if (mMultiPackage) {
1131                 pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage);
1132             }
1133             if (this != mCommonProcess) {
1134                 pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName);
1135                         pw.print("/"); pw.print(mCommonProcess.mUid);
1136                         pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
1137             }
1138             if (mCommonSources != null) {
1139                 pw.print(prefix); pw.println("Aggregated Association Sources:");
1140                 AssociationState.dumpSources(
1141                         pw, prefix + "  ", prefix + "    ", prefix + "        ",
1142                         AssociationState.createSortedAssociations(now, totalTime, mCommonSources),
1143                         now, totalTime, reqPackage, true, dumpAll);
1144             }
1145         }
1146         if (mActive) {
1147             pw.print(prefix); pw.print("mActive="); pw.println(mActive);
1148         }
1149         if (mDead) {
1150             pw.print(prefix); pw.print("mDead="); pw.println(mDead);
1151         }
1152         if (mNumActiveServices != 0 || mNumStartedServices != 0) {
1153             pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices);
1154                     pw.print(" mNumStartedServices=");
1155                     pw.println(mNumStartedServices);
1156         }
1157     }
1158 
computeProcessData(ProcessStats.ProcessDataCollection data, long now)1159     public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) {
1160         data.totalTime = 0;
1161         data.numPss = data.minPss = data.avgPss = data.maxPss =
1162                 data.minUss = data.avgUss = data.maxUss =
1163                 data.minRss = data.avgRss = data.maxRss = 0;
1164         for (int is=0; is<data.screenStates.length; is++) {
1165             for (int im=0; im<data.memStates.length; im++) {
1166                 for (int ip=0; ip<data.procStates.length; ip++) {
1167                     int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
1168                             + data.procStates[ip];
1169                     data.totalTime += getDuration(bucket, now);
1170                     long samples = getPssSampleCount(bucket);
1171                     if (samples > 0) {
1172                         long minPss = getPssMinimum(bucket);
1173                         long avgPss = getPssAverage(bucket);
1174                         long maxPss = getPssMaximum(bucket);
1175                         long minUss = getPssUssMinimum(bucket);
1176                         long avgUss = getPssUssAverage(bucket);
1177                         long maxUss = getPssUssMaximum(bucket);
1178                         long minRss = getPssRssMinimum(bucket);
1179                         long avgRss = getPssRssAverage(bucket);
1180                         long maxRss = getPssRssMaximum(bucket);
1181                         if (data.numPss == 0) {
1182                             data.minPss = minPss;
1183                             data.avgPss = avgPss;
1184                             data.maxPss = maxPss;
1185                             data.minUss = minUss;
1186                             data.avgUss = avgUss;
1187                             data.maxUss = maxUss;
1188                             data.minRss = minRss;
1189                             data.avgRss = avgRss;
1190                             data.maxRss = maxRss;
1191                         } else {
1192                             if (minPss < data.minPss) {
1193                                 data.minPss = minPss;
1194                             }
1195                             data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
1196                                     + (avgPss*(double)samples)) / (data.numPss+samples) );
1197                             if (maxPss > data.maxPss) {
1198                                 data.maxPss = maxPss;
1199                             }
1200                             if (minUss < data.minUss) {
1201                                 data.minUss = minUss;
1202                             }
1203                             data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
1204                                     + (avgUss*(double)samples)) / (data.numPss+samples) );
1205                             if (maxUss > data.maxUss) {
1206                                 data.maxUss = maxUss;
1207                             }
1208                             if (minRss < data.minRss) {
1209                                 data.minRss = minRss;
1210                             }
1211                             data.avgRss = (long)( ((data.avgRss*(double)data.numPss)
1212                                     + (avgRss*(double)samples)) / (data.numPss+samples) );
1213                             if (maxRss > data.maxRss) {
1214                                 data.maxRss = maxRss;
1215                             }
1216                         }
1217                         data.numPss += samples;
1218                     }
1219                 }
1220             }
1221         }
1222     }
1223 
dumpCsv(PrintWriter pw, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)1224     public void dumpCsv(PrintWriter pw,
1225             boolean sepScreenStates, int[] screenStates, boolean sepMemStates,
1226             int[] memStates, boolean sepProcStates, int[] procStates, long now) {
1227         final int NSS = sepScreenStates ? screenStates.length : 1;
1228         final int NMS = sepMemStates ? memStates.length : 1;
1229         final int NPS = sepProcStates ? procStates.length : 1;
1230         for (int iss=0; iss<NSS; iss++) {
1231             for (int ims=0; ims<NMS; ims++) {
1232                 for (int ips=0; ips<NPS; ips++) {
1233                     final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
1234                     final int vsmem = sepMemStates ? memStates[ims] : 0;
1235                     final int vsproc = sepProcStates ? procStates[ips] : 0;
1236                     final int NSA = sepScreenStates ? 1 : screenStates.length;
1237                     final int NMA = sepMemStates ? 1 : memStates.length;
1238                     final int NPA = sepProcStates ? 1 : procStates.length;
1239                     long totalTime = 0;
1240                     for (int isa=0; isa<NSA; isa++) {
1241                         for (int ima=0; ima<NMA; ima++) {
1242                             for (int ipa=0; ipa<NPA; ipa++) {
1243                                 final int vascreen = sepScreenStates ? 0 : screenStates[isa];
1244                                 final int vamem = sepMemStates ? 0 : memStates[ima];
1245                                 final int vaproc = sepProcStates ? 0 : procStates[ipa];
1246                                 final int bucket = ((vsscreen + vascreen + vsmem + vamem)
1247                                         * STATE_COUNT) + vsproc + vaproc;
1248                                 totalTime += getDuration(bucket, now);
1249                             }
1250                         }
1251                     }
1252                     pw.print(DumpUtils.CSV_SEP);
1253                     pw.print(totalTime);
1254                 }
1255             }
1256         }
1257     }
1258 
dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers, String itemName, long now)1259     public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers,
1260             String itemName, long now) {
1261         pw.print("pkgproc,");
1262         pw.print(pkgName);
1263         pw.print(",");
1264         pw.print(uid);
1265         pw.print(",");
1266         pw.print(vers);
1267         pw.print(",");
1268         pw.print(DumpUtils.collapseString(pkgName, itemName));
1269         dumpAllStateCheckin(pw, now);
1270         pw.println();
1271         if (mPssTable.getKeyCount() > 0) {
1272             pw.print("pkgpss,");
1273             pw.print(pkgName);
1274             pw.print(",");
1275             pw.print(uid);
1276             pw.print(",");
1277             pw.print(vers);
1278             pw.print(",");
1279             pw.print(DumpUtils.collapseString(pkgName, itemName));
1280             dumpAllPssCheckin(pw);
1281             pw.println();
1282         }
1283         if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1284             pw.print("pkgrun,");
1285             pw.print(pkgName);
1286             pw.print(",");
1287             pw.print(uid);
1288             pw.print(",");
1289             pw.print(vers);
1290             pw.print(",");
1291             pw.print(DumpUtils.collapseString(pkgName, itemName));
1292             pw.print(",");
1293             pw.print(getTotalRunningDuration(now));
1294             pw.print(",");
1295             dumpPssSamplesCheckin(pw, mTotalRunningPss, 0);
1296             pw.println();
1297         }
1298         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1299             pw.print("pkgkills,");
1300             pw.print(pkgName);
1301             pw.print(",");
1302             pw.print(uid);
1303             pw.print(",");
1304             pw.print(vers);
1305             pw.print(",");
1306             pw.print(DumpUtils.collapseString(pkgName, itemName));
1307             pw.print(",");
1308             pw.print("0"); // was mNumExcessiveWake
1309             pw.print(",");
1310             pw.print(mNumExcessiveCpu);
1311             pw.print(",");
1312             pw.print(mNumCachedKill);
1313             pw.print(",");
1314             pw.print(mMinCachedKillPss);
1315             pw.print(":");
1316             pw.print(mAvgCachedKillPss);
1317             pw.print(":");
1318             pw.print(mMaxCachedKillPss);
1319             pw.println();
1320         }
1321     }
1322 
dumpProcCheckin(PrintWriter pw, String procName, int uid, long now)1323     public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) {
1324         if (mDurations.getKeyCount() > 0) {
1325             pw.print("proc,");
1326             pw.print(procName);
1327             pw.print(",");
1328             pw.print(uid);
1329             dumpAllStateCheckin(pw, now);
1330             pw.println();
1331         }
1332         if (mPssTable.getKeyCount() > 0) {
1333             pw.print("pss,");
1334             pw.print(procName);
1335             pw.print(",");
1336             pw.print(uid);
1337             dumpAllPssCheckin(pw);
1338             pw.println();
1339         }
1340         if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1341             pw.print("procrun,");
1342             pw.print(procName);
1343             pw.print(",");
1344             pw.print(uid);
1345             pw.print(",");
1346             pw.print(getTotalRunningDuration(now));
1347             pw.print(",");
1348             dumpPssSamplesCheckin(pw, mTotalRunningPss, 0);
1349             pw.println();
1350         }
1351         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1352             pw.print("kills,");
1353             pw.print(procName);
1354             pw.print(",");
1355             pw.print(uid);
1356             pw.print(",");
1357             pw.print("0"); // was mNumExcessiveWake
1358             pw.print(",");
1359             pw.print(mNumExcessiveCpu);
1360             pw.print(",");
1361             pw.print(mNumCachedKill);
1362             pw.print(",");
1363             pw.print(mMinCachedKillPss);
1364             pw.print(":");
1365             pw.print(mAvgCachedKillPss);
1366             pw.print(":");
1367             pw.print(mMaxCachedKillPss);
1368             pw.println();
1369         }
1370     }
1371 
dumpAllStateCheckin(PrintWriter pw, long now)1372     public void dumpAllStateCheckin(PrintWriter pw, long now) {
1373         boolean didCurState = false;
1374         for (int i=0; i<mDurations.getKeyCount(); i++) {
1375             final int key = mDurations.getKeyAt(i);
1376             final int type = SparseMappingTable.getIdFromKey(key);
1377             long time = mDurations.getValue(key);
1378             if (mCurCombinedState == type) {
1379                 didCurState = true;
1380                 time += now - mStartTime;
1381             }
1382             DumpUtils.printProcStateTagAndValue(pw, type, time);
1383         }
1384         if (!didCurState && mCurCombinedState != STATE_NOTHING) {
1385             DumpUtils.printProcStateTagAndValue(pw, mCurCombinedState, now - mStartTime);
1386         }
1387     }
1388 
dumpAllPssCheckin(PrintWriter pw)1389     public void dumpAllPssCheckin(PrintWriter pw) {
1390         final int N = mPssTable.getKeyCount();
1391         for (int i=0; i<N; i++) {
1392             final int key = mPssTable.getKeyAt(i);
1393             final int type = SparseMappingTable.getIdFromKey(key);
1394             pw.print(',');
1395             DumpUtils.printProcStateTag(pw, type);
1396             pw.print(':');
1397             dumpPssSamplesCheckin(pw, mPssTable.getArrayForKey(key),
1398                     SparseMappingTable.getIndexFromKey(key));
1399         }
1400     }
1401 
dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset)1402     public static void dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset) {
1403         pw.print(table[offset + PSS_SAMPLE_COUNT]);
1404         pw.print(':');
1405         pw.print(table[offset + PSS_MINIMUM]);
1406         pw.print(':');
1407         pw.print(table[offset + PSS_AVERAGE]);
1408         pw.print(':');
1409         pw.print(table[offset + PSS_MAXIMUM]);
1410         pw.print(':');
1411         pw.print(table[offset + PSS_USS_MINIMUM]);
1412         pw.print(':');
1413         pw.print(table[offset + PSS_USS_AVERAGE]);
1414         pw.print(':');
1415         pw.print(table[offset + PSS_USS_MAXIMUM]);
1416         pw.print(':');
1417         pw.print(table[offset + PSS_RSS_MINIMUM]);
1418         pw.print(':');
1419         pw.print(table[offset + PSS_RSS_AVERAGE]);
1420         pw.print(':');
1421         pw.print(table[offset + PSS_RSS_MAXIMUM]);
1422     }
1423 
1424     @Override
toString()1425     public String toString() {
1426         StringBuilder sb = new StringBuilder(128);
1427         sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
1428                 .append(" ").append(mName).append("/").append(mUid)
1429                 .append(" pkg=").append(mPackage);
1430         if (mMultiPackage) sb.append(" (multi)");
1431         if (mCommonProcess != this) sb.append(" (sub)");
1432         sb.append("}");
1433         return sb.toString();
1434     }
1435 
dumpDebug(ProtoOutputStream proto, long fieldId, String procName, int uid, long now)1436     public void dumpDebug(ProtoOutputStream proto, long fieldId,
1437             String procName, int uid, long now) {
1438         final long token = proto.start(fieldId);
1439         proto.write(ProcessStatsProto.PROCESS, procName);
1440         proto.write(ProcessStatsProto.UID, uid);
1441         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) {
1442             final long killToken = proto.start(ProcessStatsProto.KILL);
1443             proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu);
1444             proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill);
1445             ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS,
1446                     mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss);
1447             proto.end(killToken);
1448         }
1449 
1450         // Group proc stats by type (screen state + mem state + process state)
1451         SparseLongArray durationByState = new SparseLongArray();
1452         boolean didCurState = false;
1453         for (int i=0; i<mDurations.getKeyCount(); i++) {
1454             final int key = mDurations.getKeyAt(i);
1455             final int type = SparseMappingTable.getIdFromKey(key);
1456             long time = mDurations.getValue(key);
1457             if (mCurCombinedState == type) {
1458                 didCurState = true;
1459                 time += now - mStartTime;
1460             }
1461             durationByState.put(type, time);
1462         }
1463         if (!didCurState && mCurCombinedState != STATE_NOTHING) {
1464             durationByState.put(mCurCombinedState, now - mStartTime);
1465         }
1466 
1467         for (int i=0; i<mPssTable.getKeyCount(); i++) {
1468             final int key = mPssTable.getKeyAt(i);
1469             final int type = SparseMappingTable.getIdFromKey(key);
1470             if (durationByState.indexOfKey(type) < 0) {
1471                 // state without duration should not have stats!
1472                 continue;
1473             }
1474             final long stateToken = proto.start(ProcessStatsProto.STATES);
1475             DumpUtils.printProcStateTagProto(proto,
1476                     ProcessStatsStateProto.SCREEN_STATE,
1477                     ProcessStatsStateProto.MEMORY_STATE,
1478                     ProcessStatsStateProto.PROCESS_STATE,
1479                     type);
1480 
1481             long duration = durationByState.get(type);
1482             durationByState.delete(type); // remove the key since it is already being dumped.
1483             proto.write(ProcessStatsStateProto.DURATION_MS, duration);
1484 
1485             mPssTable.writeStatsToProtoForKey(proto, key);
1486 
1487             proto.end(stateToken);
1488         }
1489 
1490         for (int i = 0; i < durationByState.size(); i++) {
1491             final long stateToken = proto.start(ProcessStatsProto.STATES);
1492             DumpUtils.printProcStateTagProto(proto,
1493                     ProcessStatsStateProto.SCREEN_STATE,
1494                     ProcessStatsStateProto.MEMORY_STATE,
1495                     ProcessStatsStateProto.PROCESS_STATE,
1496                     durationByState.keyAt(i));
1497             proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.valueAt(i));
1498             proto.end(stateToken);
1499         }
1500 
1501         final long totalRunningDuration = getTotalRunningDuration(now);
1502         if (totalRunningDuration > 0) {
1503             final long stateToken = proto.start(ProcessStatsProto.TOTAL_RUNNING_STATE);
1504             proto.write(ProcessStatsStateProto.DURATION_MS, totalRunningDuration);
1505             if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1506                 PssTable.writeStatsToProto(proto, mTotalRunningPss, 0);
1507             }
1508             proto.end(stateToken);
1509         }
1510 
1511         proto.end(token);
1512     }
1513 
1514     /**
1515      * Assume the atom already includes a UID field, write the process name only if
1516      * it's different from the package name; and only write the suffix if possible.
1517      */
writeCompressedProcessName(final ProtoOutputStream proto, final long fieldId, final String procName, final String packageName, final boolean sharedUid)1518     static void writeCompressedProcessName(final ProtoOutputStream proto, final long fieldId,
1519             final String procName, final String packageName, final boolean sharedUid) {
1520         if (sharedUid) {
1521             // This UID has multiple packages running, write the full process name here
1522             proto.write(fieldId, procName);
1523             return;
1524         }
1525         if (TextUtils.equals(procName, packageName)) {
1526             // Same name, don't bother to write the process name here.
1527             return;
1528         }
1529         if (procName.startsWith(packageName)) {
1530             final int pkgLength = packageName.length();
1531             if (procName.charAt(pkgLength) == ':') {
1532                 // Only write the suffix starting with ':'
1533                 proto.write(fieldId, procName.substring(pkgLength));
1534                 return;
1535             }
1536         }
1537         // Write the full process name
1538         proto.write(fieldId, procName);
1539     }
1540 
1541     /** 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)1542     public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
1543             String procName, int uid, long now,
1544             final ProcessMap<ArraySet<PackageState>> procToPkgMap,
1545             final SparseArray<ArraySet<String>> uidToPkgMap) {
1546         // Group proc stats by aggregated type (only screen state + process state)
1547         SparseLongArray durationByState = new SparseLongArray();
1548         boolean didCurState = false;
1549         for (int i = 0; i < mDurations.getKeyCount(); i++) {
1550             final int key = mDurations.getKeyAt(i);
1551             final int type = SparseMappingTable.getIdFromKey(key);
1552             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type);
1553             if ((type % STATE_COUNT) == STATE_SERVICE_RESTARTING) {
1554                 // Skip restarting service state -- that is not actually a running process.
1555                 continue;
1556             }
1557 
1558             long time = mDurations.getValue(key);
1559             if (mCurCombinedState == type) {
1560                 didCurState = true;
1561                 time += now - mStartTime;
1562             }
1563             int index = durationByState.indexOfKey(aggregatedType);
1564             if (index >= 0) {
1565                 durationByState.put(aggregatedType, time + durationByState.valueAt(index));
1566             } else {
1567                 durationByState.put(aggregatedType, time);
1568             }
1569         }
1570         if (!didCurState && mCurCombinedState != STATE_NOTHING
1571                 && (mCurCombinedState % STATE_COUNT) != STATE_SERVICE_RESTARTING) {
1572             // Skip restarting service state -- that is not actually a running process.
1573             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(mCurCombinedState);
1574             int index = durationByState.indexOfKey(aggregatedType);
1575             if (index >= 0) {
1576                 durationByState.put(aggregatedType,
1577                         (now - mStartTime) + durationByState.valueAt(index));
1578             } else {
1579                 durationByState.put(aggregatedType, now - mStartTime);
1580             }
1581         }
1582 
1583         // Now we have total durations, aggregate the RSS values
1584         SparseLongArray meanRssByState = new SparseLongArray();
1585         SparseLongArray maxRssByState = new SparseLongArray();
1586         // compute weighted averages and max-of-max
1587         for (int i = 0; i < mPssTable.getKeyCount(); i++) {
1588             final int key = mPssTable.getKeyAt(i);
1589             final int type = SparseMappingTable.getIdFromKey(key);
1590             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type);
1591             if (durationByState.indexOfKey(aggregatedType) < 0) {
1592                 // state without duration should not have stats!
1593                 continue;
1594             }
1595 
1596             long[] rssMeanAndMax = mPssTable.getRssMeanAndMax(key);
1597 
1598             // compute mean * duration, then store sum of that in meanRssByState
1599             long meanTimesDuration = rssMeanAndMax[0] * mDurations.getValueForId((byte) type);
1600             if (meanRssByState.indexOfKey(aggregatedType) >= 0) {
1601                 meanRssByState.put(aggregatedType,
1602                         meanTimesDuration + meanRssByState.get(aggregatedType));
1603             } else {
1604                 meanRssByState.put(aggregatedType, meanTimesDuration);
1605             }
1606 
1607             // accumulate max-of-maxes in maxRssByState
1608             if (maxRssByState.indexOfKey(aggregatedType) >= 0
1609                     && maxRssByState.get(aggregatedType) < rssMeanAndMax[1]) {
1610                 maxRssByState.put(aggregatedType, rssMeanAndMax[1]);
1611             } else if (maxRssByState.indexOfKey(aggregatedType) < 0) {
1612                 maxRssByState.put(aggregatedType, rssMeanAndMax[1]);
1613             }
1614         }
1615 
1616         // divide the means by the durations to get the weighted mean-of-means
1617         for (int i = 0; i < durationByState.size(); i++) {
1618             int aggregatedKey = durationByState.keyAt(i);
1619             if (meanRssByState.indexOfKey(aggregatedKey) < 0) {
1620                 // these data structures should be consistent
1621                 continue;
1622             }
1623             final long duration = durationByState.get(aggregatedKey);
1624             meanRssByState.put(aggregatedKey,
1625                     duration > 0 ? (meanRssByState.get(aggregatedKey) / duration)
1626                             : meanRssByState.get(aggregatedKey));
1627         }
1628 
1629         // build the output
1630         final long token = proto.start(fieldId);
1631         writeCompressedProcessName(proto, ProcessStatsProto.PROCESS, procName, mPackage,
1632                 mMultiPackage || (uidToPkgMap.get(mUid).size() > 1));
1633         proto.write(ProcessStatsProto.UID, uid);
1634 
1635         for (int i = 0; i < durationByState.size(); i++) {
1636             final long stateToken = proto.start(ProcessStatsProto.STATES);
1637 
1638             final int aggregatedKey = durationByState.keyAt(i);
1639 
1640             DumpUtils.printAggregatedProcStateTagProto(proto,
1641                     ProcessStatsStateProto.SCREEN_STATE,
1642                     ProcessStatsStateProto.PROCESS_STATE_AGGREGATED,
1643                     aggregatedKey);
1644             proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.get(aggregatedKey));
1645 
1646             ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.RSS,
1647                     0, /* do not output a minimum value */
1648                     0, /* do not output an average value */
1649                     0, /* do not output a max value */
1650                     (int) meanRssByState.get(aggregatedKey),
1651                     (int) maxRssByState.get(aggregatedKey));
1652 
1653             proto.end(stateToken);
1654         }
1655 
1656         mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
1657                 now, this, uidToPkgMap);
1658         proto.end(token);
1659     }
1660 }
1661