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