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