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