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