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