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