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