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