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 
reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss)693     public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) {
694         ensureNotDead();
695         mCommonProcess.addCachedKill(1, pss, pss, pss);
696         if (!mCommonProcess.mMultiPackage) {
697             return;
698         }
699 
700         for (int ip=pkgList.size()-1; ip>=0; ip--) {
701             pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss);
702         }
703     }
704 
pullFixedProc(String pkgName)705     public ProcessState pullFixedProc(String pkgName) {
706         if (mMultiPackage) {
707             // The array map is still pointing to a common process state
708             // that is now shared across packages.  Update it to point to
709             // the new per-package state.
710             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
711             if (vpkg == null) {
712                 throw new IllegalStateException("Didn't find package " + pkgName
713                         + " / " + mUid);
714             }
715             PackageState pkg = vpkg.get(mVersion);
716             if (pkg == null) {
717                 throw new IllegalStateException("Didn't find package " + pkgName
718                         + " / " + mUid + " vers " + mVersion);
719             }
720             ProcessState proc = pkg.mProcesses.get(mName);
721             if (proc == null) {
722                 throw new IllegalStateException("Didn't create per-package process "
723                         + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion);
724             }
725             return proc;
726         }
727         return this;
728     }
729 
pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList, int index)730     private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList,
731             int index) {
732         ProcessStateHolder holder = pkgList.valueAt(index);
733         ProcessState proc = holder.state;
734         if (mDead && proc.mCommonProcess != proc) {
735             // Somehow we are continuing to use a process state that is dead, because
736             // it was not being told it was active during the last commit.  We can recover
737             // from this by generating a fresh new state, but this is bad because we
738             // are losing whatever data we had in the old process state.
739             Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage
740                     + " uid=" + mUid + " common.name=" + mCommonProcess.mName);
741             proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion,
742                     proc.mName);
743         }
744         if (proc.mMultiPackage) {
745             // The array map is still pointing to a common process state
746             // that is now shared across packages.  Update it to point to
747             // the new per-package state.
748             LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
749                     proc.mUid);
750             if (vpkg == null) {
751                 throw new IllegalStateException("No existing package "
752                         + pkgList.keyAt(index) + "/" + proc.mUid
753                         + " for multi-proc " + proc.mName);
754             }
755             PackageState expkg = vpkg.get(proc.mVersion);
756             if (expkg == null) {
757                 throw new IllegalStateException("No existing package "
758                         + pkgList.keyAt(index) + "/" + proc.mUid
759                         + " for multi-proc " + proc.mName + " version " + proc.mVersion);
760             }
761             String savedName = proc.mName;
762             proc = expkg.mProcesses.get(proc.mName);
763             if (proc == null) {
764                 throw new IllegalStateException("Didn't create per-package process "
765                         + savedName + " in pkg " + expkg.mPackageName + "/" + expkg.mUid);
766             }
767             holder.state = proc;
768         }
769         return proc;
770     }
771 
getTotalRunningDuration(long now)772     public long getTotalRunningDuration(long now) {
773         return mTotalRunningDuration +
774                 (mTotalRunningStartTime != 0 ? (now - mTotalRunningStartTime) : 0);
775     }
776 
getDuration(int state, long now)777     public long getDuration(int state, long now) {
778         long time = mDurations.getValueForId((byte)state);
779         if (mCurCombinedState == state) {
780             time += now - mStartTime;
781         }
782         return time;
783     }
784 
getPssSampleCount(int state)785     public long getPssSampleCount(int state) {
786         return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT);
787     }
788 
getPssMinimum(int state)789     public long getPssMinimum(int state) {
790         return mPssTable.getValueForId((byte)state, PSS_MINIMUM);
791     }
792 
getPssAverage(int state)793     public long getPssAverage(int state) {
794         return mPssTable.getValueForId((byte)state, PSS_AVERAGE);
795     }
796 
getPssMaximum(int state)797     public long getPssMaximum(int state) {
798         return mPssTable.getValueForId((byte)state, PSS_MAXIMUM);
799     }
800 
getPssUssMinimum(int state)801     public long getPssUssMinimum(int state) {
802         return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM);
803     }
804 
getPssUssAverage(int state)805     public long getPssUssAverage(int state) {
806         return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE);
807     }
808 
getPssUssMaximum(int state)809     public long getPssUssMaximum(int state) {
810         return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM);
811     }
812 
getPssRssMinimum(int state)813     public long getPssRssMinimum(int state) {
814         return mPssTable.getValueForId((byte)state, PSS_RSS_MINIMUM);
815     }
816 
getPssRssAverage(int state)817     public long getPssRssAverage(int state) {
818         return mPssTable.getValueForId((byte)state, PSS_RSS_AVERAGE);
819     }
820 
getPssRssMaximum(int state)821     public long getPssRssMaximum(int state) {
822         return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
823     }
824 
getOrCreateSourceState(SourceKey key)825     SourceState getOrCreateSourceState(SourceKey key) {
826         if (mCommonSources == null) {
827             mCommonSources = new ArrayMap<>();
828         }
829         SourceState state = mCommonSources.get(key);
830         if (state == null) {
831             state = new SourceState(mStats, null, this, key);
832             mCommonSources.put(key, state);
833         }
834         return state;
835     }
836 
837     /**
838      * Sums up the PSS data and adds it to 'data'.
839      *
840      * @param data The aggregate data is added here.
841      * @param now SystemClock.uptimeMillis()
842      */
aggregatePss(TotalMemoryUseCollection data, long now)843     public void aggregatePss(TotalMemoryUseCollection data, long now) {
844         final PssAggr fgPss = new PssAggr();
845         final PssAggr bgPss = new PssAggr();
846         final PssAggr cachedPss = new PssAggr();
847         boolean havePss = false;
848         for (int i=0; i<mDurations.getKeyCount(); i++) {
849             final int key = mDurations.getKeyAt(i);
850             int type = SparseMappingTable.getIdFromKey(key);
851             int procState = type % STATE_COUNT;
852             long samples = getPssSampleCount(type);
853             if (samples > 0) {
854                 long avg = getPssAverage(type);
855                 havePss = true;
856                 if (procState <= STATE_IMPORTANT_FOREGROUND) {
857                     fgPss.add(avg, samples);
858                 } else if (procState <= STATE_RECEIVER) {
859                     bgPss.add(avg, samples);
860                 } else {
861                     cachedPss.add(avg, samples);
862                 }
863             }
864         }
865         if (!havePss) {
866             return;
867         }
868         boolean fgHasBg = false;
869         boolean fgHasCached = false;
870         boolean bgHasCached = false;
871         if (fgPss.samples < 3 && bgPss.samples > 0) {
872             fgHasBg = true;
873             fgPss.add(bgPss.pss, bgPss.samples);
874         }
875         if (fgPss.samples < 3 && cachedPss.samples > 0) {
876             fgHasCached = true;
877             fgPss.add(cachedPss.pss, cachedPss.samples);
878         }
879         if (bgPss.samples < 3 && cachedPss.samples > 0) {
880             bgHasCached = true;
881             bgPss.add(cachedPss.pss, cachedPss.samples);
882         }
883         if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) {
884             bgPss.add(fgPss.pss, fgPss.samples);
885         }
886         if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) {
887             cachedPss.add(bgPss.pss, bgPss.samples);
888         }
889         if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) {
890             cachedPss.add(fgPss.pss, fgPss.samples);
891         }
892         for (int i=0; i<mDurations.getKeyCount(); i++) {
893             final int key = mDurations.getKeyAt(i);
894             final int type = SparseMappingTable.getIdFromKey(key);
895             long time = mDurations.getValue(key);
896             if (mCurCombinedState == type) {
897                 time += now - mStartTime;
898             }
899             final int procState = type % STATE_COUNT;
900             data.processStateTime[procState] += time;
901             long samples = getPssSampleCount(type);
902             long avg;
903             if (samples > 0) {
904                 avg = getPssAverage(type);
905             } else if (procState <= STATE_IMPORTANT_FOREGROUND) {
906                 samples = fgPss.samples;
907                 avg = fgPss.pss;
908             } else if (procState <= STATE_RECEIVER) {
909                 samples = bgPss.samples;
910                 avg = bgPss.pss;
911             } else {
912                 samples = cachedPss.samples;
913                 avg = cachedPss.pss;
914             }
915             double newAvg = ( (data.processStatePss[procState]
916                     * (double)data.processStateSamples[procState])
917                         + (avg*(double)samples)
918                     ) / (data.processStateSamples[procState]+samples);
919             data.processStatePss[procState] = (long)newAvg;
920             data.processStateSamples[procState] += samples;
921             data.processStateWeight[procState] += avg * (double)time;
922         }
923     }
924 
computeProcessTimeLocked(int[] screenStates, int[] memStates, int[] procStates, long now)925     public long computeProcessTimeLocked(int[] screenStates, int[] memStates,
926                 int[] procStates, long now) {
927         long totalTime = 0;
928         for (int is=0; is<screenStates.length; is++) {
929             for (int im=0; im<memStates.length; im++) {
930                 for (int ip=0; ip<procStates.length; ip++) {
931                     int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT)
932                             + procStates[ip];
933                     totalTime += getDuration(bucket, now);
934                 }
935             }
936         }
937         mTmpTotalTime = totalTime;
938         return totalTime;
939     }
940 
dumpSummary(PrintWriter pw, String prefix, String header, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)941     public void dumpSummary(PrintWriter pw, String prefix, String header,
942             int[] screenStates, int[] memStates, int[] procStates,
943             long now, long totalTime) {
944         pw.print(prefix);
945         pw.print("* ");
946         if (header != null) {
947             pw.print(header);
948         }
949         pw.print(mName);
950         pw.print(" / ");
951         UserHandle.formatUid(pw, mUid);
952         pw.print(" / v");
953         pw.print(mVersion);
954         pw.println(":");
955         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABEL_TOTAL,
956                 screenStates, memStates, procStates, now, totalTime, true);
957         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_PERSISTENT],
958                 screenStates, memStates, new int[] { STATE_PERSISTENT }, now, totalTime, true);
959         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_TOP],
960                 screenStates, memStates, new int[] {STATE_TOP}, now, totalTime, true);
961         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_TOP],
962                 screenStates, memStates, new int[] { STATE_BOUND_TOP }, now, totalTime,
963                 true);
964         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BOUND_FGS],
965                 screenStates, memStates, new int[] { STATE_BOUND_FGS }, now, totalTime,
966                 true);
967         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_FGS],
968                 screenStates, memStates, new int[] { STATE_FGS}, now, totalTime,
969                 true);
970         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_FOREGROUND],
971                 screenStates, memStates, new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime,
972                 true);
973         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_BACKGROUND],
974                 screenStates, memStates, new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime,
975                 true);
976         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BACKUP],
977                 screenStates, memStates, new int[] {STATE_BACKUP}, now, totalTime, true);
978         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE],
979                 screenStates, memStates, new int[] {STATE_SERVICE}, now, totalTime, true);
980         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE_RESTARTING],
981                 screenStates, memStates, new int[] {STATE_SERVICE_RESTARTING}, now, totalTime,
982                 true);
983         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_RECEIVER],
984                 screenStates, memStates, new int[] {STATE_RECEIVER}, now, totalTime, true);
985         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HEAVY_WEIGHT],
986                 screenStates, memStates, new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true);
987         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HOME],
988                 screenStates, memStates, new int[] {STATE_HOME}, now, totalTime, true);
989         dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_LAST_ACTIVITY],
990                 screenStates, memStates, new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true);
991     }
992 
dumpProcessState(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)993     public void dumpProcessState(PrintWriter pw, String prefix,
994             int[] screenStates, int[] memStates, int[] procStates, long now) {
995         long totalTime = 0;
996         int printedScreen = -1;
997         for (int is=0; is<screenStates.length; is++) {
998             int printedMem = -1;
999             for (int im=0; im<memStates.length; im++) {
1000                 for (int ip=0; ip<procStates.length; ip++) {
1001                     final int iscreen = screenStates[is];
1002                     final int imem = memStates[im];
1003                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
1004                     long time = mDurations.getValueForId((byte)bucket);
1005                     String running = "";
1006                     if (mCurCombinedState == bucket) {
1007                         running = " (running)";
1008                         time += now - mStartTime;
1009                     }
1010                     if (time != 0) {
1011                         pw.print(prefix);
1012                         if (screenStates.length > 1) {
1013                             DumpUtils.printScreenLabel(pw, printedScreen != iscreen
1014                                     ? iscreen : STATE_NOTHING);
1015                             printedScreen = iscreen;
1016                         }
1017                         if (memStates.length > 1) {
1018                             DumpUtils.printMemLabel(pw,
1019                                     printedMem != imem ? imem : STATE_NOTHING, '/');
1020                             printedMem = imem;
1021                         }
1022                         pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": ");
1023                         TimeUtils.formatDuration(time, pw); pw.println(running);
1024                         totalTime += time;
1025                     }
1026                 }
1027             }
1028         }
1029         if (totalTime != 0) {
1030             pw.print(prefix);
1031             if (screenStates.length > 1) {
1032                 DumpUtils.printScreenLabel(pw, STATE_NOTHING);
1033             }
1034             if (memStates.length > 1) {
1035                 DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
1036             }
1037             pw.print(DumpUtils.STATE_LABEL_TOTAL);
1038             pw.print(": ");
1039             TimeUtils.formatDuration(totalTime, pw);
1040             pw.println();
1041         }
1042     }
1043 
dumpPss(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)1044     public void dumpPss(PrintWriter pw, String prefix,
1045             int[] screenStates, int[] memStates, int[] procStates, long now) {
1046         boolean printedHeader = false;
1047         int printedScreen = -1;
1048         for (int is=0; is<screenStates.length; is++) {
1049             int printedMem = -1;
1050             for (int im=0; im<memStates.length; im++) {
1051                 for (int ip=0; ip<procStates.length; ip++) {
1052                     final int iscreen = screenStates[is];
1053                     final int imem = memStates[im];
1054                     final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
1055                     final int key = mPssTable.getKey((byte)bucket);
1056                     if (key == SparseMappingTable.INVALID_KEY) {
1057                         continue;
1058                     }
1059                     final long[] table = mPssTable.getArrayForKey(key);
1060                     final int tableOffset = SparseMappingTable.getIndexFromKey(key);
1061                     if (!printedHeader) {
1062                         pw.print(prefix);
1063                         pw.print("PSS/USS (");
1064                         pw.print(mPssTable.getKeyCount());
1065                         pw.println(" entries):");
1066                         printedHeader = true;
1067                     }
1068                     pw.print(prefix);
1069                     pw.print("  ");
1070                     if (screenStates.length > 1) {
1071                         DumpUtils.printScreenLabel(pw,
1072                                 printedScreen != iscreen ? iscreen : STATE_NOTHING);
1073                         printedScreen = iscreen;
1074                     }
1075                     if (memStates.length > 1) {
1076                         DumpUtils.printMemLabel(pw,
1077                                 printedMem != imem ? imem : STATE_NOTHING, '/');
1078                         printedMem = imem;
1079                     }
1080                     pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": ");
1081                     dumpPssSamples(pw, table, tableOffset);
1082                     pw.println();
1083                 }
1084             }
1085         }
1086         final long totalRunningDuration = getTotalRunningDuration(now);
1087         if (totalRunningDuration != 0) {
1088             pw.print(prefix);
1089             pw.print("Cur time ");
1090             TimeUtils.formatDuration(totalRunningDuration, pw);
1091             if (mTotalRunningStartTime != 0) {
1092                 pw.print(" (running)");
1093             }
1094             if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1095                 pw.print(": ");
1096                 dumpPssSamples(pw, mTotalRunningPss, 0);
1097             }
1098             pw.println();
1099         }
1100         if (mNumExcessiveCpu != 0) {
1101             pw.print(prefix); pw.print("Killed for excessive CPU use: ");
1102                     pw.print(mNumExcessiveCpu); pw.println(" times");
1103         }
1104         if (mNumCachedKill != 0) {
1105             pw.print(prefix); pw.print("Killed from cached state: ");
1106                     pw.print(mNumCachedKill); pw.print(" times from pss ");
1107                     DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-");
1108                     DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-");
1109                     DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println();
1110         }
1111     }
1112 
dumpPssSamples(PrintWriter pw, long[] table, int offset)1113     public static void dumpPssSamples(PrintWriter pw, long[] table, int offset) {
1114         DebugUtils.printSizeValue(pw, table[offset + PSS_MINIMUM] * 1024);
1115         pw.print("-");
1116         DebugUtils.printSizeValue(pw, table[offset + PSS_AVERAGE] * 1024);
1117         pw.print("-");
1118         DebugUtils.printSizeValue(pw, table[offset + PSS_MAXIMUM] * 1024);
1119         pw.print("/");
1120         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MINIMUM] * 1024);
1121         pw.print("-");
1122         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_AVERAGE] * 1024);
1123         pw.print("-");
1124         DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MAXIMUM] * 1024);
1125         pw.print("/");
1126         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MINIMUM] * 1024);
1127         pw.print("-");
1128         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_AVERAGE] * 1024);
1129         pw.print("-");
1130         DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MAXIMUM] * 1024);
1131         pw.print(" over ");
1132         pw.print(table[offset + PSS_SAMPLE_COUNT]);
1133     }
1134 
dumpProcessSummaryDetails(PrintWriter pw, String prefix, String label, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime, boolean full)1135     private void dumpProcessSummaryDetails(PrintWriter pw, String prefix,
1136             String label, int[] screenStates, int[] memStates, int[] procStates,
1137             long now, long totalTime, boolean full) {
1138         ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection(
1139                 screenStates, memStates, procStates);
1140         computeProcessData(totals, now);
1141         final double percentage = (double) totals.totalTime / (double) totalTime * 100;
1142         // We don't print percentages < .01, so just drop those.
1143         if (percentage >= 0.005 || totals.numPss != 0) {
1144             if (prefix != null) {
1145                 pw.print(prefix);
1146             }
1147             if (label != null) {
1148                 pw.print("  ");
1149                 pw.print(label);
1150                 pw.print(": ");
1151             }
1152             totals.print(pw, totalTime, full);
1153             if (prefix != null) {
1154                 pw.println();
1155             }
1156         }
1157     }
1158 
dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage, long totalTime, long now, boolean dumpAll)1159     void dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage,
1160             long totalTime, long now, boolean dumpAll) {
1161         if (dumpAll) {
1162             pw.print(prefix); pw.print("myID=");
1163                     pw.print(Integer.toHexString(System.identityHashCode(this)));
1164                     pw.print(" mCommonProcess=");
1165                     pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess)));
1166                     pw.print(" mPackage="); pw.println(mPackage);
1167             if (mMultiPackage) {
1168                 pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage);
1169             }
1170             if (this != mCommonProcess) {
1171                 pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName);
1172                         pw.print("/"); pw.print(mCommonProcess.mUid);
1173                         pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
1174             }
1175             if (mCommonSources != null) {
1176                 pw.print(prefix); pw.println("Aggregated Association Sources:");
1177                 AssociationState.dumpSources(
1178                         pw, prefix + "  ", prefix + "    ", prefix + "        ",
1179                         AssociationState.createSortedAssociations(now, totalTime, mCommonSources),
1180                         now, totalTime, reqPackage, true, dumpAll);
1181             }
1182         }
1183         if (mActive) {
1184             pw.print(prefix); pw.print("mActive="); pw.println(mActive);
1185         }
1186         if (mDead) {
1187             pw.print(prefix); pw.print("mDead="); pw.println(mDead);
1188         }
1189         if (mNumActiveServices != 0 || mNumStartedServices != 0) {
1190             pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices);
1191                     pw.print(" mNumStartedServices=");
1192                     pw.println(mNumStartedServices);
1193         }
1194     }
1195 
computeProcessData(ProcessStats.ProcessDataCollection data, long now)1196     public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) {
1197         data.totalTime = 0;
1198         data.numPss = data.minPss = data.avgPss = data.maxPss =
1199                 data.minUss = data.avgUss = data.maxUss =
1200                 data.minRss = data.avgRss = data.maxRss = 0;
1201         for (int is=0; is<data.screenStates.length; is++) {
1202             for (int im=0; im<data.memStates.length; im++) {
1203                 for (int ip=0; ip<data.procStates.length; ip++) {
1204                     int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT)
1205                             + data.procStates[ip];
1206                     data.totalTime += getDuration(bucket, now);
1207                     long samples = getPssSampleCount(bucket);
1208                     if (samples > 0) {
1209                         long minPss = getPssMinimum(bucket);
1210                         long avgPss = getPssAverage(bucket);
1211                         long maxPss = getPssMaximum(bucket);
1212                         long minUss = getPssUssMinimum(bucket);
1213                         long avgUss = getPssUssAverage(bucket);
1214                         long maxUss = getPssUssMaximum(bucket);
1215                         long minRss = getPssRssMinimum(bucket);
1216                         long avgRss = getPssRssAverage(bucket);
1217                         long maxRss = getPssRssMaximum(bucket);
1218                         if (data.numPss == 0) {
1219                             data.minPss = minPss;
1220                             data.avgPss = avgPss;
1221                             data.maxPss = maxPss;
1222                             data.minUss = minUss;
1223                             data.avgUss = avgUss;
1224                             data.maxUss = maxUss;
1225                             data.minRss = minRss;
1226                             data.avgRss = avgRss;
1227                             data.maxRss = maxRss;
1228                         } else {
1229                             if (minPss < data.minPss) {
1230                                 data.minPss = minPss;
1231                             }
1232                             data.avgPss = (long)( ((data.avgPss*(double)data.numPss)
1233                                     + (avgPss*(double)samples)) / (data.numPss+samples) );
1234                             if (maxPss > data.maxPss) {
1235                                 data.maxPss = maxPss;
1236                             }
1237                             if (minUss < data.minUss) {
1238                                 data.minUss = minUss;
1239                             }
1240                             data.avgUss = (long)( ((data.avgUss*(double)data.numPss)
1241                                     + (avgUss*(double)samples)) / (data.numPss+samples) );
1242                             if (maxUss > data.maxUss) {
1243                                 data.maxUss = maxUss;
1244                             }
1245                             if (minRss < data.minRss) {
1246                                 data.minRss = minRss;
1247                             }
1248                             data.avgRss = (long)( ((data.avgRss*(double)data.numPss)
1249                                     + (avgRss*(double)samples)) / (data.numPss+samples) );
1250                             if (maxRss > data.maxRss) {
1251                                 data.maxRss = maxRss;
1252                             }
1253                         }
1254                         data.numPss += samples;
1255                     }
1256                 }
1257             }
1258         }
1259     }
1260 
dumpCsv(PrintWriter pw, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)1261     public void dumpCsv(PrintWriter pw,
1262             boolean sepScreenStates, int[] screenStates, boolean sepMemStates,
1263             int[] memStates, boolean sepProcStates, int[] procStates, long now) {
1264         final int NSS = sepScreenStates ? screenStates.length : 1;
1265         final int NMS = sepMemStates ? memStates.length : 1;
1266         final int NPS = sepProcStates ? procStates.length : 1;
1267         for (int iss=0; iss<NSS; iss++) {
1268             for (int ims=0; ims<NMS; ims++) {
1269                 for (int ips=0; ips<NPS; ips++) {
1270                     final int vsscreen = sepScreenStates ? screenStates[iss] : 0;
1271                     final int vsmem = sepMemStates ? memStates[ims] : 0;
1272                     final int vsproc = sepProcStates ? procStates[ips] : 0;
1273                     final int NSA = sepScreenStates ? 1 : screenStates.length;
1274                     final int NMA = sepMemStates ? 1 : memStates.length;
1275                     final int NPA = sepProcStates ? 1 : procStates.length;
1276                     long totalTime = 0;
1277                     for (int isa=0; isa<NSA; isa++) {
1278                         for (int ima=0; ima<NMA; ima++) {
1279                             for (int ipa=0; ipa<NPA; ipa++) {
1280                                 final int vascreen = sepScreenStates ? 0 : screenStates[isa];
1281                                 final int vamem = sepMemStates ? 0 : memStates[ima];
1282                                 final int vaproc = sepProcStates ? 0 : procStates[ipa];
1283                                 final int bucket = ((vsscreen + vascreen + vsmem + vamem)
1284                                         * STATE_COUNT) + vsproc + vaproc;
1285                                 totalTime += getDuration(bucket, now);
1286                             }
1287                         }
1288                     }
1289                     pw.print(DumpUtils.CSV_SEP);
1290                     pw.print(totalTime);
1291                 }
1292             }
1293         }
1294     }
1295 
dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers, String itemName, long now)1296     public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers,
1297             String itemName, long now) {
1298         pw.print("pkgproc,");
1299         pw.print(pkgName);
1300         pw.print(",");
1301         pw.print(uid);
1302         pw.print(",");
1303         pw.print(vers);
1304         pw.print(",");
1305         pw.print(DumpUtils.collapseString(pkgName, itemName));
1306         dumpAllStateCheckin(pw, now);
1307         pw.println();
1308         if (mPssTable.getKeyCount() > 0) {
1309             pw.print("pkgpss,");
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             dumpAllPssCheckin(pw);
1318             pw.println();
1319         }
1320         if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1321             pw.print("pkgrun,");
1322             pw.print(pkgName);
1323             pw.print(",");
1324             pw.print(uid);
1325             pw.print(",");
1326             pw.print(vers);
1327             pw.print(",");
1328             pw.print(DumpUtils.collapseString(pkgName, itemName));
1329             pw.print(",");
1330             pw.print(getTotalRunningDuration(now));
1331             pw.print(",");
1332             dumpPssSamplesCheckin(pw, mTotalRunningPss, 0);
1333             pw.println();
1334         }
1335         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1336             pw.print("pkgkills,");
1337             pw.print(pkgName);
1338             pw.print(",");
1339             pw.print(uid);
1340             pw.print(",");
1341             pw.print(vers);
1342             pw.print(",");
1343             pw.print(DumpUtils.collapseString(pkgName, itemName));
1344             pw.print(",");
1345             pw.print("0"); // was mNumExcessiveWake
1346             pw.print(",");
1347             pw.print(mNumExcessiveCpu);
1348             pw.print(",");
1349             pw.print(mNumCachedKill);
1350             pw.print(",");
1351             pw.print(mMinCachedKillPss);
1352             pw.print(":");
1353             pw.print(mAvgCachedKillPss);
1354             pw.print(":");
1355             pw.print(mMaxCachedKillPss);
1356             pw.println();
1357         }
1358     }
1359 
dumpProcCheckin(PrintWriter pw, String procName, int uid, long now)1360     public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) {
1361         if (mDurations.getKeyCount() > 0) {
1362             pw.print("proc,");
1363             pw.print(procName);
1364             pw.print(",");
1365             pw.print(uid);
1366             dumpAllStateCheckin(pw, now);
1367             pw.println();
1368         }
1369         if (mPssTable.getKeyCount() > 0) {
1370             pw.print("pss,");
1371             pw.print(procName);
1372             pw.print(",");
1373             pw.print(uid);
1374             dumpAllPssCheckin(pw);
1375             pw.println();
1376         }
1377         if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1378             pw.print("procrun,");
1379             pw.print(procName);
1380             pw.print(",");
1381             pw.print(uid);
1382             pw.print(",");
1383             pw.print(getTotalRunningDuration(now));
1384             pw.print(",");
1385             dumpPssSamplesCheckin(pw, mTotalRunningPss, 0);
1386             pw.println();
1387         }
1388         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) {
1389             pw.print("kills,");
1390             pw.print(procName);
1391             pw.print(",");
1392             pw.print(uid);
1393             pw.print(",");
1394             pw.print("0"); // was mNumExcessiveWake
1395             pw.print(",");
1396             pw.print(mNumExcessiveCpu);
1397             pw.print(",");
1398             pw.print(mNumCachedKill);
1399             pw.print(",");
1400             pw.print(mMinCachedKillPss);
1401             pw.print(":");
1402             pw.print(mAvgCachedKillPss);
1403             pw.print(":");
1404             pw.print(mMaxCachedKillPss);
1405             pw.println();
1406         }
1407     }
1408 
dumpAllStateCheckin(PrintWriter pw, long now)1409     public void dumpAllStateCheckin(PrintWriter pw, long now) {
1410         boolean didCurState = false;
1411         for (int i=0; i<mDurations.getKeyCount(); i++) {
1412             final int key = mDurations.getKeyAt(i);
1413             final int type = SparseMappingTable.getIdFromKey(key);
1414             long time = mDurations.getValue(key);
1415             if (mCurCombinedState == type) {
1416                 didCurState = true;
1417                 time += now - mStartTime;
1418             }
1419             DumpUtils.printProcStateTagAndValue(pw, type, time);
1420         }
1421         if (!didCurState && mCurCombinedState != STATE_NOTHING) {
1422             DumpUtils.printProcStateTagAndValue(pw, mCurCombinedState, now - mStartTime);
1423         }
1424     }
1425 
dumpAllPssCheckin(PrintWriter pw)1426     public void dumpAllPssCheckin(PrintWriter pw) {
1427         final int N = mPssTable.getKeyCount();
1428         for (int i=0; i<N; i++) {
1429             final int key = mPssTable.getKeyAt(i);
1430             final int type = SparseMappingTable.getIdFromKey(key);
1431             pw.print(',');
1432             DumpUtils.printProcStateTag(pw, type);
1433             pw.print(':');
1434             dumpPssSamplesCheckin(pw, mPssTable.getArrayForKey(key),
1435                     SparseMappingTable.getIndexFromKey(key));
1436         }
1437     }
1438 
dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset)1439     public static void dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset) {
1440         pw.print(table[offset + PSS_SAMPLE_COUNT]);
1441         pw.print(':');
1442         pw.print(table[offset + PSS_MINIMUM]);
1443         pw.print(':');
1444         pw.print(table[offset + PSS_AVERAGE]);
1445         pw.print(':');
1446         pw.print(table[offset + PSS_MAXIMUM]);
1447         pw.print(':');
1448         pw.print(table[offset + PSS_USS_MINIMUM]);
1449         pw.print(':');
1450         pw.print(table[offset + PSS_USS_AVERAGE]);
1451         pw.print(':');
1452         pw.print(table[offset + PSS_USS_MAXIMUM]);
1453         pw.print(':');
1454         pw.print(table[offset + PSS_RSS_MINIMUM]);
1455         pw.print(':');
1456         pw.print(table[offset + PSS_RSS_AVERAGE]);
1457         pw.print(':');
1458         pw.print(table[offset + PSS_RSS_MAXIMUM]);
1459     }
1460 
1461     @Override
toString()1462     public String toString() {
1463         StringBuilder sb = new StringBuilder(128);
1464         sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this)))
1465                 .append(" ").append(mName).append("/").append(mUid)
1466                 .append(" pkg=").append(mPackage);
1467         if (mMultiPackage) sb.append(" (multi)");
1468         if (mCommonProcess != this) sb.append(" (sub)");
1469         sb.append("}");
1470         return sb.toString();
1471     }
1472 
dumpDebug(ProtoOutputStream proto, long fieldId, String procName, int uid, long now)1473     public void dumpDebug(ProtoOutputStream proto, long fieldId,
1474             String procName, int uid, long now) {
1475         final long token = proto.start(fieldId);
1476         proto.write(ProcessStatsProto.PROCESS, procName);
1477         proto.write(ProcessStatsProto.UID, uid);
1478         if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) {
1479             final long killToken = proto.start(ProcessStatsProto.KILL);
1480             proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu);
1481             proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill);
1482             ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS,
1483                     mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss);
1484             proto.end(killToken);
1485         }
1486 
1487         // Group proc stats by type (screen state + mem state + process state)
1488         SparseLongArray durationByState = new SparseLongArray();
1489         boolean didCurState = false;
1490         for (int i=0; i<mDurations.getKeyCount(); i++) {
1491             final int key = mDurations.getKeyAt(i);
1492             final int type = SparseMappingTable.getIdFromKey(key);
1493             long time = mDurations.getValue(key);
1494             if (mCurCombinedState == type) {
1495                 didCurState = true;
1496                 time += now - mStartTime;
1497             }
1498             durationByState.put(type, time);
1499         }
1500         if (!didCurState && mCurCombinedState != STATE_NOTHING) {
1501             durationByState.put(mCurCombinedState, now - mStartTime);
1502         }
1503 
1504         for (int i=0; i<mPssTable.getKeyCount(); i++) {
1505             final int key = mPssTable.getKeyAt(i);
1506             final int type = SparseMappingTable.getIdFromKey(key);
1507             if (durationByState.indexOfKey(type) < 0) {
1508                 // state without duration should not have stats!
1509                 continue;
1510             }
1511             final long stateToken = proto.start(ProcessStatsProto.STATES);
1512             DumpUtils.printProcStateTagProto(proto,
1513                     ProcessStatsStateProto.SCREEN_STATE,
1514                     ProcessStatsStateProto.MEMORY_STATE,
1515                     ProcessStatsStateProto.PROCESS_STATE,
1516                     type);
1517 
1518             long duration = durationByState.get(type);
1519             durationByState.delete(type); // remove the key since it is already being dumped.
1520             proto.write(ProcessStatsStateProto.DURATION_MS, duration);
1521 
1522             mPssTable.writeStatsToProtoForKey(proto, key);
1523 
1524             proto.end(stateToken);
1525         }
1526 
1527         for (int i = 0; i < durationByState.size(); i++) {
1528             final long stateToken = proto.start(ProcessStatsProto.STATES);
1529             DumpUtils.printProcStateTagProto(proto,
1530                     ProcessStatsStateProto.SCREEN_STATE,
1531                     ProcessStatsStateProto.MEMORY_STATE,
1532                     ProcessStatsStateProto.PROCESS_STATE,
1533                     durationByState.keyAt(i));
1534             proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.valueAt(i));
1535             proto.end(stateToken);
1536         }
1537 
1538         final long totalRunningDuration = getTotalRunningDuration(now);
1539         if (totalRunningDuration > 0) {
1540             final long stateToken = proto.start(ProcessStatsProto.TOTAL_RUNNING_STATE);
1541             proto.write(ProcessStatsStateProto.DURATION_MS, totalRunningDuration);
1542             if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) {
1543                 PssTable.writeStatsToProto(proto, mTotalRunningPss, 0);
1544             }
1545             proto.end(stateToken);
1546         }
1547 
1548         proto.end(token);
1549     }
1550 
1551     /**
1552      * Assume the atom already includes a UID field, write the process name only if
1553      * it's different from the package name; and only write the suffix if possible.
1554      */
writeCompressedProcessName(final ProtoOutputStream proto, final long fieldId, final String procName, final String packageName, final boolean sharedUid)1555     static void writeCompressedProcessName(final ProtoOutputStream proto, final long fieldId,
1556             final String procName, final String packageName, final boolean sharedUid) {
1557         if (sharedUid) {
1558             // This UID has multiple packages running, write the full process name here
1559             proto.write(fieldId, procName);
1560             return;
1561         }
1562         if (TextUtils.equals(procName, packageName)) {
1563             // Same name, don't bother to write the process name here.
1564             return;
1565         }
1566         if (procName.startsWith(packageName)) {
1567             final int pkgLength = packageName.length();
1568             if (procName.charAt(pkgLength) == ':') {
1569                 // Only write the suffix starting with ':'
1570                 proto.write(fieldId, procName.substring(pkgLength));
1571                 return;
1572             }
1573         }
1574         // Write the full process name
1575         proto.write(fieldId, procName);
1576     }
1577 
1578     /** Dumps the duration of each state to statsEventOutput. */
dumpStateDurationToStatsd( int atomTag, ProcessStats processStats, StatsEventOutput statsEventOutput)1579     public void dumpStateDurationToStatsd(
1580             int atomTag, ProcessStats processStats, StatsEventOutput statsEventOutput) {
1581         long topMs = 0;
1582         long fgsMs = 0;
1583         long boundTopMs = 0;
1584         long boundFgsMs = 0;
1585         long importantForegroundMs = 0;
1586         long cachedMs = 0;
1587         long frozenMs = 0;
1588         long otherMs = 0;
1589         for (int i = 0, size = mDurations.getKeyCount(); i < size; i++) {
1590             final int key = mDurations.getKeyAt(i);
1591             final int type = SparseMappingTable.getIdFromKey(key);
1592             int procStateIndex = type % STATE_COUNT;
1593             long duration = mDurations.getValue(key);
1594             switch (procStateIndex) {
1595                 case STATE_TOP:
1596                     topMs += duration;
1597                     break;
1598                 case STATE_BOUND_FGS:
1599                     boundFgsMs += duration;
1600                     break;
1601                 case STATE_BOUND_TOP:
1602                     boundTopMs += duration;
1603                     break;
1604                 case STATE_FGS:
1605                     fgsMs += duration;
1606                     break;
1607                 case STATE_IMPORTANT_FOREGROUND:
1608                 case STATE_IMPORTANT_BACKGROUND:
1609                     importantForegroundMs += duration;
1610                     break;
1611                 case STATE_BACKUP:
1612                 case STATE_SERVICE:
1613                 case STATE_SERVICE_RESTARTING:
1614                 case STATE_RECEIVER:
1615                 case STATE_HEAVY_WEIGHT:
1616                 case STATE_HOME:
1617                 case STATE_LAST_ACTIVITY:
1618                 case STATE_PERSISTENT:
1619                     otherMs += duration;
1620                     break;
1621                 case STATE_CACHED:
1622                     cachedMs += duration;
1623                     break;
1624                 case STATE_FROZEN:
1625                     frozenMs += duration;
1626                     break;
1627             }
1628         }
1629         statsEventOutput.write(
1630                 atomTag,
1631                 getUid(),
1632                 getName(),
1633                 (int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodStartUptime),
1634                 (int) TimeUnit.MILLISECONDS.toSeconds(processStats.mTimePeriodEndUptime),
1635                 (int)
1636                         TimeUnit.MILLISECONDS.toSeconds(
1637                                 processStats.mTimePeriodEndUptime
1638                                         - processStats.mTimePeriodStartUptime),
1639                 (int) TimeUnit.MILLISECONDS.toSeconds(topMs),
1640                 (int) TimeUnit.MILLISECONDS.toSeconds(fgsMs),
1641                 (int) TimeUnit.MILLISECONDS.toSeconds(boundTopMs),
1642                 (int) TimeUnit.MILLISECONDS.toSeconds(boundFgsMs),
1643                 (int) TimeUnit.MILLISECONDS.toSeconds(importantForegroundMs),
1644                 (int) TimeUnit.MILLISECONDS.toSeconds(cachedMs),
1645                 (int) TimeUnit.MILLISECONDS.toSeconds(frozenMs),
1646                 (int) TimeUnit.MILLISECONDS.toSeconds(otherMs));
1647     }
1648 
1649     /** 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)1650     public void dumpAggregatedProtoForStatsd(ProtoOutputStream proto, long fieldId,
1651             String procName, int uid, long now,
1652             final ProcessMap<ArraySet<PackageState>> procToPkgMap,
1653             final SparseArray<ArraySet<String>> uidToPkgMap) {
1654         // Group proc stats by aggregated type (only screen state + process state)
1655         SparseLongArray durationByState = new SparseLongArray();
1656         boolean didCurState = false;
1657         for (int i = 0; i < mDurations.getKeyCount(); i++) {
1658             final int key = mDurations.getKeyAt(i);
1659             final int type = SparseMappingTable.getIdFromKey(key);
1660             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type);
1661             if ((type % STATE_COUNT) == STATE_SERVICE_RESTARTING) {
1662                 // Skip restarting service state -- that is not actually a running process.
1663                 continue;
1664             }
1665 
1666             long time = mDurations.getValue(key);
1667             if (mCurCombinedState == type) {
1668                 didCurState = true;
1669                 time += now - mStartTime;
1670             }
1671             int index = durationByState.indexOfKey(aggregatedType);
1672             if (index >= 0) {
1673                 durationByState.put(aggregatedType, time + durationByState.valueAt(index));
1674             } else {
1675                 durationByState.put(aggregatedType, time);
1676             }
1677         }
1678         if (!didCurState && mCurCombinedState != STATE_NOTHING
1679                 && (mCurCombinedState % STATE_COUNT) != STATE_SERVICE_RESTARTING) {
1680             // Skip restarting service state -- that is not actually a running process.
1681             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(mCurCombinedState);
1682             int index = durationByState.indexOfKey(aggregatedType);
1683             if (index >= 0) {
1684                 durationByState.put(aggregatedType,
1685                         (now - mStartTime) + durationByState.valueAt(index));
1686             } else {
1687                 durationByState.put(aggregatedType, now - mStartTime);
1688             }
1689         }
1690 
1691         // Now we have total durations, aggregate the RSS values
1692         SparseLongArray meanRssByState = new SparseLongArray();
1693         SparseLongArray maxRssByState = new SparseLongArray();
1694         // compute weighted averages and max-of-max
1695         for (int i = 0; i < mPssTable.getKeyCount(); i++) {
1696             final int key = mPssTable.getKeyAt(i);
1697             final int type = SparseMappingTable.getIdFromKey(key);
1698             final int aggregatedType = DumpUtils.aggregateCurrentProcessState(type);
1699             if (durationByState.indexOfKey(aggregatedType) < 0) {
1700                 // state without duration should not have stats!
1701                 continue;
1702             }
1703 
1704             long[] rssMeanAndMax = mPssTable.getRssMeanAndMax(key);
1705 
1706             // compute mean * duration, then store sum of that in meanRssByState
1707             long meanTimesDuration = rssMeanAndMax[0] * mDurations.getValueForId((byte) type);
1708             if (meanRssByState.indexOfKey(aggregatedType) >= 0) {
1709                 meanRssByState.put(aggregatedType,
1710                         meanTimesDuration + meanRssByState.get(aggregatedType));
1711             } else {
1712                 meanRssByState.put(aggregatedType, meanTimesDuration);
1713             }
1714 
1715             // accumulate max-of-maxes in maxRssByState
1716             if (maxRssByState.indexOfKey(aggregatedType) >= 0
1717                     && maxRssByState.get(aggregatedType) < rssMeanAndMax[1]) {
1718                 maxRssByState.put(aggregatedType, rssMeanAndMax[1]);
1719             } else if (maxRssByState.indexOfKey(aggregatedType) < 0) {
1720                 maxRssByState.put(aggregatedType, rssMeanAndMax[1]);
1721             }
1722         }
1723 
1724         // divide the means by the durations to get the weighted mean-of-means
1725         for (int i = 0; i < durationByState.size(); i++) {
1726             int aggregatedKey = durationByState.keyAt(i);
1727             if (meanRssByState.indexOfKey(aggregatedKey) < 0) {
1728                 // these data structures should be consistent
1729                 continue;
1730             }
1731             final long duration = durationByState.get(aggregatedKey);
1732             meanRssByState.put(aggregatedKey,
1733                     duration > 0 ? (meanRssByState.get(aggregatedKey) / duration)
1734                             : meanRssByState.get(aggregatedKey));
1735         }
1736 
1737         // build the output
1738         final long token = proto.start(fieldId);
1739         writeCompressedProcessName(proto, ProcessStatsProto.PROCESS, procName, mPackage,
1740                 mMultiPackage || (uidToPkgMap.get(mUid).size() > 1));
1741         proto.write(ProcessStatsProto.UID, uid);
1742 
1743         for (int i = 0; i < durationByState.size(); i++) {
1744             final long stateToken = proto.start(ProcessStatsProto.STATES);
1745 
1746             final int aggregatedKey = durationByState.keyAt(i);
1747 
1748             DumpUtils.printAggregatedProcStateTagProto(proto,
1749                     ProcessStatsStateProto.SCREEN_STATE,
1750                     ProcessStatsStateProto.PROCESS_STATE_AGGREGATED,
1751                     aggregatedKey);
1752             proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.get(aggregatedKey));
1753 
1754             ProtoUtils.toAggStatsProto(proto, ProcessStatsStateProto.RSS,
1755                     0, /* do not output a minimum value */
1756                     0, /* do not output an average value */
1757                     0, /* do not output a max value */
1758                     (int) meanRssByState.get(aggregatedKey),
1759                     (int) maxRssByState.get(aggregatedKey));
1760 
1761             proto.end(stateToken);
1762         }
1763 
1764         mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
1765                 now, this, uidToPkgMap);
1766         proto.end(token);
1767     }
1768 }
1769