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