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 17package com.android.internal.app.procstats; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.os.SystemClock; 22import android.os.SystemProperties; 23import android.os.UserHandle; 24import android.text.format.DateFormat; 25import android.util.ArrayMap; 26import android.util.ArraySet; 27import android.util.DebugUtils; 28import android.util.Log; 29import android.util.Slog; 30import android.util.SparseArray; 31import android.util.TimeUtils; 32 33import com.android.internal.app.procstats.ProcessStats; 34import com.android.internal.app.procstats.ProcessStats.PackageState; 35import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder; 36import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection; 37import static com.android.internal.app.procstats.ProcessStats.PSS_SAMPLE_COUNT; 38import static com.android.internal.app.procstats.ProcessStats.PSS_MINIMUM; 39import static com.android.internal.app.procstats.ProcessStats.PSS_AVERAGE; 40import static com.android.internal.app.procstats.ProcessStats.PSS_MAXIMUM; 41import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MINIMUM; 42import static com.android.internal.app.procstats.ProcessStats.PSS_USS_AVERAGE; 43import static com.android.internal.app.procstats.ProcessStats.PSS_USS_MAXIMUM; 44import static com.android.internal.app.procstats.ProcessStats.PSS_COUNT; 45import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING; 46import static com.android.internal.app.procstats.ProcessStats.STATE_PERSISTENT; 47import static com.android.internal.app.procstats.ProcessStats.STATE_TOP; 48import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_FOREGROUND; 49import static com.android.internal.app.procstats.ProcessStats.STATE_IMPORTANT_BACKGROUND; 50import static com.android.internal.app.procstats.ProcessStats.STATE_BACKUP; 51import static com.android.internal.app.procstats.ProcessStats.STATE_HEAVY_WEIGHT; 52import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE; 53import static com.android.internal.app.procstats.ProcessStats.STATE_SERVICE_RESTARTING; 54import static com.android.internal.app.procstats.ProcessStats.STATE_RECEIVER; 55import static com.android.internal.app.procstats.ProcessStats.STATE_HOME; 56import static com.android.internal.app.procstats.ProcessStats.STATE_LAST_ACTIVITY; 57import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY; 58import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_ACTIVITY_CLIENT; 59import static com.android.internal.app.procstats.ProcessStats.STATE_CACHED_EMPTY; 60import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT; 61 62import dalvik.system.VMRuntime; 63import libcore.util.EmptyArray; 64 65import java.io.IOException; 66import java.io.InputStream; 67import java.io.PrintWriter; 68import java.util.ArrayList; 69import java.util.Arrays; 70import java.util.Collections; 71import java.util.Comparator; 72import java.util.Objects; 73 74public final class ProcessState { 75 private static final String TAG = "ProcessStats"; 76 private static final boolean DEBUG = false; 77 private static final boolean DEBUG_PARCEL = false; 78 79 // Map from process states to the states we track. 80 private static final int[] PROCESS_STATE_TO_STATE = new int[] { 81 STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT 82 STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI 83 STATE_TOP, // ActivityManager.PROCESS_STATE_TOP 84 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE 85 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE 86 STATE_TOP, // ActivityManager.PROCESS_STATE_TOP_SLEEPING 87 STATE_IMPORTANT_FOREGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND 88 STATE_IMPORTANT_BACKGROUND, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND 89 STATE_BACKUP, // ActivityManager.PROCESS_STATE_BACKUP 90 STATE_HEAVY_WEIGHT, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT 91 STATE_SERVICE, // ActivityManager.PROCESS_STATE_SERVICE 92 STATE_RECEIVER, // ActivityManager.PROCESS_STATE_RECEIVER 93 STATE_HOME, // ActivityManager.PROCESS_STATE_HOME 94 STATE_LAST_ACTIVITY, // ActivityManager.PROCESS_STATE_LAST_ACTIVITY 95 STATE_CACHED_ACTIVITY, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY 96 STATE_CACHED_ACTIVITY_CLIENT, // ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT 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 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 int mVersion; 132 private final DurationsTable mDurations; 133 private final PssTable mPssTable; 134 135 private ProcessState mCommonProcess; 136 private int mCurState = STATE_NOTHING; 137 private long mStartTime; 138 139 private int mLastPssState = STATE_NOTHING; 140 private long mLastPssTime; 141 142 private boolean mActive; 143 private int mNumActiveServices; 144 private int mNumStartedServices; 145 146 private int mNumExcessiveWake; 147 private int mNumExcessiveCpu; 148 149 private int mNumCachedKill; 150 private long mMinCachedKillPss; 151 private long mAvgCachedKillPss; 152 private long mMaxCachedKillPss; 153 154 private boolean mMultiPackage; 155 private boolean mDead; 156 157 // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful. 158 private long mTmpTotalTime; 159 160 /** 161 * Create a new top-level process state, for the initial case where there is only 162 * a single package running in a process. The initial state is not running. 163 */ 164 public ProcessState(ProcessStats processStats, String pkg, int uid, int vers, String name) { 165 mStats = processStats; 166 mName = name; 167 mCommonProcess = this; 168 mPackage = pkg; 169 mUid = uid; 170 mVersion = vers; 171 mDurations = new DurationsTable(processStats.mTableData); 172 mPssTable = new PssTable(processStats.mTableData); 173 } 174 175 /** 176 * Create a new per-package process state for an existing top-level process 177 * state. The current running state of the top-level process is also copied, 178 * marked as started running at 'now'. 179 */ 180 public ProcessState(ProcessState commonProcess, String pkg, int uid, int vers, String name, 181 long now) { 182 mStats = commonProcess.mStats; 183 mName = name; 184 mCommonProcess = commonProcess; 185 mPackage = pkg; 186 mUid = uid; 187 mVersion = vers; 188 mCurState = commonProcess.mCurState; 189 mStartTime = now; 190 mDurations = new DurationsTable(commonProcess.mStats.mTableData); 191 mPssTable = new PssTable(commonProcess.mStats.mTableData); 192 } 193 194 public ProcessState clone(long now) { 195 ProcessState pnew = new ProcessState(this, mPackage, mUid, mVersion, mName, now); 196 pnew.mDurations.addDurations(mDurations); 197 pnew.mPssTable.copyFrom(mPssTable, PSS_COUNT); 198 pnew.mNumExcessiveWake = mNumExcessiveWake; 199 pnew.mNumExcessiveCpu = mNumExcessiveCpu; 200 pnew.mNumCachedKill = mNumCachedKill; 201 pnew.mMinCachedKillPss = mMinCachedKillPss; 202 pnew.mAvgCachedKillPss = mAvgCachedKillPss; 203 pnew.mMaxCachedKillPss = mMaxCachedKillPss; 204 pnew.mActive = mActive; 205 pnew.mNumActiveServices = mNumActiveServices; 206 pnew.mNumStartedServices = mNumStartedServices; 207 return pnew; 208 } 209 210 public String getName() { 211 return mName; 212 } 213 214 public ProcessState getCommonProcess() { 215 return mCommonProcess; 216 } 217 218 /** 219 * Say that we are not part of a shared process, so mCommonProcess = this. 220 */ 221 public void makeStandalone() { 222 mCommonProcess = this; 223 } 224 225 public String getPackage() { 226 return mPackage; 227 } 228 229 public int getUid() { 230 return mUid; 231 } 232 233 public int getVersion() { 234 return mVersion; 235 } 236 237 public boolean isMultiPackage() { 238 return mMultiPackage; 239 } 240 241 public void setMultiPackage(boolean val) { 242 mMultiPackage = val; 243 } 244 245 public int getDurationsBucketCount() { 246 return mDurations.getKeyCount(); 247 } 248 249 public void add(ProcessState other) { 250 mDurations.addDurations(other.mDurations); 251 mPssTable.mergeStats(other.mPssTable); 252 mNumExcessiveWake += other.mNumExcessiveWake; 253 mNumExcessiveCpu += other.mNumExcessiveCpu; 254 if (other.mNumCachedKill > 0) { 255 addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss, 256 other.mAvgCachedKillPss, other.mMaxCachedKillPss); 257 } 258 } 259 260 public void resetSafely(long now) { 261 mDurations.resetTable(); 262 mPssTable.resetTable(); 263 mStartTime = now; 264 mLastPssState = STATE_NOTHING; 265 mLastPssTime = 0; 266 mNumExcessiveWake = 0; 267 mNumExcessiveCpu = 0; 268 mNumCachedKill = 0; 269 mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0; 270 } 271 272 public void makeDead() { 273 mDead = true; 274 } 275 276 private void ensureNotDead() { 277 if (!mDead) { 278 return; 279 } 280 Slog.w(TAG, "ProcessState dead: name=" + mName 281 + " pkg=" + mPackage + " uid=" + mUid + " common.name=" + mCommonProcess.mName); 282 } 283 284 public void writeToParcel(Parcel out, long now) { 285 out.writeInt(mMultiPackage ? 1 : 0); 286 mDurations.writeToParcel(out); 287 mPssTable.writeToParcel(out); 288 out.writeInt(mNumExcessiveWake); 289 out.writeInt(mNumExcessiveCpu); 290 out.writeInt(mNumCachedKill); 291 if (mNumCachedKill > 0) { 292 out.writeLong(mMinCachedKillPss); 293 out.writeLong(mAvgCachedKillPss); 294 out.writeLong(mMaxCachedKillPss); 295 } 296 } 297 298 public boolean readFromParcel(Parcel in, boolean fully) { 299 boolean multiPackage = in.readInt() != 0; 300 if (fully) { 301 mMultiPackage = multiPackage; 302 } 303 if (DEBUG_PARCEL) Slog.d(TAG, "Reading durations table..."); 304 if (!mDurations.readFromParcel(in)) { 305 return false; 306 } 307 if (DEBUG_PARCEL) Slog.d(TAG, "Reading pss table..."); 308 if (!mPssTable.readFromParcel(in)) { 309 return false; 310 } 311 mNumExcessiveWake = in.readInt(); 312 mNumExcessiveCpu = in.readInt(); 313 mNumCachedKill = in.readInt(); 314 if (mNumCachedKill > 0) { 315 mMinCachedKillPss = in.readLong(); 316 mAvgCachedKillPss = in.readLong(); 317 mMaxCachedKillPss = in.readLong(); 318 } else { 319 mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0; 320 } 321 return true; 322 } 323 324 public void makeActive() { 325 ensureNotDead(); 326 mActive = true; 327 } 328 329 public void makeInactive() { 330 mActive = false; 331 } 332 333 public boolean isInUse() { 334 return mActive || mNumActiveServices > 0 || mNumStartedServices > 0 335 || mCurState != STATE_NOTHING; 336 } 337 338 public boolean isActive() { 339 return mActive; 340 } 341 342 public boolean hasAnyData() { 343 return !(mDurations.getKeyCount() == 0 344 && mCurState == STATE_NOTHING 345 && mPssTable.getKeyCount() == 0); 346 } 347 348 /** 349 * Update the current state of the given list of processes. 350 * 351 * @param state Current ActivityManager.PROCESS_STATE_* 352 * @param memFactor Current mem factor constant. 353 * @param now Current time. 354 * @param pkgList Processes to update. 355 */ 356 public void setState(int state, int memFactor, long now, 357 ArrayMap<String, ProcessStateHolder> pkgList) { 358 if (state < 0) { 359 state = mNumStartedServices > 0 360 ? (STATE_SERVICE_RESTARTING+(memFactor*STATE_COUNT)) : STATE_NOTHING; 361 } else { 362 state = PROCESS_STATE_TO_STATE[state] + (memFactor*STATE_COUNT); 363 } 364 365 // First update the common process. 366 mCommonProcess.setState(state, now); 367 368 // If the common process is not multi-package, there is nothing else to do. 369 if (!mCommonProcess.mMultiPackage) { 370 return; 371 } 372 373 if (pkgList != null) { 374 for (int ip=pkgList.size()-1; ip>=0; ip--) { 375 pullFixedProc(pkgList, ip).setState(state, now); 376 } 377 } 378 } 379 380 public void setState(int state, long now) { 381 ensureNotDead(); 382 if (mCurState != state) { 383 //Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state); 384 commitStateTime(now); 385 mCurState = state; 386 } 387 } 388 389 public void commitStateTime(long now) { 390 if (mCurState != STATE_NOTHING) { 391 long dur = now - mStartTime; 392 if (dur > 0) { 393 mDurations.addDuration(mCurState, dur); 394 } 395 } 396 mStartTime = now; 397 } 398 399 public void incActiveServices(String serviceName) { 400 if (DEBUG && "".equals(mName)) { 401 RuntimeException here = new RuntimeException("here"); 402 here.fillInStackTrace(); 403 Slog.d(TAG, "incActiveServices: " + this + " service=" + serviceName 404 + " to " + (mNumActiveServices+1), here); 405 } 406 if (mCommonProcess != this) { 407 mCommonProcess.incActiveServices(serviceName); 408 } 409 mNumActiveServices++; 410 } 411 412 public void decActiveServices(String serviceName) { 413 if (DEBUG && "".equals(mName)) { 414 RuntimeException here = new RuntimeException("here"); 415 here.fillInStackTrace(); 416 Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName 417 + " to " + (mNumActiveServices-1), here); 418 } 419 if (mCommonProcess != this) { 420 mCommonProcess.decActiveServices(serviceName); 421 } 422 mNumActiveServices--; 423 if (mNumActiveServices < 0) { 424 Slog.wtfStack(TAG, "Proc active services underrun: pkg=" + mPackage 425 + " uid=" + mUid + " proc=" + mName + " service=" + serviceName); 426 mNumActiveServices = 0; 427 } 428 } 429 430 public void incStartedServices(int memFactor, long now, String serviceName) { 431 if (false) { 432 RuntimeException here = new RuntimeException("here"); 433 here.fillInStackTrace(); 434 Slog.d(TAG, "incStartedServices: " + this + " service=" + serviceName 435 + " to " + (mNumStartedServices+1), here); 436 } 437 if (mCommonProcess != this) { 438 mCommonProcess.incStartedServices(memFactor, now, serviceName); 439 } 440 mNumStartedServices++; 441 if (mNumStartedServices == 1 && mCurState == STATE_NOTHING) { 442 setState(STATE_SERVICE_RESTARTING + (memFactor*STATE_COUNT), now); 443 } 444 } 445 446 public void decStartedServices(int memFactor, long now, String serviceName) { 447 if (false) { 448 RuntimeException here = new RuntimeException("here"); 449 here.fillInStackTrace(); 450 Slog.d(TAG, "decActiveServices: " + this + " service=" + serviceName 451 + " to " + (mNumStartedServices-1), here); 452 } 453 if (mCommonProcess != this) { 454 mCommonProcess.decStartedServices(memFactor, now, serviceName); 455 } 456 mNumStartedServices--; 457 if (mNumStartedServices == 0 && (mCurState%STATE_COUNT) == STATE_SERVICE_RESTARTING) { 458 setState(STATE_NOTHING, now); 459 } else if (mNumStartedServices < 0) { 460 Slog.wtfStack(TAG, "Proc started services underrun: pkg=" 461 + mPackage + " uid=" + mUid + " name=" + mName); 462 mNumStartedServices = 0; 463 } 464 } 465 466 public void addPss(long pss, long uss, boolean always, 467 ArrayMap<String, ProcessStateHolder> pkgList) { 468 ensureNotDead(); 469 if (!always) { 470 if (mLastPssState == mCurState && SystemClock.uptimeMillis() 471 < (mLastPssTime+(30*1000))) { 472 return; 473 } 474 } 475 mLastPssState = mCurState; 476 mLastPssTime = SystemClock.uptimeMillis(); 477 if (mCurState != STATE_NOTHING) { 478 // First update the common process. 479 mCommonProcess.mPssTable.mergeStats(mCurState, 1, pss, pss, pss, uss, uss, uss); 480 481 // If the common process is not multi-package, there is nothing else to do. 482 if (!mCommonProcess.mMultiPackage) { 483 return; 484 } 485 486 if (pkgList != null) { 487 for (int ip=pkgList.size()-1; ip>=0; ip--) { 488 pullFixedProc(pkgList, ip).mPssTable.mergeStats(mCurState, 1, 489 pss, pss, pss, uss, uss, uss); 490 } 491 } 492 } 493 } 494 495 public void reportExcessiveWake(ArrayMap<String, ProcessStateHolder> pkgList) { 496 ensureNotDead(); 497 mCommonProcess.mNumExcessiveWake++; 498 if (!mCommonProcess.mMultiPackage) { 499 return; 500 } 501 502 for (int ip=pkgList.size()-1; ip>=0; ip--) { 503 pullFixedProc(pkgList, ip).mNumExcessiveWake++; 504 } 505 } 506 507 public void reportExcessiveCpu(ArrayMap<String, ProcessStateHolder> pkgList) { 508 ensureNotDead(); 509 mCommonProcess.mNumExcessiveCpu++; 510 if (!mCommonProcess.mMultiPackage) { 511 return; 512 } 513 514 for (int ip=pkgList.size()-1; ip>=0; ip--) { 515 pullFixedProc(pkgList, ip).mNumExcessiveCpu++; 516 } 517 } 518 519 private void addCachedKill(int num, long minPss, long avgPss, long maxPss) { 520 if (mNumCachedKill <= 0) { 521 mNumCachedKill = num; 522 mMinCachedKillPss = minPss; 523 mAvgCachedKillPss = avgPss; 524 mMaxCachedKillPss = maxPss; 525 } else { 526 if (minPss < mMinCachedKillPss) { 527 mMinCachedKillPss = minPss; 528 } 529 if (maxPss > mMaxCachedKillPss) { 530 mMaxCachedKillPss = maxPss; 531 } 532 mAvgCachedKillPss = (long)( ((mAvgCachedKillPss*(double)mNumCachedKill) + avgPss) 533 / (mNumCachedKill+num) ); 534 mNumCachedKill += num; 535 } 536 } 537 538 public void reportCachedKill(ArrayMap<String, ProcessStateHolder> pkgList, long pss) { 539 ensureNotDead(); 540 mCommonProcess.addCachedKill(1, pss, pss, pss); 541 if (!mCommonProcess.mMultiPackage) { 542 return; 543 } 544 545 for (int ip=pkgList.size()-1; ip>=0; ip--) { 546 pullFixedProc(pkgList, ip).addCachedKill(1, pss, pss, pss); 547 } 548 } 549 550 public ProcessState pullFixedProc(String pkgName) { 551 if (mMultiPackage) { 552 // The array map is still pointing to a common process state 553 // that is now shared across packages. Update it to point to 554 // the new per-package state. 555 SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid); 556 if (vpkg == null) { 557 throw new IllegalStateException("Didn't find package " + pkgName 558 + " / " + mUid); 559 } 560 PackageState pkg = vpkg.get(mVersion); 561 if (pkg == null) { 562 throw new IllegalStateException("Didn't find package " + pkgName 563 + " / " + mUid + " vers " + mVersion); 564 } 565 ProcessState proc = pkg.mProcesses.get(mName); 566 if (proc == null) { 567 throw new IllegalStateException("Didn't create per-package process " 568 + mName + " in pkg " + pkgName + " / " + mUid + " vers " + mVersion); 569 } 570 return proc; 571 } 572 return this; 573 } 574 575 private ProcessState pullFixedProc(ArrayMap<String, ProcessStateHolder> pkgList, 576 int index) { 577 ProcessStateHolder holder = pkgList.valueAt(index); 578 ProcessState proc = holder.state; 579 if (mDead && proc.mCommonProcess != proc) { 580 // Somehow we are contining to use a process state that is dead, because 581 // it was not being told it was active during the last commit. We can recover 582 // from this by generating a fresh new state, but this is bad because we 583 // are losing whatever data we had in the old process state. 584 Log.wtf(TAG, "Pulling dead proc: name=" + mName + " pkg=" + mPackage 585 + " uid=" + mUid + " common.name=" + mCommonProcess.mName); 586 proc = mStats.getProcessStateLocked(proc.mPackage, proc.mUid, proc.mVersion, 587 proc.mName); 588 } 589 if (proc.mMultiPackage) { 590 // The array map is still pointing to a common process state 591 // that is now shared across packages. Update it to point to 592 // the new per-package state. 593 SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index), 594 proc.mUid); 595 if (vpkg == null) { 596 throw new IllegalStateException("No existing package " 597 + pkgList.keyAt(index) + "/" + proc.mUid 598 + " for multi-proc " + proc.mName); 599 } 600 PackageState pkg = vpkg.get(proc.mVersion); 601 if (pkg == null) { 602 throw new IllegalStateException("No existing package " 603 + pkgList.keyAt(index) + "/" + proc.mUid 604 + " for multi-proc " + proc.mName + " version " + proc.mVersion); 605 } 606 String savedName = proc.mName; 607 proc = pkg.mProcesses.get(proc.mName); 608 if (proc == null) { 609 throw new IllegalStateException("Didn't create per-package process " 610 + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid); 611 } 612 holder.state = proc; 613 } 614 return proc; 615 } 616 617 public long getDuration(int state, long now) { 618 long time = mDurations.getValueForId((byte)state); 619 if (mCurState == state) { 620 time += now - mStartTime; 621 } 622 return time; 623 } 624 625 public long getPssSampleCount(int state) { 626 return mPssTable.getValueForId((byte)state, PSS_SAMPLE_COUNT); 627 } 628 629 public long getPssMinimum(int state) { 630 return mPssTable.getValueForId((byte)state, PSS_MINIMUM); 631 } 632 633 public long getPssAverage(int state) { 634 return mPssTable.getValueForId((byte)state, PSS_AVERAGE); 635 } 636 637 public long getPssMaximum(int state) { 638 return mPssTable.getValueForId((byte)state, PSS_MAXIMUM); 639 } 640 641 public long getPssUssMinimum(int state) { 642 return mPssTable.getValueForId((byte)state, PSS_USS_MINIMUM); 643 } 644 645 public long getPssUssAverage(int state) { 646 return mPssTable.getValueForId((byte)state, PSS_USS_AVERAGE); 647 } 648 649 public long getPssUssMaximum(int state) { 650 return mPssTable.getValueForId((byte)state, PSS_USS_MAXIMUM); 651 } 652 653 /** 654 * Sums up the PSS data and adds it to 'data'. 655 * 656 * @param data The aggregate data is added here. 657 * @param now SystemClock.uptimeMillis() 658 */ 659 public void aggregatePss(TotalMemoryUseCollection data, long now) { 660 final PssAggr fgPss = new PssAggr(); 661 final PssAggr bgPss = new PssAggr(); 662 final PssAggr cachedPss = new PssAggr(); 663 boolean havePss = false; 664 for (int i=0; i<mDurations.getKeyCount(); i++) { 665 final int key = mDurations.getKeyAt(i); 666 int type = SparseMappingTable.getIdFromKey(key); 667 int procState = type % STATE_COUNT; 668 long samples = getPssSampleCount(type); 669 if (samples > 0) { 670 long avg = getPssAverage(type); 671 havePss = true; 672 if (procState <= STATE_IMPORTANT_FOREGROUND) { 673 fgPss.add(avg, samples); 674 } else if (procState <= STATE_RECEIVER) { 675 bgPss.add(avg, samples); 676 } else { 677 cachedPss.add(avg, samples); 678 } 679 } 680 } 681 if (!havePss) { 682 return; 683 } 684 boolean fgHasBg = false; 685 boolean fgHasCached = false; 686 boolean bgHasCached = false; 687 if (fgPss.samples < 3 && bgPss.samples > 0) { 688 fgHasBg = true; 689 fgPss.add(bgPss.pss, bgPss.samples); 690 } 691 if (fgPss.samples < 3 && cachedPss.samples > 0) { 692 fgHasCached = true; 693 fgPss.add(cachedPss.pss, cachedPss.samples); 694 } 695 if (bgPss.samples < 3 && cachedPss.samples > 0) { 696 bgHasCached = true; 697 bgPss.add(cachedPss.pss, cachedPss.samples); 698 } 699 if (bgPss.samples < 3 && !fgHasBg && fgPss.samples > 0) { 700 bgPss.add(fgPss.pss, fgPss.samples); 701 } 702 if (cachedPss.samples < 3 && !bgHasCached && bgPss.samples > 0) { 703 cachedPss.add(bgPss.pss, bgPss.samples); 704 } 705 if (cachedPss.samples < 3 && !fgHasCached && fgPss.samples > 0) { 706 cachedPss.add(fgPss.pss, fgPss.samples); 707 } 708 for (int i=0; i<mDurations.getKeyCount(); i++) { 709 final int key = mDurations.getKeyAt(i); 710 final int type = SparseMappingTable.getIdFromKey(key); 711 long time = mDurations.getValue(key); 712 if (mCurState == type) { 713 time += now - mStartTime; 714 } 715 final int procState = type % STATE_COUNT; 716 data.processStateTime[procState] += time; 717 long samples = getPssSampleCount(type); 718 long avg; 719 if (samples > 0) { 720 avg = getPssAverage(type); 721 } else if (procState <= STATE_IMPORTANT_FOREGROUND) { 722 samples = fgPss.samples; 723 avg = fgPss.pss; 724 } else if (procState <= STATE_RECEIVER) { 725 samples = bgPss.samples; 726 avg = bgPss.pss; 727 } else { 728 samples = cachedPss.samples; 729 avg = cachedPss.pss; 730 } 731 double newAvg = ( (data.processStatePss[procState] 732 * (double)data.processStateSamples[procState]) 733 + (avg*(double)samples) 734 ) / (data.processStateSamples[procState]+samples); 735 data.processStatePss[procState] = (long)newAvg; 736 data.processStateSamples[procState] += samples; 737 data.processStateWeight[procState] += avg * (double)time; 738 } 739 } 740 741 public long computeProcessTimeLocked(int[] screenStates, int[] memStates, 742 int[] procStates, long now) { 743 long totalTime = 0; 744 for (int is=0; is<screenStates.length; is++) { 745 for (int im=0; im<memStates.length; im++) { 746 for (int ip=0; ip<procStates.length; ip++) { 747 int bucket = ((screenStates[is] + memStates[im]) * STATE_COUNT) 748 + procStates[ip]; 749 totalTime += getDuration(bucket, now); 750 } 751 } 752 } 753 mTmpTotalTime = totalTime; 754 return totalTime; 755 } 756 757 public void dumpSummary(PrintWriter pw, String prefix, 758 int[] screenStates, int[] memStates, int[] procStates, 759 long now, long totalTime) { 760 pw.print(prefix); 761 pw.print("* "); 762 pw.print(mName); 763 pw.print(" / "); 764 UserHandle.formatUid(pw, mUid); 765 pw.print(" / v"); 766 pw.print(mVersion); 767 pw.println(":"); 768 dumpProcessSummaryDetails(pw, prefix, " TOTAL: ", screenStates, memStates, 769 procStates, now, totalTime, true); 770 dumpProcessSummaryDetails(pw, prefix, " Persistent: ", screenStates, memStates, 771 new int[] { STATE_PERSISTENT }, now, totalTime, true); 772 dumpProcessSummaryDetails(pw, prefix, " Top: ", screenStates, memStates, 773 new int[] {STATE_TOP}, now, totalTime, true); 774 dumpProcessSummaryDetails(pw, prefix, " Imp Fg: ", screenStates, memStates, 775 new int[] { STATE_IMPORTANT_FOREGROUND }, now, totalTime, true); 776 dumpProcessSummaryDetails(pw, prefix, " Imp Bg: ", screenStates, memStates, 777 new int[] {STATE_IMPORTANT_BACKGROUND}, now, totalTime, true); 778 dumpProcessSummaryDetails(pw, prefix, " Backup: ", screenStates, memStates, 779 new int[] {STATE_BACKUP}, now, totalTime, true); 780 dumpProcessSummaryDetails(pw, prefix, " Heavy Wgt: ", screenStates, memStates, 781 new int[] {STATE_HEAVY_WEIGHT}, now, totalTime, true); 782 dumpProcessSummaryDetails(pw, prefix, " Service: ", screenStates, memStates, 783 new int[] {STATE_SERVICE}, now, totalTime, true); 784 dumpProcessSummaryDetails(pw, prefix, " Service Rs: ", screenStates, memStates, 785 new int[] {STATE_SERVICE_RESTARTING}, now, totalTime, true); 786 dumpProcessSummaryDetails(pw, prefix, " Receiver: ", screenStates, memStates, 787 new int[] {STATE_RECEIVER}, now, totalTime, true); 788 dumpProcessSummaryDetails(pw, prefix, " (Home): ", screenStates, memStates, 789 new int[] {STATE_HOME}, now, totalTime, true); 790 dumpProcessSummaryDetails(pw, prefix, " (Last Act): ", screenStates, memStates, 791 new int[] {STATE_LAST_ACTIVITY}, now, totalTime, true); 792 dumpProcessSummaryDetails(pw, prefix, " (Cached): ", screenStates, memStates, 793 new int[] {STATE_CACHED_ACTIVITY, STATE_CACHED_ACTIVITY_CLIENT, 794 STATE_CACHED_EMPTY}, now, totalTime, true); 795 } 796 797 public void dumpProcessState(PrintWriter pw, String prefix, 798 int[] screenStates, int[] memStates, int[] procStates, long now) { 799 long totalTime = 0; 800 int printedScreen = -1; 801 for (int is=0; is<screenStates.length; is++) { 802 int printedMem = -1; 803 for (int im=0; im<memStates.length; im++) { 804 for (int ip=0; ip<procStates.length; ip++) { 805 final int iscreen = screenStates[is]; 806 final int imem = memStates[im]; 807 final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip]; 808 long time = mDurations.getValueForId((byte)bucket); 809 String running = ""; 810 if (mCurState == bucket) { 811 running = " (running)"; 812 } 813 if (time != 0) { 814 pw.print(prefix); 815 if (screenStates.length > 1) { 816 DumpUtils.printScreenLabel(pw, printedScreen != iscreen 817 ? iscreen : STATE_NOTHING); 818 printedScreen = iscreen; 819 } 820 if (memStates.length > 1) { 821 DumpUtils.printMemLabel(pw, 822 printedMem != imem ? imem : STATE_NOTHING, '/'); 823 printedMem = imem; 824 } 825 pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": "); 826 TimeUtils.formatDuration(time, pw); pw.println(running); 827 totalTime += time; 828 } 829 } 830 } 831 } 832 if (totalTime != 0) { 833 pw.print(prefix); 834 if (screenStates.length > 1) { 835 DumpUtils.printScreenLabel(pw, STATE_NOTHING); 836 } 837 if (memStates.length > 1) { 838 DumpUtils.printMemLabel(pw, STATE_NOTHING, '/'); 839 } 840 pw.print("TOTAL : "); 841 TimeUtils.formatDuration(totalTime, pw); 842 pw.println(); 843 } 844 } 845 846 public void dumpPss(PrintWriter pw, String prefix, 847 int[] screenStates, int[] memStates, int[] procStates) { 848 boolean printedHeader = false; 849 int printedScreen = -1; 850 for (int is=0; is<screenStates.length; is++) { 851 int printedMem = -1; 852 for (int im=0; im<memStates.length; im++) { 853 for (int ip=0; ip<procStates.length; ip++) { 854 final int iscreen = screenStates[is]; 855 final int imem = memStates[im]; 856 final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip]; 857 long count = getPssSampleCount(bucket); 858 if (count > 0) { 859 if (!printedHeader) { 860 pw.print(prefix); 861 pw.print("PSS/USS ("); 862 pw.print(mPssTable.getKeyCount()); 863 pw.println(" entries):"); 864 printedHeader = true; 865 } 866 pw.print(prefix); 867 pw.print(" "); 868 if (screenStates.length > 1) { 869 DumpUtils.printScreenLabel(pw, 870 printedScreen != iscreen ? iscreen : STATE_NOTHING); 871 printedScreen = iscreen; 872 } 873 if (memStates.length > 1) { 874 DumpUtils.printMemLabel(pw, 875 printedMem != imem ? imem : STATE_NOTHING, '/'); 876 printedMem = imem; 877 } 878 pw.print(DumpUtils.STATE_NAMES[procStates[ip]]); pw.print(": "); 879 pw.print(count); 880 pw.print(" samples "); 881 DebugUtils.printSizeValue(pw, getPssMinimum(bucket) * 1024); 882 pw.print(" "); 883 DebugUtils.printSizeValue(pw, getPssAverage(bucket) * 1024); 884 pw.print(" "); 885 DebugUtils.printSizeValue(pw, getPssMaximum(bucket) * 1024); 886 pw.print(" / "); 887 DebugUtils.printSizeValue(pw, getPssUssMinimum(bucket) * 1024); 888 pw.print(" "); 889 DebugUtils.printSizeValue(pw, getPssUssAverage(bucket) * 1024); 890 pw.print(" "); 891 DebugUtils.printSizeValue(pw, getPssUssMaximum(bucket) * 1024); 892 pw.println(); 893 } 894 } 895 } 896 } 897 if (mNumExcessiveWake != 0) { 898 pw.print(prefix); pw.print("Killed for excessive wake locks: "); 899 pw.print(mNumExcessiveWake); pw.println(" times"); 900 } 901 if (mNumExcessiveCpu != 0) { 902 pw.print(prefix); pw.print("Killed for excessive CPU use: "); 903 pw.print(mNumExcessiveCpu); pw.println(" times"); 904 } 905 if (mNumCachedKill != 0) { 906 pw.print(prefix); pw.print("Killed from cached state: "); 907 pw.print(mNumCachedKill); pw.print(" times from pss "); 908 DebugUtils.printSizeValue(pw, mMinCachedKillPss * 1024); pw.print("-"); 909 DebugUtils.printSizeValue(pw, mAvgCachedKillPss * 1024); pw.print("-"); 910 DebugUtils.printSizeValue(pw, mMaxCachedKillPss * 1024); pw.println(); 911 } 912 } 913 914 private void dumpProcessSummaryDetails(PrintWriter pw, String prefix, 915 String label, int[] screenStates, int[] memStates, int[] procStates, 916 long now, long totalTime, boolean full) { 917 ProcessStats.ProcessDataCollection totals = new ProcessStats.ProcessDataCollection( 918 screenStates, memStates, procStates); 919 computeProcessData(totals, now); 920 final double percentage = (double) totals.totalTime / (double) totalTime * 100; 921 // We don't print percentages < .01, so just drop those. 922 if (percentage >= 0.005 || totals.numPss != 0) { 923 if (prefix != null) { 924 pw.print(prefix); 925 } 926 if (label != null) { 927 pw.print(label); 928 } 929 totals.print(pw, totalTime, full); 930 if (prefix != null) { 931 pw.println(); 932 } 933 } 934 } 935 936 public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) { 937 if (dumpAll) { 938 pw.print(prefix); pw.print("myID="); 939 pw.print(Integer.toHexString(System.identityHashCode(this))); 940 pw.print(" mCommonProcess="); 941 pw.print(Integer.toHexString(System.identityHashCode(mCommonProcess))); 942 pw.print(" mPackage="); pw.println(mPackage); 943 if (mMultiPackage) { 944 pw.print(prefix); pw.print("mMultiPackage="); pw.println(mMultiPackage); 945 } 946 if (this != mCommonProcess) { 947 pw.print(prefix); pw.print("Common Proc: "); pw.print(mCommonProcess.mName); 948 pw.print("/"); pw.print(mCommonProcess.mUid); 949 pw.print(" pkg="); pw.println(mCommonProcess.mPackage); 950 } 951 } 952 if (mActive) { 953 pw.print(prefix); pw.print("mActive="); pw.println(mActive); 954 } 955 if (mDead) { 956 pw.print(prefix); pw.print("mDead="); pw.println(mDead); 957 } 958 if (mNumActiveServices != 0 || mNumStartedServices != 0) { 959 pw.print(prefix); pw.print("mNumActiveServices="); pw.print(mNumActiveServices); 960 pw.print(" mNumStartedServices="); 961 pw.println(mNumStartedServices); 962 } 963 } 964 965 public void computeProcessData(ProcessStats.ProcessDataCollection data, long now) { 966 data.totalTime = 0; 967 data.numPss = data.minPss = data.avgPss = data.maxPss = 968 data.minUss = data.avgUss = data.maxUss = 0; 969 for (int is=0; is<data.screenStates.length; is++) { 970 for (int im=0; im<data.memStates.length; im++) { 971 for (int ip=0; ip<data.procStates.length; ip++) { 972 int bucket = ((data.screenStates[is] + data.memStates[im]) * STATE_COUNT) 973 + data.procStates[ip]; 974 data.totalTime += getDuration(bucket, now); 975 long samples = getPssSampleCount(bucket); 976 if (samples > 0) { 977 long minPss = getPssMinimum(bucket); 978 long avgPss = getPssAverage(bucket); 979 long maxPss = getPssMaximum(bucket); 980 long minUss = getPssUssMinimum(bucket); 981 long avgUss = getPssUssAverage(bucket); 982 long maxUss = getPssUssMaximum(bucket); 983 if (data.numPss == 0) { 984 data.minPss = minPss; 985 data.avgPss = avgPss; 986 data.maxPss = maxPss; 987 data.minUss = minUss; 988 data.avgUss = avgUss; 989 data.maxUss = maxUss; 990 } else { 991 if (minPss < data.minPss) { 992 data.minPss = minPss; 993 } 994 data.avgPss = (long)( ((data.avgPss*(double)data.numPss) 995 + (avgPss*(double)samples)) / (data.numPss+samples) ); 996 if (maxPss > data.maxPss) { 997 data.maxPss = maxPss; 998 } 999 if (minUss < data.minUss) { 1000 data.minUss = minUss; 1001 } 1002 data.avgUss = (long)( ((data.avgUss*(double)data.numPss) 1003 + (avgUss*(double)samples)) / (data.numPss+samples) ); 1004 if (maxUss > data.maxUss) { 1005 data.maxUss = maxUss; 1006 } 1007 } 1008 data.numPss += samples; 1009 } 1010 } 1011 } 1012 } 1013 } 1014 1015 public void dumpCsv(PrintWriter pw, 1016 boolean sepScreenStates, int[] screenStates, boolean sepMemStates, 1017 int[] memStates, boolean sepProcStates, int[] procStates, long now) { 1018 final int NSS = sepScreenStates ? screenStates.length : 1; 1019 final int NMS = sepMemStates ? memStates.length : 1; 1020 final int NPS = sepProcStates ? procStates.length : 1; 1021 for (int iss=0; iss<NSS; iss++) { 1022 for (int ims=0; ims<NMS; ims++) { 1023 for (int ips=0; ips<NPS; ips++) { 1024 final int vsscreen = sepScreenStates ? screenStates[iss] : 0; 1025 final int vsmem = sepMemStates ? memStates[ims] : 0; 1026 final int vsproc = sepProcStates ? procStates[ips] : 0; 1027 final int NSA = sepScreenStates ? 1 : screenStates.length; 1028 final int NMA = sepMemStates ? 1 : memStates.length; 1029 final int NPA = sepProcStates ? 1 : procStates.length; 1030 long totalTime = 0; 1031 for (int isa=0; isa<NSA; isa++) { 1032 for (int ima=0; ima<NMA; ima++) { 1033 for (int ipa=0; ipa<NPA; ipa++) { 1034 final int vascreen = sepScreenStates ? 0 : screenStates[isa]; 1035 final int vamem = sepMemStates ? 0 : memStates[ima]; 1036 final int vaproc = sepProcStates ? 0 : procStates[ipa]; 1037 final int bucket = ((vsscreen + vascreen + vsmem + vamem) 1038 * STATE_COUNT) + vsproc + vaproc; 1039 totalTime += getDuration(bucket, now); 1040 } 1041 } 1042 } 1043 pw.print(DumpUtils.CSV_SEP); 1044 pw.print(totalTime); 1045 } 1046 } 1047 } 1048 } 1049 1050 public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, int vers, 1051 String itemName, long now) { 1052 pw.print("pkgproc,"); 1053 pw.print(pkgName); 1054 pw.print(","); 1055 pw.print(uid); 1056 pw.print(","); 1057 pw.print(vers); 1058 pw.print(","); 1059 pw.print(DumpUtils.collapseString(pkgName, itemName)); 1060 dumpAllStateCheckin(pw, now); 1061 pw.println(); 1062 if (mPssTable.getKeyCount() > 0) { 1063 pw.print("pkgpss,"); 1064 pw.print(pkgName); 1065 pw.print(","); 1066 pw.print(uid); 1067 pw.print(","); 1068 pw.print(vers); 1069 pw.print(","); 1070 pw.print(DumpUtils.collapseString(pkgName, itemName)); 1071 dumpAllPssCheckin(pw); 1072 pw.println(); 1073 } 1074 if (mNumExcessiveWake > 0 || mNumExcessiveCpu > 0 || mNumCachedKill > 0) { 1075 pw.print("pkgkills,"); 1076 pw.print(pkgName); 1077 pw.print(","); 1078 pw.print(uid); 1079 pw.print(","); 1080 pw.print(vers); 1081 pw.print(","); 1082 pw.print(DumpUtils.collapseString(pkgName, itemName)); 1083 pw.print(","); 1084 pw.print(mNumExcessiveWake); 1085 pw.print(","); 1086 pw.print(mNumExcessiveCpu); 1087 pw.print(","); 1088 pw.print(mNumCachedKill); 1089 pw.print(","); 1090 pw.print(mMinCachedKillPss); 1091 pw.print(":"); 1092 pw.print(mAvgCachedKillPss); 1093 pw.print(":"); 1094 pw.print(mMaxCachedKillPss); 1095 pw.println(); 1096 } 1097 } 1098 1099 public void dumpProcCheckin(PrintWriter pw, String procName, int uid, long now) { 1100 if (mDurations.getKeyCount() > 0) { 1101 pw.print("proc,"); 1102 pw.print(procName); 1103 pw.print(","); 1104 pw.print(uid); 1105 dumpAllStateCheckin(pw, now); 1106 pw.println(); 1107 } 1108 if (mPssTable.getKeyCount() > 0) { 1109 pw.print("pss,"); 1110 pw.print(procName); 1111 pw.print(","); 1112 pw.print(uid); 1113 dumpAllPssCheckin(pw); 1114 pw.println(); 1115 } 1116 if (mNumExcessiveWake > 0 || mNumExcessiveCpu > 0 || mNumCachedKill > 0) { 1117 pw.print("kills,"); 1118 pw.print(procName); 1119 pw.print(","); 1120 pw.print(uid); 1121 pw.print(","); 1122 pw.print(mNumExcessiveWake); 1123 pw.print(","); 1124 pw.print(mNumExcessiveCpu); 1125 pw.print(","); 1126 pw.print(mNumCachedKill); 1127 pw.print(","); 1128 pw.print(mMinCachedKillPss); 1129 pw.print(":"); 1130 pw.print(mAvgCachedKillPss); 1131 pw.print(":"); 1132 pw.print(mMaxCachedKillPss); 1133 pw.println(); 1134 } 1135 } 1136 1137 public void dumpAllStateCheckin(PrintWriter pw, long now) { 1138 boolean didCurState = false; 1139 for (int i=0; i<mDurations.getKeyCount(); i++) { 1140 final int key = mDurations.getKeyAt(i); 1141 final int type = SparseMappingTable.getIdFromKey(key); 1142 long time = mDurations.getValue(key); 1143 if (mCurState == type) { 1144 didCurState = true; 1145 time += now - mStartTime; 1146 } 1147 DumpUtils.printProcStateTagAndValue(pw, type, time); 1148 } 1149 if (!didCurState && mCurState != STATE_NOTHING) { 1150 DumpUtils.printProcStateTagAndValue(pw, mCurState, now - mStartTime); 1151 } 1152 } 1153 1154 public void dumpAllPssCheckin(PrintWriter pw) { 1155 final int N = mPssTable.getKeyCount(); 1156 for (int i=0; i<N; i++) { 1157 final int key = mPssTable.getKeyAt(i); 1158 final int type = SparseMappingTable.getIdFromKey(key); 1159 pw.print(','); 1160 DumpUtils.printProcStateTag(pw, type); 1161 pw.print(':'); 1162 pw.print(mPssTable.getValue(key, PSS_SAMPLE_COUNT)); 1163 pw.print(':'); 1164 pw.print(mPssTable.getValue(key, PSS_MINIMUM)); 1165 pw.print(':'); 1166 pw.print(mPssTable.getValue(key, PSS_AVERAGE)); 1167 pw.print(':'); 1168 pw.print(mPssTable.getValue(key, PSS_MAXIMUM)); 1169 pw.print(':'); 1170 pw.print(mPssTable.getValue(key, PSS_USS_MINIMUM)); 1171 pw.print(':'); 1172 pw.print(mPssTable.getValue(key, PSS_USS_AVERAGE)); 1173 pw.print(':'); 1174 pw.print(mPssTable.getValue(key, PSS_USS_MAXIMUM)); 1175 } 1176 } 1177 1178 public String toString() { 1179 StringBuilder sb = new StringBuilder(128); 1180 sb.append("ProcessState{").append(Integer.toHexString(System.identityHashCode(this))) 1181 .append(" ").append(mName).append("/").append(mUid) 1182 .append(" pkg=").append(mPackage); 1183 if (mMultiPackage) sb.append(" (multi)"); 1184 if (mCommonProcess != this) sb.append(" (sub)"); 1185 sb.append("}"); 1186 return sb.toString(); 1187 } 1188} 1189