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 android.os.Parcel; 20 import android.os.SystemClock; 21 import android.os.UserHandle; 22 import android.service.procstats.ProcessStatsProto; 23 import android.service.procstats.ProcessStatsStateProto; 24 import android.util.ArrayMap; 25 import android.util.DebugUtils; 26 import android.util.Log; 27 import android.util.LongSparseArray; 28 import android.util.Slog; 29 import android.util.SparseLongArray; 30 import android.util.TimeUtils; 31 import android.util.proto.ProtoOutputStream; 32 import android.util.proto.ProtoUtils; 33 34 35 import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; 36 import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; 37 import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; 38 import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM; 39 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_AVERAGE; 40 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MAXIMUM; 41 import static com.android.internal.app.procstats.ProcessStats.PSS_RSS_MINIMUM; 42 import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT; 43 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE; 44 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM; 45 import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM; 46 import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP; 47 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY; 48 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT; 49 import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY; 50 import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT; 51 import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT; 52 import static com.android.internal.app.procstats.ProcessStats.STATE_HOME; 53 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND; 54 import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND; 55 import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY; 56 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING; 57 import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT; 58 import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER; 59 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE; 60 import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING; 61 import static com.android.internal.app.procstats.ProcessStats.STATE_TOP; 62 63 import com.android.internal.app.procstats.ProcessStats.PackageState; 64 import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder; 65 import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection; 66 67 import java.io.PrintWriter; 68 import java.util.Comparator; 69 70 public final class ProcessState { 71 private static final String TAG = "ProcessStats"; 72 private static final boolean DEBUG = false; 73 private static final boolean DEBUG_PARCEL = false; 74 75 // Map from process states to the states we track. 76 static final int[] PROCESS_STATE_TO_STATE = new int[] { 77 STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT 78 STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI 79 STATE_TOP, // ActivityManager.PROCESS_STATE_TOP 80 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION 81 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_TOP 82 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE 83 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE 84 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND 85 STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND 86 STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND 87 STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP 88 STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE 89 STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER 90 STATE_TOP, // ActivityManager.PROCESS_STATE_TOP_SLEEPING 91 STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT 92 STATE_HOME, // ActivityManager.PROCESS_STATE_HOME 93 STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY 94 STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY 95 STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT 96 STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_RECENT 97 STATE_CACHED_EMPTY, // ActivityManager.PROCESS_STATE_CACHED_EMPTY 98 }; 99 100 public static final Comparator<ProcessState> COMPARATOR = new Comparator<ProcessState>() { 101 @Override 102 public int compare(ProcessState lhs, ProcessState rhs) { 103 if (lhs.mTmpTotalTime < rhs.mTmpTotalTime) { 104 return -1; 105 } else if (lhs.mTmpTotalTime > rhs.mTmpTotalTime) { 106 return 1; 107 } 108 return 0; 109 } 110 }; 111 112 static class PssAggr { 113 long pss = 0; 114 long samples = 0; 115 add(long newPss, long newSamples)116 void add(long newPss, long newSamples) { 117 pss = (long)( (pss*(double)samples) + (newPss*(double)newSamples) ) 118 / (samples+newSamples); 119 samples += newSamples; 120 } 121 } 122 123 // Used by reset to count rather than storing extra maps. Be careful. 124 public int tmpNumInUse; 125 public ProcessState tmpFoundSubProc; 126 127 private final ProcessStats mStats; 128 private final String mName; 129 private final String mPackage; 130 private final int mUid; 131 private final long mVersion; 132 private final DurationsTable mDurations; 133 private final PssTable mPssTable; 134 private final long[] mTotalRunningPss = new long[ProcessStats.PSS_COUNT]; 135 136 private ProcessState mCommonProcess; 137 private int mCurCombinedState = STATE_NOTHING; 138 private long mStartTime; 139 140 private int mLastPssState = STATE_NOTHING; 141 private long mLastPssTime; 142 143 private long mTotalRunningStartTime; 144 private long mTotalRunningDuration; 145 146 private boolean mActive; 147 private int mNumActiveServices; 148 private int mNumStartedServices; 149 150 private int mNumExcessiveCpu; 151 152 private int mNumCachedKill; 153 private long mMinCachedKillPss; 154 private long mAvgCachedKillPss; 155 private long mMaxCachedKillPss; 156 157 private boolean mMultiPackage; 158 private boolean mDead; 159 160 // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful. 161 private long mTmpTotalTime; 162 163 /** 164 * Create a new top-level process state, for the initial case where there is only 165 * a single package running in a process. The initial state is not running. 166 */ ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name)167 public ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name) { 168 mStats = processStats; 169 mName = name; 170 mCommonProcess = this; 171 mPackage = pkg; 172 mUid = uid; 173 mVersion = vers; 174 mDurations = new DurationsTable(processStats.mTableData); 175 mPssTable = new PssTable(processStats.mTableData); 176 } 177 178 /** 179 * Create a new per-package process state for an existing top-level process 180 * state. The current running state of the top-level process is also copied, 181 * marked as started running at 'now'. 182 */ ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name, long now)183 public ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name, 184 long now) { 185 mStats = commonProcess.mStats; 186 mName = name; 187 mCommonProcess = commonProcess; 188 mPackage = pkg; 189 mUid = uid; 190 mVersion = vers; 191 mCurCombinedState = commonProcess.mCurCombinedState; 192 mStartTime = now; 193 if (mCurCombinedState != STATE_NOTHING) { 194 mTotalRunningStartTime = now; 195 } 196 mDurations = new DurationsTable(commonProcess.mStats.mTableData); 197 mPssTable = new PssTable(commonProcess.mStats.mTableData); 198 } 199 clone(long now)200 public ProcessState clone(long now) { 201 ProcessState pnew = new ProcessState(this, mPackage, mUid, mVersion, mName, now); 202 pnew.mDurations.addDurations(mDurations); 203 pnew.mPssTable.copyFrom(mPssTable, PSS_COUNT); 204 System.arraycopy(mTotalRunningPss, 0, pnew.mTotalRunningPss, 0, ProcessStats.PSS_COUNT); 205 pnew.mTotalRunningDuration = getTotalRunningDuration(now); 206 pnew.mNumExcessiveCpu = mNumExcessiveCpu; 207 pnew.mNumCachedKill = mNumCachedKill; 208 pnew.mMinCachedKillPss = mMinCachedKillPss; 209 pnew.mAvgCachedKillPss = mAvgCachedKillPss; 210 pnew.mMaxCachedKillPss = mMaxCachedKillPss; 211 pnew.mActive = mActive; 212 pnew.mNumActiveServices = mNumActiveServices; 213 pnew.mNumStartedServices = mNumStartedServices; 214 return pnew; 215 } 216 getName()217 public String getName() { 218 return mName; 219 } 220 getCommonProcess()221 public ProcessState getCommonProcess() { 222 return mCommonProcess; 223 } 224 225 /** 226 * Say that we are not part of a shared process, so mCommonProcess = this. 227 */ makeStandalone()228 public void makeStandalone() { 229 mCommonProcess = this; 230 } 231 getPackage()232 public String getPackage() { 233 return mPackage; 234 } 235 getUid()236 public int getUid() { 237 return mUid; 238 } 239 getVersion()240 public long getVersion() { 241 return mVersion; 242 } 243 isMultiPackage()244 public boolean isMultiPackage() { 245 return mMultiPackage; 246 } 247 setMultiPackage(boolean val)248 public void setMultiPackage(boolean val) { 249 mMultiPackage = val; 250 } 251 getDurationsBucketCount()252 public int getDurationsBucketCount() { 253 return mDurations.getKeyCount(); 254 } 255 add(ProcessState other)256 public void add(ProcessState other) { 257 mDurations.addDurations(other.mDurations); 258 mPssTable.mergeStats(other.mPssTable); 259 // Note that we don't touch mTotalRunningPss, because in current use 260 // 'other' is older stats that are being added in to these newer ones. 261 // So the newer ones keep track of the total running time, which is always 262 // the right thing over whatever was in older stats. 263 mNumExcessiveCpu += other.mNumExcessiveCpu; 264 if (other.mNumCachedKill > 0) { 265 addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss, 266 other.mAvgCachedKillPss, other.mMaxCachedKillPss); 267 } 268 } 269 resetSafely(long now)270 public void resetSafely(long now) { 271 mDurations.resetTable(); 272 mPssTable.resetTable(); 273 mStartTime = now; 274 mLastPssState = STATE_NOTHING; 275 mLastPssTime = 0; 276 mNumExcessiveCpu = 0; 277 mNumCachedKill = 0; 278 mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0; 279 } 280 makeDead()281 public void makeDead() { 282 mDead = true; 283 } 284 ensureNotDead()285 private void ensureNotDead() { 286 if (!mDead) { 287 return; 288 } 289 Slog.w(TAG, "ProcessState dead: name=" + mName 290 + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName); 291 } 292 writeToParcel(Parcel out, long now)293 public void writeToParcel(Parcel out, long now) { 294 out.writeInt(mMultiPackage ? 1 : 0); 295 mDurations.writeToParcel(out); 296 mPssTable.writeToParcel(out); 297 for (int i = 0; i < ProcessStats.PSS_COUNT; i++) { 298 out.writeLong(mTotalRunningPss[i]); 299 } 300 out.writeLong(getTotalRunningDuration(now)); 301 out.writeInt(0); // was mNumExcessiveWake 302 out.writeInt(mNumExcessiveCpu); 303 out.writeInt(mNumCachedKill); 304 if (mNumCachedKill > 0) { 305 out.writeLong(mMinCachedKillPss); 306 out.writeLong(mAvgCachedKillPss); 307 out.writeLong(mMaxCachedKillPss); 308 } 309 } 310 readFromParcel(Parcel in, boolean fully)311 public boolean readFromParcel(Parcel in, boolean fully) { 312 boolean multiPackage = in.readInt() != 0; 313 if (fully) { 314 mMultiPackage = multiPackage; 315 } 316 if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table..."); 317 if (!mDurations.readFromParcel(in)) { 318 return false; 319 } 320 if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table..."); 321 if (!mPssTable.readFromParcel(in)) { 322 return false; 323 } 324 for (int i = 0; i < ProcessStats.PSS_COUNT; i++) { 325 mTotalRunningPss[i] = in.readLong(); 326 } 327 mTotalRunningDuration = in.readLong(); 328 in.readInt(); // was mNumExcessiveWake 329 mNumExcessiveCpu = in.readInt(); 330 mNumCachedKill = in.readInt(); 331 if (mNumCachedKill > 0) { 332 mMinCachedKillPss = in.readLong(); 333 mAvgCachedKillPss = in.readLong(); 334 mMaxCachedKillPss = in.readLong(); 335 } else { 336 mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0; 337 } 338 return true; 339 } 340 makeActive()341 public void makeActive() { 342 ensureNotDead(); 343 mActive = true; 344 } 345 makeInactive()346 public void makeInactive() { 347 mActive = false; 348 } 349 isInUse()350 public boolean isInUse() { 351 return mActive || mNumActiveServices > 0 || mNumStartedServices > 0 352 || mCurCombinedState != STATE_NOTHING; 353 } 354 isActive()355 public boolean isActive() { 356 return mActive; 357 } 358 hasAnyData()359 public boolean hasAnyData() { 360 return !(mDurations.getKeyCount() == 0 361 && mCurCombinedState == STATE_NOTHING 362 && mPssTable.getKeyCount() == 0 363 && mTotalRunningPss[PSS_SAMPLE_COUNT] == 0); 364 } 365 366 /** 367 * Update the current state of the given list of processes. 368 * 369 * @param state Current ActivityManager.PROCESS_STATE_* 370 * @param memFactor Current mem factor constant. 371 * @param now Current time. 372 * @param pkgList Processes to update. 373 */ setState(int state, int memFactor, long now, ArrayMap<String, ProcessStateHolder> pkgList)374 public void setState(int state, int memFactor, long now, 375 ArrayMap<String, ProcessStateHolder> pkgList) { 376 if (state < 0) { 377 state = mNumStartedServices > 0 378 ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING; 379 } else { 380 state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT); 381 } 382 383 // First update the common process. 384 mCommonProcess.setCombinedState(state, now); 385 386 // If the common process is not multi-package, there is nothing else to do. 387 if (!mCommonProcess.mMultiPackage) { 388 return; 389 } 390 391 if (pkgList != null) { 392 for (int ip=pkgList.size()-1; ip>=0; ip--) { 393 pullFixedProc(pkgList, ip).setCombinedState(state, now); 394 } 395 } 396 } 397 setCombinedState(int state, long now)398 public void setCombinedState(int state, long now) { 399 ensureNotDead(); 400 if (!mDead && (mCurCombinedState != state)) { 401 //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state); 402 commitStateTime(now); 403 if (state == STATE_NOTHING) { 404 // We are transitioning to a no longer running state... stop counting run time. 405 mTotalRunningDuration += now - mTotalRunningStartTime; 406 mTotalRunningStartTime = 0; 407 } else if (mCurCombinedState == STATE_NOTHING) { 408 // We previously weren't running... now starting again, clear out total 409 // running info. 410 mTotalRunningDuration = 0; 411 mTotalRunningStartTime = now; 412 for (int i = ProcessStats.PSS_COUNT - 1; i >= 0; i--) { 413 mTotalRunningPss[i] = 0; 414 } 415 } 416 mCurCombinedState = state; 417 } 418 } 419 getCombinedState()420 public int getCombinedState() { 421 return mCurCombinedState; 422 } 423 commitStateTime(long now)424 public void commitStateTime(long now) { 425 if (mCurCombinedState != STATE_NOTHING) { 426 long dur = now - mStartTime; 427 if (dur > 0) { 428 mDurations.addDuration(mCurCombinedState, dur); 429 } 430 mTotalRunningDuration += now - mTotalRunningStartTime; 431 mTotalRunningStartTime = now; 432 } 433 mStartTime = now; 434 } 435 incActiveServices(String serviceName)436 public void incActiveServices(String serviceName) { 437 if (DEBUG && "".equals(mName)) { 438 RuntimeException here = new RuntimeException("here"); 439 here.fillInStackTrace(); 440 Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName 441 + " to " + (mNumActiveServices+1), here); 442 } 443 if (mCommonProcess != this) { 444 mCommonProcess.incActiveServices(serviceName); 445 } 446 mNumActiveServices++; 447 } 448 decActiveServices(String serviceName)449 public void decActiveServices(String serviceName) { 450 if (DEBUG && "".equals(mName)) { 451 RuntimeException here = new RuntimeException("here"); 452 here.fillInStackTrace(); 453 Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName 454 + " to " + (mNumActiveServices-1), here); 455 } 456 if (mCommonProcess != this) { 457 mCommonProcess.decActiveServices(serviceName); 458 } 459 mNumActiveServices--; 460 if (mNumActiveServices < 0) { 461 Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage 462 + " uid=" + mUid + " proc=" + mName + " service=" + serviceName); 463 mNumActiveServices = 0; 464 } 465 } 466 incStartedServices(int memFactor, long now, String serviceName)467 public void incStartedServices(int memFactor, long now, String serviceName) { 468 if (false) { 469 RuntimeException here = new RuntimeException("here"); 470 here.fillInStackTrace(); 471 Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName 472 + " to " + (mNumStartedServices+1), here); 473 } 474 if (mCommonProcess != this) { 475 mCommonProcess.incStartedServices(memFactor, now, serviceName); 476 } 477 mNumStartedServices++; 478 if (mNumStartedServices == 1 && mCurCombinedState == STATE_NOTHING) { 479 setCombinedState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now); 480 } 481 } 482 decStartedServices(int memFactor, long now, String serviceName)483 public void decStartedServices(int memFactor, long now, String serviceName) { 484 if (false) { 485 RuntimeException here = new RuntimeException("here"); 486 here.fillInStackTrace(); 487 Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName 488 + " to " + (mNumStartedServices-1), here); 489 } 490 if (mCommonProcess != this) { 491 mCommonProcess.decStartedServices(memFactor, now, serviceName); 492 } 493 mNumStartedServices--; 494 if (mNumStartedServices == 0 && (mCurCombinedState %STATE_COUNT) == STATE_SERVICE_RESTARTING) { 495 setCombinedState(STATE_NOTHING, now); 496 } else if (mNumStartedServices < 0) { 497 Slog.wtfStack(TAG, "Proc started services underrun: pkg=" 498 + mPackage + " uid=" + mUid + " name=" + mName); 499 mNumStartedServices = 0; 500 } 501 } 502 addPss(long pss, long uss, long rss, boolean always, int type, long duration, ArrayMap<String, ProcessStateHolder> pkgList)503 public void addPss(long pss, long uss, long rss, boolean always, int type, long duration, 504 ArrayMap<String, ProcessStateHolder> pkgList) { 505 ensureNotDead(); 506 switch (type) { 507 case ProcessStats.ADD_PSS_INTERNAL_SINGLE: 508 mStats.mInternalSinglePssCount++; 509 mStats.mInternalSinglePssTime += duration; 510 break; 511 case ProcessStats.ADD_PSS_INTERNAL_ALL_MEM: 512 mStats.mInternalAllMemPssCount++; 513 mStats.mInternalAllMemPssTime += duration; 514 break; 515 case ProcessStats.ADD_PSS_INTERNAL_ALL_POLL: 516 mStats.mInternalAllPollPssCount++; 517 mStats.mInternalAllPollPssTime += duration; 518 break; 519 case ProcessStats.ADD_PSS_EXTERNAL: 520 mStats.mExternalPssCount++; 521 mStats.mExternalPssTime += duration; 522 break; 523 case ProcessStats.ADD_PSS_EXTERNAL_SLOW: 524 mStats.mExternalSlowPssCount++; 525 mStats.mExternalSlowPssTime += duration; 526 break; 527 } 528 if (!always) { 529 if (mLastPssState == mCurCombinedState && SystemClock.uptimeMillis() 530 < (mLastPssTime+(30*1000))) { 531 return; 532 } 533 } 534 mLastPssState = mCurCombinedState; 535 mLastPssTime = SystemClock.uptimeMillis(); 536 if (mCurCombinedState != STATE_NOTHING) { 537 // First update the common process. 538 mCommonProcess.mPssTable.mergeStats(mCurCombinedState, 1, pss, pss, pss, uss, uss, uss, 539 rss, rss, rss); 540 PssTable.mergeStats(mCommonProcess.mTotalRunningPss, 0, 1, pss, pss, pss, uss, uss, uss, 541 rss, rss, rss); 542 543 // If the common process is not multi-package, there is nothing else to do. 544 if (!mCommonProcess.mMultiPackage) { 545 return; 546 } 547 548 if (pkgList != null) { 549 for (int ip=pkgList.size()-1; ip>=0; ip--) { 550 ProcessState fixedProc = pullFixedProc(pkgList, ip); 551 fixedProc.mPssTable.mergeStats(mCurCombinedState, 1, 552 pss, pss, pss, uss, uss, uss, rss, rss, rss); 553 PssTable.mergeStats(fixedProc.mTotalRunningPss, 0, 1, 554 pss, pss, pss, uss, uss, uss, rss, rss, rss); 555 } 556 } 557 } 558 } 559 reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList)560 public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) { 561 ensureNotDead(); 562 mCommonProcess.mNumExcessiveCpu++; 563 if (!mCommonProcess.mMultiPackage) { 564 return; 565 } 566 567 for (int ip=pkgList.size()-1; ip>=0; ip--) { 568 pullFixedProc(pkgList, ip).mNumExcessiveCpu++; 569 } 570 } 571 addCachedKill(int num, long minPss, long avgPss, long maxPss)572 private void addCachedKill(int num, long minPss, long avgPss, long maxPss) { 573 if (mNumCachedKill <= 0) { 574 mNumCachedKill = num; 575 mMinCachedKillPss = minPss; 576 mAvgCachedKillPss = avgPss; 577 mMaxCachedKillPss = maxPss; 578 } else { 579 if (minPss < mMinCachedKillPss) { 580 mMinCachedKillPss = minPss; 581 } 582 if (maxPss > mMaxCachedKillPss) { 583 mMaxCachedKillPss = maxPss; 584 } 585 mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss) 586 / (mNumCachedKill+num) ); 587 mNumCachedKill += num; 588 } 589 } 590 reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss)591 public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) { 592 ensureNotDead(); 593 mCommonProcess.addCachedKill(1, pss, pss, pss); 594 if (!mCommonProcess.mMultiPackage) { 595 return; 596 } 597 598 for (int ip=pkgList.size()-1; ip>=0; ip--) { 599 pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss); 600 } 601 } 602 pullFixedProc(String pkgName)603 public ProcessState pullFixedProc(String pkgName) { 604 if (mMultiPackage) { 605 // The array map is still pointing to a common process state 606 // that is now shared across packages. Update it to point to 607 // the new per-package state. 608 LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid); 609 if (vpkg == null) { 610 throw new IllegalStateException("Didn't find package " + pkgName 611 + " / " + mUid); 612 } 613 PackageState pkg = vpkg.get(mVersion); 614 if (pkg == null) { 615 throw new IllegalStateException("Didn't find package " + pkgName 616 + " / " + mUid + " vers " + mVersion); 617 } 618 ProcessState proc = pkg.mProcesses.get(mName); 619 if (proc == null) { 620 throw new IllegalStateException("Didn't create per-package process " 621 + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion); 622 } 623 return proc; 624 } 625 return this; 626 } 627 pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList, int index)628 private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList, 629 int index) { 630 ProcessStateHolder holder = pkgList.valueAt(index); 631 ProcessState proc = holder.state; 632 if (mDead && proc.mCommonProcess != proc) { 633 // Somehow we are continuing to use a process state that is dead, because 634 // it was not being told it was active during the last commit. We can recover 635 // from this by generating a fresh new state, but this is bad because we 636 // are losing whatever data we had in the old process state. 637 Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage 638 + " uid=" + mUid + " common.name=" + mCommonProcess.mName); 639 proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion, 640 proc.mName); 641 } 642 if (proc.mMultiPackage) { 643 // The array map is still pointing to a common process state 644 // that is now shared across packages. Update it to point to 645 // the new per-package state. 646 LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index), 647 proc.mUid); 648 if (vpkg == null) { 649 throw new IllegalStateException("No existing package " 650 + pkgList.keyAt(index) + "/" + proc.mUid 651 + " for multi-proc " + proc.mName); 652 } 653 PackageState expkg = vpkg.get(proc.mVersion); 654 if (expkg == null) { 655 throw new IllegalStateException("No existing package " 656 + pkgList.keyAt(index) + "/" + proc.mUid 657 + " for multi-proc " + proc.mName + " version " + proc.mVersion); 658 } 659 String savedName = proc.mName; 660 proc = expkg.mProcesses.get(proc.mName); 661 if (proc == null) { 662 throw new IllegalStateException("Didn't create per-package process " 663 + savedName + " in pkg " + expkg.mPackageName + "/" + expkg.mUid); 664 } 665 holder.state = proc; 666 } 667 return proc; 668 } 669 getTotalRunningDuration(long now)670 public long getTotalRunningDuration(long now) { 671 return mTotalRunningDuration + 672 (mTotalRunningStartTime != 0 ? (now - mTotalRunningStartTime) : 0); 673 } 674 getDuration(int state, long now)675 public long getDuration(int state, long now) { 676 long time = mDurations.getValueForId((byte)state); 677 if (mCurCombinedState == state) { 678 time += now - mStartTime; 679 } 680 return time; 681 } 682 getPssSampleCount(int state)683 public long getPssSampleCount(int state) { 684 return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT); 685 } 686 getPssMinimum(int state)687 public long getPssMinimum(int state) { 688 return mPssTable.getValueForId((byte)state, PSS_MINIMUM); 689 } 690 getPssAverage(int state)691 public long getPssAverage(int state) { 692 return mPssTable.getValueForId((byte)state, PSS_AVERAGE); 693 } 694 getPssMaximum(int state)695 public long getPssMaximum(int state) { 696 return mPssTable.getValueForId((byte)state, PSS_MAXIMUM); 697 } 698 getPssUssMinimum(int state)699 public long getPssUssMinimum(int state) { 700 return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM); 701 } 702 getPssUssAverage(int state)703 public long getPssUssAverage(int state) { 704 return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE); 705 } 706 getPssUssMaximum(int state)707 public long getPssUssMaximum(int state) { 708 return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM); 709 } 710 getPssRssMinimum(int state)711 public long getPssRssMinimum(int state) { 712 return mPssTable.getValueForId((byte)state, PSS_RSS_MINIMUM); 713 } 714 getPssRssAverage(int state)715 public long getPssRssAverage(int state) { 716 return mPssTable.getValueForId((byte)state, PSS_RSS_AVERAGE); 717 } 718 getPssRssMaximum(int state)719 public long getPssRssMaximum(int state) { 720 return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM); 721 } 722 723 /** 724 * Sums up the PSS data and adds it to 'data'. 725 * 726 * @param data The aggregate data is added here. 727 * @param now SystemClock.uptimeMillis() 728 */ aggregatePss(TotalMemoryUseCollection data, long now)729 public void aggregatePss(TotalMemoryUseCollection data, long now) { 730 final PssAggr fgPss = new PssAggr(); 731 final PssAggr bgPss = new PssAggr(); 732 final PssAggr cachedPss = new PssAggr(); 733 boolean havePss = false; 734 for (int i=0; i<mDurations.getKeyCount(); i++) { 735 final int key = mDurations.getKeyAt(i); 736 int type = SparseMappingTable.getIdFromKey(key); 737 int procState = type % STATE_COUNT; 738 long samples = getPssSampleCount(type); 739 if (samples > 0) { 740 long avg = getPssAverage(type); 741 havePss = true; 742 if (procState <= STATE_IMPORTANT_FOREGROUND) { 743 fgPss.add(avg, samples); 744 } else if (procState <= STATE_RECEIVER) { 745 bgPss.add(avg, samples); 746 } else { 747 cachedPss.add(avg, samples); 748 } 749 } 750 } 751 if (!havePss) { 752 return; 753 } 754 boolean fgHasBg = false; 755 boolean fgHasCached = false; 756 boolean bgHasCached = false; 757 if (fgPss.samples < 3 && bgPss.samples > 0) { 758 fgHasBg = true; 759 fgPss.add(bgPss.pss, bgPss.samples); 760 } 761 if (fgPss.samples < 3 && cachedPss.samples > 0) { 762 fgHasCached = true; 763 fgPss.add(cachedPss.pss, cachedPss.samples); 764 } 765 if (bgPss.samples < 3 && cachedPss.samples > 0) { 766 bgHasCached = true; 767 bgPss.add(cachedPss.pss, cachedPss.samples); 768 } 769 if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) { 770 bgPss.add(fgPss.pss, fgPss.samples); 771 } 772 if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) { 773 cachedPss.add(bgPss.pss, bgPss.samples); 774 } 775 if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) { 776 cachedPss.add(fgPss.pss, fgPss.samples); 777 } 778 for (int i=0; i<mDurations.getKeyCount(); i++) { 779 final int key = mDurations.getKeyAt(i); 780 final int type = SparseMappingTable.getIdFromKey(key); 781 long time = mDurations.getValue(key); 782 if (mCurCombinedState == type) { 783 time += now - mStartTime; 784 } 785 final int procState = type % STATE_COUNT; 786 data.processStateTime[procState] += time; 787 long samples = getPssSampleCount(type); 788 long avg; 789 if (samples > 0) { 790 avg = getPssAverage(type); 791 } else if (procState <= STATE_IMPORTANT_FOREGROUND) { 792 samples = fgPss.samples; 793 avg = fgPss.pss; 794 } else if (procState <= STATE_RECEIVER) { 795 samples = bgPss.samples; 796 avg = bgPss.pss; 797 } else { 798 samples = cachedPss.samples; 799 avg = cachedPss.pss; 800 } 801 double newAvg = ( (data.processStatePss[procState] 802 * (double)data.processStateSamples[procState]) 803 + (avg*(double)samples) 804 ) / (data.processStateSamples[procState]+samples); 805 data.processStatePss[procState] = (long)newAvg; 806 data.processStateSamples[procState] += samples; 807 data.processStateWeight[procState] += avg * (double)time; 808 } 809 } 810 computeProcessTimeLocked(int[] screenStates, int[] memStates, int[] procStates, long now)811 public long computeProcessTimeLocked(int[] screenStates, int[] memStates, 812 int[] procStates, long now) { 813 long totalTime = 0; 814 for (int is=0; is<screenStates.length; is++) { 815 for (int im=0; im<memStates.length; im++) { 816 for (int ip=0; ip<procStates.length; ip++) { 817 int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT) 818 + procStates[ip]; 819 totalTime += getDuration(bucket, now); 820 } 821 } 822 } 823 mTmpTotalTime = totalTime; 824 return totalTime; 825 } 826 dumpSummary(PrintWriter pw, String prefix, String header, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime)827 public void dumpSummary(PrintWriter pw, String prefix, String header, 828 int[] screenStates, int[] memStates, int[] procStates, 829 long now, long totalTime) { 830 pw.print(prefix); 831 pw.print("* "); 832 if (header != null) { 833 pw.print(header); 834 } 835 pw.print(mName); 836 pw.print(" / "); 837 UserHandle.formatUid(pw, mUid); 838 pw.print(" / v"); 839 pw.print(mVersion); 840 pw.println(":"); 841 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABEL_TOTAL, 842 screenStates, memStates, procStates, now, totalTime, true); 843 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_PERSISTENT], 844 screenStates, memStates, new int[] { STATE_PERSISTENT }, now, totalTime, true); 845 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_TOP], 846 screenStates, memStates, new int[] {STATE_TOP}, now, totalTime, true); 847 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_FOREGROUND], 848 screenStates, memStates, new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, 849 true); 850 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_IMPORTANT_BACKGROUND], 851 screenStates, memStates, new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, 852 true); 853 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_BACKUP], 854 screenStates, memStates, new int[] {STATE_BACKUP}, now, totalTime, true); 855 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE], 856 screenStates, memStates, new int[] {STATE_SERVICE}, now, totalTime, true); 857 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_SERVICE_RESTARTING], 858 screenStates, memStates, new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, 859 true); 860 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_RECEIVER], 861 screenStates, memStates, new int[] {STATE_RECEIVER}, now, totalTime, true); 862 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HEAVY_WEIGHT], 863 screenStates, memStates, new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true); 864 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_HOME], 865 screenStates, memStates, new int[] {STATE_HOME}, now, totalTime, true); 866 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABELS[STATE_LAST_ACTIVITY], 867 screenStates, memStates, new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true); 868 dumpProcessSummaryDetails(pw, prefix, DumpUtils.STATE_LABEL_CACHED, 869 screenStates, memStates, new int[] {STATE_CACHED_ACTIVITY, 870 STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY}, now, totalTime, true); 871 } 872 dumpProcessState(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)873 public void dumpProcessState(PrintWriter pw, String prefix, 874 int[] screenStates, int[] memStates, int[] procStates, long now) { 875 long totalTime = 0; 876 int printedScreen = -1; 877 for (int is=0; is<screenStates.length; is++) { 878 int printedMem = -1; 879 for (int im=0; im<memStates.length; im++) { 880 for (int ip=0; ip<procStates.length; ip++) { 881 final int iscreen = screenStates[is]; 882 final int imem = memStates[im]; 883 final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip]; 884 long time = mDurations.getValueForId((byte)bucket); 885 String running = ""; 886 if (mCurCombinedState == bucket) { 887 running = " (running)"; 888 time += now - mStartTime; 889 } 890 if (time != 0) { 891 pw.print(prefix); 892 if (screenStates.length > 1) { 893 DumpUtils.printScreenLabel(pw, printedScreen != iscreen 894 ? iscreen : STATE_NOTHING); 895 printedScreen = iscreen; 896 } 897 if (memStates.length > 1) { 898 DumpUtils.printMemLabel(pw, 899 printedMem != imem ? imem : STATE_NOTHING, '/'); 900 printedMem = imem; 901 } 902 pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": "); 903 TimeUtils.formatDuration(time, pw); pw.println(running); 904 totalTime += time; 905 } 906 } 907 } 908 } 909 if (totalTime != 0) { 910 pw.print(prefix); 911 if (screenStates.length > 1) { 912 DumpUtils.printScreenLabel(pw, STATE_NOTHING); 913 } 914 if (memStates.length > 1) { 915 DumpUtils.printMemLabel(pw, STATE_NOTHING, '/'); 916 } 917 pw.print(DumpUtils.STATE_LABEL_TOTAL); 918 pw.print(": "); 919 TimeUtils.formatDuration(totalTime, pw); 920 pw.println(); 921 } 922 } 923 dumpPss(PrintWriter pw, String prefix, int[] screenStates, int[] memStates, int[] procStates, long now)924 public void dumpPss(PrintWriter pw, String prefix, 925 int[] screenStates, int[] memStates, int[] procStates, long now) { 926 boolean printedHeader = false; 927 int printedScreen = -1; 928 for (int is=0; is<screenStates.length; is++) { 929 int printedMem = -1; 930 for (int im=0; im<memStates.length; im++) { 931 for (int ip=0; ip<procStates.length; ip++) { 932 final int iscreen = screenStates[is]; 933 final int imem = memStates[im]; 934 final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip]; 935 final int key = mPssTable.getKey((byte)bucket); 936 if (key == SparseMappingTable.INVALID_KEY) { 937 continue; 938 } 939 final long[] table = mPssTable.getArrayForKey(key); 940 final int tableOffset = SparseMappingTable.getIndexFromKey(key); 941 if (!printedHeader) { 942 pw.print(prefix); 943 pw.print("PSS/USS ("); 944 pw.print(mPssTable.getKeyCount()); 945 pw.println(" entries):"); 946 printedHeader = true; 947 } 948 pw.print(prefix); 949 pw.print(" "); 950 if (screenStates.length > 1) { 951 DumpUtils.printScreenLabel(pw, 952 printedScreen != iscreen ? iscreen : STATE_NOTHING); 953 printedScreen = iscreen; 954 } 955 if (memStates.length > 1) { 956 DumpUtils.printMemLabel(pw, 957 printedMem != imem ? imem : STATE_NOTHING, '/'); 958 printedMem = imem; 959 } 960 pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": "); 961 dumpPssSamples(pw, table, tableOffset); 962 pw.println(); 963 } 964 } 965 } 966 final long totalRunningDuration = getTotalRunningDuration(now); 967 if (totalRunningDuration != 0) { 968 pw.print(prefix); 969 pw.print("Cur time "); 970 TimeUtils.formatDuration(totalRunningDuration, pw); 971 if (mTotalRunningStartTime != 0) { 972 pw.print(" (running)"); 973 } 974 if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) { 975 pw.print(": "); 976 dumpPssSamples(pw, mTotalRunningPss, 0); 977 } 978 pw.println(); 979 } 980 if (mNumExcessiveCpu != 0) { 981 pw.print(prefix); pw.print("Killed for excessive CPU use: "); 982 pw.print(mNumExcessiveCpu); pw.println(" times"); 983 } 984 if (mNumCachedKill != 0) { 985 pw.print(prefix); pw.print("Killed from cached state: "); 986 pw.print(mNumCachedKill); pw.print(" times from pss "); 987 DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-"); 988 DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-"); 989 DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println(); 990 } 991 } 992 dumpPssSamples(PrintWriter pw, long[] table, int offset)993 public static void dumpPssSamples(PrintWriter pw, long[] table, int offset) { 994 DebugUtils.printSizeValue(pw, table[offset + PSS_MINIMUM] * 1024); 995 pw.print("-"); 996 DebugUtils.printSizeValue(pw, table[offset + PSS_AVERAGE] * 1024); 997 pw.print("-"); 998 DebugUtils.printSizeValue(pw, table[offset + PSS_MAXIMUM] * 1024); 999 pw.print("/"); 1000 DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MINIMUM] * 1024); 1001 pw.print("-"); 1002 DebugUtils.printSizeValue(pw, table[offset + PSS_USS_AVERAGE] * 1024); 1003 pw.print("-"); 1004 DebugUtils.printSizeValue(pw, table[offset + PSS_USS_MAXIMUM] * 1024); 1005 pw.print("/"); 1006 DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MINIMUM] * 1024); 1007 pw.print("-"); 1008 DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_AVERAGE] * 1024); 1009 pw.print("-"); 1010 DebugUtils.printSizeValue(pw, table[offset + PSS_RSS_MAXIMUM] * 1024); 1011 pw.print(" over "); 1012 pw.print(table[offset + PSS_SAMPLE_COUNT]); 1013 } 1014 dumpProcessSummaryDetails(PrintWriter pw, String prefix, String label, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime, boolean full)1015 private void dumpProcessSummaryDetails(PrintWriter pw, String prefix, 1016 String label, int[] screenStates, int[] memStates, int[] procStates, 1017 long now, long totalTime, boolean full) { 1018 ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection( 1019 screenStates, memStates, procStates); 1020 computeProcessData(totals, now); 1021 final double percentage = (double) totals.totalTime / (double) totalTime * 100; 1022 // We don't print percentages < .01, so just drop those. 1023 if (percentage >= 0.005 || totals.numPss != 0) { 1024 if (prefix != null) { 1025 pw.print(prefix); 1026 } 1027 if (label != null) { 1028 pw.print(" "); 1029 pw.print(label); 1030 pw.print(": "); 1031 } 1032 totals.print(pw, totalTime, full); 1033 if (prefix != null) { 1034 pw.println(); 1035 } 1036 } 1037 } 1038 dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll)1039 public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) { 1040 if (dumpAll) { 1041 pw.print(prefix); pw.print("myID="); 1042 pw.print(Integer.toHexString(System.identityHashCode(this))); 1043 pw.print(" mCommonProcess="); 1044 pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess))); 1045 pw.print(" mPackage="); pw.println(mPackage); 1046 if (mMultiPackage) { 1047 pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage); 1048 } 1049 if (this != mCommonProcess) { 1050 pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName); 1051 pw.print("/"); pw.print(mCommonProcess.mUid); 1052 pw.print(" pkg="); pw.println(mCommonProcess.mPackage); 1053 } 1054 } 1055 if (mActive) { 1056 pw.print(prefix); pw.print("mActive="); pw.println(mActive); 1057 } 1058 if (mDead) { 1059 pw.print(prefix); pw.print("mDead="); pw.println(mDead); 1060 } 1061 if (mNumActiveServices != 0 || mNumStartedServices != 0) { 1062 pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices); 1063 pw.print(" mNumStartedServices="); 1064 pw.println(mNumStartedServices); 1065 } 1066 } 1067 computeProcessData(ProcessStats.ProcessDataCollection data, long now)1068 public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) { 1069 data.totalTime = 0; 1070 data.numPss = data.minPss = data.avgPss = data.maxPss = 1071 data.minUss = data.avgUss = data.maxUss = 1072 data.minRss = data.avgRss = data.maxRss = 0; 1073 for (int is=0; is<data.screenStates.length; is++) { 1074 for (int im=0; im<data.memStates.length; im++) { 1075 for (int ip=0; ip<data.procStates.length; ip++) { 1076 int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT) 1077 + data.procStates[ip]; 1078 data.totalTime += getDuration(bucket, now); 1079 long samples = getPssSampleCount(bucket); 1080 if (samples > 0) { 1081 long minPss = getPssMinimum(bucket); 1082 long avgPss = getPssAverage(bucket); 1083 long maxPss = getPssMaximum(bucket); 1084 long minUss = getPssUssMinimum(bucket); 1085 long avgUss = getPssUssAverage(bucket); 1086 long maxUss = getPssUssMaximum(bucket); 1087 long minRss = getPssRssMinimum(bucket); 1088 long avgRss = getPssRssAverage(bucket); 1089 long maxRss = getPssRssMaximum(bucket); 1090 if (data.numPss == 0) { 1091 data.minPss = minPss; 1092 data.avgPss = avgPss; 1093 data.maxPss = maxPss; 1094 data.minUss = minUss; 1095 data.avgUss = avgUss; 1096 data.maxUss = maxUss; 1097 data.minRss = minRss; 1098 data.avgRss = avgRss; 1099 data.maxRss = maxRss; 1100 } else { 1101 if (minPss < data.minPss) { 1102 data.minPss = minPss; 1103 } 1104 data.avgPss = (long)( ((data.avgPss*(double)data.numPss) 1105 + (avgPss*(double)samples)) / (data.numPss+samples) ); 1106 if (maxPss > data.maxPss) { 1107 data.maxPss = maxPss; 1108 } 1109 if (minUss < data.minUss) { 1110 data.minUss = minUss; 1111 } 1112 data.avgUss = (long)( ((data.avgUss*(double)data.numPss) 1113 + (avgUss*(double)samples)) / (data.numPss+samples) ); 1114 if (maxUss > data.maxUss) { 1115 data.maxUss = maxUss; 1116 } 1117 if (minRss < data.minRss) { 1118 data.minRss = minRss; 1119 } 1120 data.avgRss = (long)( ((data.avgRss*(double)data.numPss) 1121 + (avgRss*(double)samples)) / (data.numPss+samples) ); 1122 if (maxRss > data.maxRss) { 1123 data.maxRss = maxRss; 1124 } 1125 } 1126 data.numPss += samples; 1127 } 1128 } 1129 } 1130 } 1131 } 1132 dumpCsv(PrintWriter pw, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now)1133 public void dumpCsv(PrintWriter pw, 1134 boolean sepScreenStates, int[] screenStates, boolean sepMemStates, 1135 int[] memStates, boolean sepProcStates, int[] procStates, long now) { 1136 final int NSS = sepScreenStates ? screenStates.length : 1; 1137 final int NMS = sepMemStates ? memStates.length : 1; 1138 final int NPS = sepProcStates ? procStates.length : 1; 1139 for (int iss=0; iss<NSS; iss++) { 1140 for (int ims=0; ims<NMS; ims++) { 1141 for (int ips=0; ips<NPS; ips++) { 1142 final int vsscreen = sepScreenStates ? screenStates[iss] : 0; 1143 final int vsmem = sepMemStates ? memStates[ims] : 0; 1144 final int vsproc = sepProcStates ? procStates[ips] : 0; 1145 final int NSA = sepScreenStates ? 1 : screenStates.length; 1146 final int NMA = sepMemStates ? 1 : memStates.length; 1147 final int NPA = sepProcStates ? 1 : procStates.length; 1148 long totalTime = 0; 1149 for (int isa=0; isa<NSA; isa++) { 1150 for (int ima=0; ima<NMA; ima++) { 1151 for (int ipa=0; ipa<NPA; ipa++) { 1152 final int vascreen = sepScreenStates ? 0 : screenStates[isa]; 1153 final int vamem = sepMemStates ? 0 : memStates[ima]; 1154 final int vaproc = sepProcStates ? 0 : procStates[ipa]; 1155 final int bucket = ((vsscreen + vascreen + vsmem + vamem) 1156 * STATE_COUNT) + vsproc + vaproc; 1157 totalTime += getDuration(bucket, now); 1158 } 1159 } 1160 } 1161 pw.print(DumpUtils.CSV_SEP); 1162 pw.print(totalTime); 1163 } 1164 } 1165 } 1166 } 1167 dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers, String itemName, long now)1168 public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers, 1169 String itemName, long now) { 1170 pw.print("pkgproc,"); 1171 pw.print(pkgName); 1172 pw.print(","); 1173 pw.print(uid); 1174 pw.print(","); 1175 pw.print(vers); 1176 pw.print(","); 1177 pw.print(DumpUtils.collapseString(pkgName, itemName)); 1178 dumpAllStateCheckin(pw, now); 1179 pw.println(); 1180 if (mPssTable.getKeyCount() > 0) { 1181 pw.print("pkgpss,"); 1182 pw.print(pkgName); 1183 pw.print(","); 1184 pw.print(uid); 1185 pw.print(","); 1186 pw.print(vers); 1187 pw.print(","); 1188 pw.print(DumpUtils.collapseString(pkgName, itemName)); 1189 dumpAllPssCheckin(pw); 1190 pw.println(); 1191 } 1192 if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) { 1193 pw.print("pkgrun,"); 1194 pw.print(pkgName); 1195 pw.print(","); 1196 pw.print(uid); 1197 pw.print(","); 1198 pw.print(vers); 1199 pw.print(","); 1200 pw.print(DumpUtils.collapseString(pkgName, itemName)); 1201 pw.print(","); 1202 pw.print(getTotalRunningDuration(now)); 1203 pw.print(","); 1204 dumpPssSamplesCheckin(pw, mTotalRunningPss, 0); 1205 pw.println(); 1206 } 1207 if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) { 1208 pw.print("pkgkills,"); 1209 pw.print(pkgName); 1210 pw.print(","); 1211 pw.print(uid); 1212 pw.print(","); 1213 pw.print(vers); 1214 pw.print(","); 1215 pw.print(DumpUtils.collapseString(pkgName, itemName)); 1216 pw.print(","); 1217 pw.print("0"); // was mNumExcessiveWake 1218 pw.print(","); 1219 pw.print(mNumExcessiveCpu); 1220 pw.print(","); 1221 pw.print(mNumCachedKill); 1222 pw.print(","); 1223 pw.print(mMinCachedKillPss); 1224 pw.print(":"); 1225 pw.print(mAvgCachedKillPss); 1226 pw.print(":"); 1227 pw.print(mMaxCachedKillPss); 1228 pw.println(); 1229 } 1230 } 1231 dumpProcCheckin(PrintWriter pw, String procName, int uid, long now)1232 public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) { 1233 if (mDurations.getKeyCount() > 0) { 1234 pw.print("proc,"); 1235 pw.print(procName); 1236 pw.print(","); 1237 pw.print(uid); 1238 dumpAllStateCheckin(pw, now); 1239 pw.println(); 1240 } 1241 if (mPssTable.getKeyCount() > 0) { 1242 pw.print("pss,"); 1243 pw.print(procName); 1244 pw.print(","); 1245 pw.print(uid); 1246 dumpAllPssCheckin(pw); 1247 pw.println(); 1248 } 1249 if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) { 1250 pw.print("procrun,"); 1251 pw.print(procName); 1252 pw.print(","); 1253 pw.print(uid); 1254 pw.print(","); 1255 pw.print(getTotalRunningDuration(now)); 1256 pw.print(","); 1257 dumpPssSamplesCheckin(pw, mTotalRunningPss, 0); 1258 pw.println(); 1259 } 1260 if (mNumExcessiveCpu > 0 || mNumCachedKill > 0) { 1261 pw.print("kills,"); 1262 pw.print(procName); 1263 pw.print(","); 1264 pw.print(uid); 1265 pw.print(","); 1266 pw.print("0"); // was mNumExcessiveWake 1267 pw.print(","); 1268 pw.print(mNumExcessiveCpu); 1269 pw.print(","); 1270 pw.print(mNumCachedKill); 1271 pw.print(","); 1272 pw.print(mMinCachedKillPss); 1273 pw.print(":"); 1274 pw.print(mAvgCachedKillPss); 1275 pw.print(":"); 1276 pw.print(mMaxCachedKillPss); 1277 pw.println(); 1278 } 1279 } 1280 dumpAllStateCheckin(PrintWriter pw, long now)1281 public void dumpAllStateCheckin(PrintWriter pw, long now) { 1282 boolean didCurState = false; 1283 for (int i=0; i<mDurations.getKeyCount(); i++) { 1284 final int key = mDurations.getKeyAt(i); 1285 final int type = SparseMappingTable.getIdFromKey(key); 1286 long time = mDurations.getValue(key); 1287 if (mCurCombinedState == type) { 1288 didCurState = true; 1289 time += now - mStartTime; 1290 } 1291 DumpUtils.printProcStateTagAndValue(pw, type, time); 1292 } 1293 if (!didCurState && mCurCombinedState != STATE_NOTHING) { 1294 DumpUtils.printProcStateTagAndValue(pw, mCurCombinedState, now - mStartTime); 1295 } 1296 } 1297 dumpAllPssCheckin(PrintWriter pw)1298 public void dumpAllPssCheckin(PrintWriter pw) { 1299 final int N = mPssTable.getKeyCount(); 1300 for (int i=0; i<N; i++) { 1301 final int key = mPssTable.getKeyAt(i); 1302 final int type = SparseMappingTable.getIdFromKey(key); 1303 pw.print(','); 1304 DumpUtils.printProcStateTag(pw, type); 1305 pw.print(':'); 1306 dumpPssSamplesCheckin(pw, mPssTable.getArrayForKey(key), 1307 SparseMappingTable.getIndexFromKey(key)); 1308 } 1309 } 1310 dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset)1311 public static void dumpPssSamplesCheckin(PrintWriter pw, long[] table, int offset) { 1312 pw.print(table[offset + PSS_SAMPLE_COUNT]); 1313 pw.print(':'); 1314 pw.print(table[offset + PSS_MINIMUM]); 1315 pw.print(':'); 1316 pw.print(table[offset + PSS_AVERAGE]); 1317 pw.print(':'); 1318 pw.print(table[offset + PSS_MAXIMUM]); 1319 pw.print(':'); 1320 pw.print(table[offset + PSS_USS_MINIMUM]); 1321 pw.print(':'); 1322 pw.print(table[offset + PSS_USS_AVERAGE]); 1323 pw.print(':'); 1324 pw.print(table[offset + PSS_USS_MAXIMUM]); 1325 pw.print(':'); 1326 pw.print(table[offset + PSS_RSS_MINIMUM]); 1327 pw.print(':'); 1328 pw.print(table[offset + PSS_RSS_AVERAGE]); 1329 pw.print(':'); 1330 pw.print(table[offset + PSS_RSS_MAXIMUM]); 1331 } 1332 1333 @Override toString()1334 public String toString() { 1335 StringBuilder sb = new StringBuilder(128); 1336 sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this))) 1337 .append(" ").append(mName).append("/").append(mUid) 1338 .append(" pkg=").append(mPackage); 1339 if (mMultiPackage) sb.append(" (multi)"); 1340 if (mCommonProcess != this) sb.append(" (sub)"); 1341 sb.append("}"); 1342 return sb.toString(); 1343 } 1344 writeToProto(ProtoOutputStream proto, long fieldId, String procName, int uid, long now)1345 public void writeToProto(ProtoOutputStream proto, long fieldId, 1346 String procName, int uid, long now) { 1347 final long token = proto.start(fieldId); 1348 proto.write(ProcessStatsProto.PROCESS, procName); 1349 proto.write(ProcessStatsProto.UID, uid); 1350 if (mNumExcessiveCpu > 0 || mNumCachedKill > 0 ) { 1351 final long killToken = proto.start(ProcessStatsProto.KILL); 1352 proto.write(ProcessStatsProto.Kill.CPU, mNumExcessiveCpu); 1353 proto.write(ProcessStatsProto.Kill.CACHED, mNumCachedKill); 1354 ProtoUtils.toAggStatsProto(proto, ProcessStatsProto.Kill.CACHED_PSS, 1355 mMinCachedKillPss, mAvgCachedKillPss, mMaxCachedKillPss); 1356 proto.end(killToken); 1357 } 1358 1359 // Group proc stats by type (screen state + mem state + process state) 1360 SparseLongArray durationByState = new SparseLongArray(); 1361 boolean didCurState = false; 1362 for (int i=0; i<mDurations.getKeyCount(); i++) { 1363 final int key = mDurations.getKeyAt(i); 1364 final int type = SparseMappingTable.getIdFromKey(key); 1365 long time = mDurations.getValue(key); 1366 if (mCurCombinedState == type) { 1367 didCurState = true; 1368 time += now - mStartTime; 1369 } 1370 durationByState.put(type, time); 1371 } 1372 if (!didCurState && mCurCombinedState != STATE_NOTHING) { 1373 durationByState.put(mCurCombinedState, now - mStartTime); 1374 } 1375 1376 for (int i=0; i<mPssTable.getKeyCount(); i++) { 1377 final int key = mPssTable.getKeyAt(i); 1378 final int type = SparseMappingTable.getIdFromKey(key); 1379 if (durationByState.indexOfKey(type) < 0) { 1380 // state without duration should not have stats! 1381 continue; 1382 } 1383 final long stateToken = proto.start(ProcessStatsProto.STATES); 1384 DumpUtils.printProcStateTagProto(proto, 1385 ProcessStatsStateProto.SCREEN_STATE, 1386 ProcessStatsStateProto.MEMORY_STATE, 1387 ProcessStatsStateProto.PROCESS_STATE, 1388 type); 1389 1390 long duration = durationByState.get(type); 1391 durationByState.delete(type); // remove the key since it is already being dumped. 1392 proto.write(ProcessStatsStateProto.DURATION_MS, duration); 1393 1394 mPssTable.writeStatsToProtoForKey(proto, key); 1395 1396 proto.end(stateToken); 1397 } 1398 1399 for (int i = 0; i < durationByState.size(); i++) { 1400 final long stateToken = proto.start(ProcessStatsProto.STATES); 1401 DumpUtils.printProcStateTagProto(proto, 1402 ProcessStatsStateProto.SCREEN_STATE, 1403 ProcessStatsStateProto.MEMORY_STATE, 1404 ProcessStatsStateProto.PROCESS_STATE, 1405 durationByState.keyAt(i)); 1406 proto.write(ProcessStatsStateProto.DURATION_MS, durationByState.valueAt(i)); 1407 proto.end(stateToken); 1408 } 1409 1410 final long totalRunningDuration = getTotalRunningDuration(now); 1411 if (totalRunningDuration > 0) { 1412 final long stateToken = proto.start(ProcessStatsProto.TOTAL_RUNNING_STATE); 1413 proto.write(ProcessStatsStateProto.DURATION_MS, totalRunningDuration); 1414 if (mTotalRunningPss[PSS_SAMPLE_COUNT] != 0) { 1415 PssTable.writeStatsToProto(proto, mTotalRunningPss, 0); 1416 } 1417 proto.end(stateToken); 1418 } 1419 1420 proto.end(token); 1421 } 1422 } 1423