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