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