1 /* 2 * Copyright (C) 2018 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 20 import android.annotation.Nullable; 21 import android.os.Parcel; 22 import android.os.SystemClock; 23 import android.os.UserHandle; 24 import android.service.procstats.PackageAssociationProcessStatsProto; 25 import android.service.procstats.PackageAssociationSourceProcessStatsProto; 26 import android.util.ArrayMap; 27 import android.util.Slog; 28 import android.util.TimeUtils; 29 import android.util.proto.ProtoOutputStream; 30 31 import java.io.PrintWriter; 32 import java.util.ArrayList; 33 import java.util.Objects; 34 35 public final class AssociationState { 36 private static final String TAG = "ProcessStats"; 37 private static final boolean DEBUG = false; 38 39 private final ProcessStats mProcessStats; 40 private final ProcessStats.PackageState mPackageState; 41 private final String mProcessName; 42 private final String mName; 43 44 public final class SourceState { 45 final SourceKey mKey; 46 int mProcStateSeq = -1; 47 int mProcState = ProcessStats.STATE_NOTHING; 48 boolean mInTrackingList; 49 int mNesting; 50 int mCount; 51 long mStartUptime; 52 long mDuration; 53 long mTrackingUptime; 54 int mActiveCount; 55 int mActiveProcState = ProcessStats.STATE_NOTHING; 56 long mActiveStartUptime; 57 long mActiveDuration; 58 DurationsTable mDurations; 59 SourceState(SourceKey key)60 SourceState(SourceKey key) { 61 mKey = key; 62 } 63 getAssociationState()64 public AssociationState getAssociationState() { 65 return AssociationState.this; 66 } 67 getProcessName()68 public String getProcessName() { 69 return mKey.mProcess; 70 } 71 getUid()72 public int getUid() { 73 return mKey.mUid; 74 } 75 trackProcState(int procState, int seq, long now)76 public void trackProcState(int procState, int seq, long now) { 77 procState = ProcessState.PROCESS_STATE_TO_STATE[procState]; 78 if (seq != mProcStateSeq) { 79 mProcStateSeq = seq; 80 mProcState = procState; 81 } else if (procState < mProcState) { 82 mProcState = procState; 83 } 84 if (procState < ProcessStats.STATE_HOME) { 85 // If the proc state has become better than cached, then we want to 86 // start tracking it to count when it is actually active. If it drops 87 // down to cached, we will clean it up when we later evaluate all currently 88 // tracked associations in ProcessStats.updateTrackingAssociationsLocked(). 89 if (!mInTrackingList) { 90 mInTrackingList = true; 91 mTrackingUptime = now; 92 mProcessStats.mTrackingAssociations.add(this); 93 } 94 } 95 } 96 stop()97 public void stop() { 98 mNesting--; 99 if (mNesting == 0) { 100 mDuration += SystemClock.uptimeMillis() - mStartUptime; 101 mNumActive--; 102 stopTracking(SystemClock.uptimeMillis()); 103 } 104 } 105 startActive(long now)106 void startActive(long now) { 107 if (mInTrackingList) { 108 if (mActiveStartUptime == 0) { 109 mActiveStartUptime = now; 110 mActiveCount++; 111 } 112 if (mActiveProcState != mProcState) { 113 if (mActiveProcState != ProcessStats.STATE_NOTHING) { 114 // Currently active proc state changed, need to store the duration 115 // so far and switch tracking to the new proc state. 116 final long duration = mActiveDuration + now - mActiveStartUptime; 117 if (duration != 0) { 118 if (mDurations == null) { 119 makeDurations(); 120 } 121 mDurations.addDuration(mActiveProcState, duration); 122 mActiveDuration = 0; 123 } 124 mActiveStartUptime = now; 125 } 126 mActiveProcState = mProcState; 127 } 128 } else { 129 Slog.wtf(TAG, "startActive while not tracking: " + this); 130 } 131 } 132 stopActive(long now)133 void stopActive(long now) { 134 if (mActiveStartUptime != 0) { 135 if (!mInTrackingList) { 136 Slog.wtf(TAG, "stopActive while not tracking: " + this); 137 } 138 final long duration = mActiveDuration + now - mActiveStartUptime; 139 if (mDurations != null) { 140 mDurations.addDuration(mActiveProcState, duration); 141 } else { 142 mActiveDuration = duration; 143 } 144 mActiveStartUptime = 0; 145 } 146 } 147 makeDurations()148 void makeDurations() { 149 mDurations = new DurationsTable(mProcessStats.mTableData); 150 } 151 stopTracking(long now)152 void stopTracking(long now) { 153 stopActive(now); 154 if (mInTrackingList) { 155 mInTrackingList = false; 156 mProcState = ProcessStats.STATE_NOTHING; 157 // Do a manual search for where to remove, since these objects will typically 158 // be towards the end of the array. 159 final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations; 160 for (int i = list.size() - 1; i >= 0; i--) { 161 if (list.get(i) == this) { 162 list.remove(i); 163 return; 164 } 165 } 166 Slog.wtf(TAG, "Stop tracking didn't find in tracking list: " + this); 167 } 168 } 169 170 @Override toString()171 public String toString() { 172 StringBuilder sb = new StringBuilder(64); 173 sb.append("SourceState{").append(Integer.toHexString(System.identityHashCode(this))) 174 .append(" ").append(mKey.mProcess).append("/").append(mKey.mUid); 175 if (mProcState != ProcessStats.STATE_NOTHING) { 176 sb.append(" ").append(DumpUtils.STATE_NAMES[mProcState]).append(" #") 177 .append(mProcStateSeq); 178 } 179 sb.append("}"); 180 return sb.toString(); 181 } 182 } 183 184 private final static class SourceKey { 185 /** 186 * UID, consider this final. Not final just to avoid a temporary object during lookup. 187 */ 188 int mUid; 189 190 /** 191 * Process name, consider this final. Not final just to avoid a temporary object during 192 * lookup. 193 */ 194 String mProcess; 195 196 /** 197 * Optional package name, or null; consider this final. Not final just to avoid a 198 * temporary object during lookup. 199 */ 200 @Nullable String mPackage; 201 SourceKey(int uid, String process, String pkg)202 SourceKey(int uid, String process, String pkg) { 203 mUid = uid; 204 mProcess = process; 205 mPackage = pkg; 206 } 207 equals(Object o)208 public boolean equals(Object o) { 209 if (!(o instanceof SourceKey)) { 210 return false; 211 } 212 SourceKey s = (SourceKey) o; 213 return s.mUid == mUid && Objects.equals(s.mProcess, mProcess) 214 && Objects.equals(s.mPackage, mPackage); 215 } 216 217 @Override hashCode()218 public int hashCode() { 219 return Integer.hashCode(mUid) ^ (mProcess == null ? 0 : mProcess.hashCode()) 220 ^ (mPackage == null ? 0 : (mPackage.hashCode() * 33)); 221 } 222 223 @Override toString()224 public String toString() { 225 StringBuilder sb = new StringBuilder(64); 226 sb.append("SourceKey{"); 227 UserHandle.formatUid(sb, mUid); 228 sb.append(' '); 229 sb.append(mProcess); 230 sb.append(' '); 231 sb.append(mPackage); 232 sb.append('}'); 233 return sb.toString(); 234 } 235 } 236 237 /** 238 * All known sources for this target component... uid -> process name -> source state. 239 */ 240 private final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>(); 241 242 private final SourceKey mTmpSourceKey = new SourceKey(0, null, null); 243 244 private ProcessState mProc; 245 246 private int mNumActive; 247 AssociationState(ProcessStats processStats, ProcessStats.PackageState packageState, String name, String processName, ProcessState proc)248 public AssociationState(ProcessStats processStats, ProcessStats.PackageState packageState, 249 String name, String processName, ProcessState proc) { 250 mProcessStats = processStats; 251 mPackageState = packageState; 252 mName = name; 253 mProcessName = processName; 254 mProc = proc; 255 } 256 getUid()257 public int getUid() { 258 return mPackageState.mUid; 259 } 260 getPackage()261 public String getPackage() { 262 return mPackageState.mPackageName; 263 } 264 getProcessName()265 public String getProcessName() { 266 return mProcessName; 267 } 268 getName()269 public String getName() { 270 return mName; 271 } 272 getProcess()273 public ProcessState getProcess() { 274 return mProc; 275 } 276 setProcess(ProcessState proc)277 public void setProcess(ProcessState proc) { 278 mProc = proc; 279 } 280 startSource(int uid, String processName, String packageName)281 public SourceState startSource(int uid, String processName, String packageName) { 282 mTmpSourceKey.mUid = uid; 283 mTmpSourceKey.mProcess = processName; 284 mTmpSourceKey.mPackage = packageName; 285 SourceState src = mSources.get(mTmpSourceKey); 286 if (src == null) { 287 SourceKey key = new SourceKey(uid, processName, packageName); 288 src = new SourceState(key); 289 mSources.put(key, src); 290 } 291 src.mNesting++; 292 if (src.mNesting == 1) { 293 src.mCount++; 294 src.mStartUptime = SystemClock.uptimeMillis(); 295 mNumActive++; 296 } 297 return src; 298 } 299 add(AssociationState other)300 public void add(AssociationState other) { 301 for (int isrc = other.mSources.size() - 1; isrc >= 0; isrc--) { 302 final SourceKey key = other.mSources.keyAt(isrc); 303 final SourceState otherSrc = other.mSources.valueAt(isrc); 304 SourceState mySrc = mSources.get(key); 305 if (mySrc == null) { 306 mySrc = new SourceState(key); 307 mSources.put(key, mySrc); 308 } 309 mySrc.mCount += otherSrc.mCount; 310 mySrc.mDuration += otherSrc.mDuration; 311 mySrc.mActiveCount += otherSrc.mActiveCount; 312 if (otherSrc.mActiveDuration != 0 || otherSrc.mDurations != null) { 313 // Only need to do anything if the other one has some duration data. 314 if (mySrc.mDurations != null) { 315 // If the target already has multiple durations, just add in whatever 316 // we have in the other. 317 if (otherSrc.mDurations != null) { 318 mySrc.mDurations.addDurations(otherSrc.mDurations); 319 } else { 320 mySrc.mDurations.addDuration(otherSrc.mActiveProcState, 321 otherSrc.mActiveDuration); 322 } 323 } else if (otherSrc.mDurations != null) { 324 // The other one has multiple durations, but we don't. Expand to 325 // multiple durations and copy over. 326 mySrc.makeDurations(); 327 mySrc.mDurations.addDurations(otherSrc.mDurations); 328 if (mySrc.mActiveDuration != 0) { 329 mySrc.mDurations.addDuration(mySrc.mActiveProcState, mySrc.mActiveDuration); 330 mySrc.mActiveDuration = 0; 331 mySrc.mActiveProcState = ProcessStats.STATE_NOTHING; 332 } 333 } else if (mySrc.mActiveDuration != 0) { 334 // Both have a single inline duration... we can either add them together, 335 // or need to expand to multiple durations. 336 if (mySrc.mActiveProcState == otherSrc.mActiveProcState) { 337 mySrc.mDuration += otherSrc.mDuration; 338 } else { 339 // The two have durations with different proc states, need to turn 340 // in to multiple durations. 341 mySrc.makeDurations(); 342 mySrc.mDurations.addDuration(mySrc.mActiveProcState, mySrc.mActiveDuration); 343 mySrc.mDurations.addDuration(otherSrc.mActiveProcState, 344 otherSrc.mActiveDuration); 345 mySrc.mActiveDuration = 0; 346 mySrc.mActiveProcState = ProcessStats.STATE_NOTHING; 347 } 348 } else { 349 // The other one has a duration, and we know the target doesn't. Copy over. 350 mySrc.mActiveProcState = otherSrc.mActiveProcState; 351 mySrc.mActiveDuration = otherSrc.mActiveDuration; 352 } 353 } 354 } 355 } 356 isInUse()357 public boolean isInUse() { 358 return mNumActive > 0; 359 } 360 resetSafely(long now)361 public void resetSafely(long now) { 362 if (!isInUse()) { 363 mSources.clear(); 364 } else { 365 // We have some active sources... clear out everything but those. 366 for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) { 367 SourceState src = mSources.valueAt(isrc); 368 if (src.mNesting > 0) { 369 src.mCount = 1; 370 src.mStartUptime = now; 371 src.mDuration = 0; 372 if (src.mActiveStartUptime > 0) { 373 src.mActiveCount = 1; 374 src.mActiveStartUptime = now; 375 } else { 376 src.mActiveCount = 0; 377 } 378 src.mActiveDuration = 0; 379 src.mDurations = null; 380 } else { 381 mSources.removeAt(isrc); 382 } 383 } 384 } 385 } 386 writeToParcel(ProcessStats stats, Parcel out, long nowUptime)387 public void writeToParcel(ProcessStats stats, Parcel out, long nowUptime) { 388 final int NSRC = mSources.size(); 389 out.writeInt(NSRC); 390 for (int isrc = 0; isrc < NSRC; isrc++) { 391 final SourceKey key = mSources.keyAt(isrc); 392 final SourceState src = mSources.valueAt(isrc); 393 out.writeInt(key.mUid); 394 stats.writeCommonString(out, key.mProcess); 395 stats.writeCommonString(out, key.mPackage); 396 out.writeInt(src.mCount); 397 out.writeLong(src.mDuration); 398 out.writeInt(src.mActiveCount); 399 if (src.mDurations != null) { 400 out.writeInt(1); 401 src.mDurations.writeToParcel(out); 402 } else { 403 out.writeInt(0); 404 out.writeInt(src.mActiveProcState); 405 out.writeLong(src.mActiveDuration); 406 } 407 } 408 } 409 410 /** 411 * Returns non-null if all else fine, else a String that describes the error that 412 * caused it to fail. 413 */ readFromParcel(ProcessStats stats, Parcel in, int parcelVersion)414 public String readFromParcel(ProcessStats stats, Parcel in, int parcelVersion) { 415 final int NSRC = in.readInt(); 416 if (NSRC < 0 || NSRC > 100000) { 417 return "Association with bad src count: " + NSRC; 418 } 419 for (int isrc = 0; isrc < NSRC; isrc++) { 420 final int uid = in.readInt(); 421 final String procName = stats.readCommonString(in, parcelVersion); 422 final String pkgName = stats.readCommonString(in, parcelVersion); 423 final SourceKey key = new SourceKey(uid, procName, pkgName); 424 final SourceState src = new SourceState(key); 425 src.mCount = in.readInt(); 426 src.mDuration = in.readLong(); 427 src.mActiveCount = in.readInt(); 428 if (in.readInt() != 0) { 429 src.makeDurations(); 430 if (!src.mDurations.readFromParcel(in)) { 431 return "Duration table corrupt: " + key + " <- " + src; 432 } 433 } else { 434 src.mActiveProcState = in.readInt(); 435 src.mActiveDuration = in.readLong(); 436 } 437 mSources.put(key, src); 438 } 439 return null; 440 } 441 commitStateTime(long nowUptime)442 public void commitStateTime(long nowUptime) { 443 if (isInUse()) { 444 for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) { 445 SourceState src = mSources.valueAt(isrc); 446 if (src.mNesting > 0) { 447 src.mDuration += nowUptime - src.mStartUptime; 448 src.mStartUptime = nowUptime; 449 } 450 if (src.mActiveStartUptime > 0) { 451 final long duration = src.mActiveDuration + nowUptime - src.mActiveStartUptime; 452 if (src.mDurations != null) { 453 src.mDurations.addDuration(src.mActiveProcState, duration); 454 } else { 455 src.mActiveDuration = duration; 456 } 457 src.mActiveStartUptime = nowUptime; 458 } 459 } 460 } 461 } 462 hasProcessOrPackage(String procName)463 public boolean hasProcessOrPackage(String procName) { 464 final int NSRC = mSources.size(); 465 for (int isrc = 0; isrc < NSRC; isrc++) { 466 final SourceKey key = mSources.keyAt(isrc); 467 if (procName.equals(key.mProcess) || procName.equals(key.mPackage)) { 468 return true; 469 } 470 } 471 return false; 472 } 473 dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, long now, long totalTime, String reqPackage, boolean dumpDetails, boolean dumpAll)474 public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, 475 long now, long totalTime, String reqPackage, boolean dumpDetails, boolean dumpAll) { 476 if (dumpAll) { 477 pw.print(prefix); 478 pw.print("mNumActive="); 479 pw.println(mNumActive); 480 } 481 final int NSRC = mSources.size(); 482 for (int isrc = 0; isrc < NSRC; isrc++) { 483 final SourceKey key = mSources.keyAt(isrc); 484 final SourceState src = mSources.valueAt(isrc); 485 if (reqPackage != null && !reqPackage.equals(key.mProcess) 486 && !reqPackage.equals(key.mPackage)) { 487 continue; 488 } 489 pw.print(prefixInner); 490 pw.print("<- "); 491 pw.print(key.mProcess); 492 pw.print("/"); 493 UserHandle.formatUid(pw, key.mUid); 494 if (key.mPackage != null) { 495 pw.print(" ("); 496 pw.print(key.mPackage); 497 pw.print(")"); 498 } 499 pw.println(":"); 500 pw.print(prefixInner); 501 pw.print(" Total count "); 502 pw.print(src.mCount); 503 long duration = src.mDuration; 504 if (src.mNesting > 0) { 505 duration += now - src.mStartUptime; 506 } 507 if (dumpAll) { 508 pw.print(": Duration "); 509 TimeUtils.formatDuration(duration, pw); 510 pw.print(" / "); 511 } else { 512 pw.print(": time "); 513 } 514 DumpUtils.printPercent(pw, (double)duration/(double)totalTime); 515 if (src.mNesting > 0) { 516 pw.print(" (running"); 517 if (src.mProcState != ProcessStats.STATE_NOTHING) { 518 pw.print(" / "); 519 pw.print(DumpUtils.STATE_NAMES[src.mProcState]); 520 pw.print(" #"); 521 pw.print(src.mProcStateSeq); 522 } 523 pw.print(")"); 524 } 525 pw.println(); 526 if (src.mActiveCount > 0 || src.mDurations != null || src.mActiveDuration != 0 527 || src.mActiveStartUptime != 0) { 528 pw.print(prefixInner); 529 pw.print(" Active count "); 530 pw.print(src.mActiveCount); 531 if (dumpDetails) { 532 if (dumpAll) { 533 pw.print(src.mDurations != null ? " (multi-field)" : " (inline)"); 534 } 535 pw.println(":"); 536 dumpTime(pw, prefixInner, src, totalTime, now, dumpDetails, dumpAll); 537 } else { 538 pw.print(": "); 539 dumpActiveDurationSummary(pw, src, totalTime, now, dumpAll); 540 pw.println(); 541 } 542 } 543 if (dumpAll) { 544 if (src.mInTrackingList) { 545 pw.print(prefixInner); 546 pw.print(" mInTrackingList="); 547 pw.println(src.mInTrackingList); 548 } 549 if (src.mProcState != ProcessStats.STATE_NOTHING) { 550 pw.print(prefixInner); 551 pw.print(" mProcState="); 552 pw.print(DumpUtils.STATE_NAMES[src.mProcState]); 553 pw.print(" mProcStateSeq="); 554 pw.println(src.mProcStateSeq); 555 } 556 } 557 } 558 } 559 dumpActiveDurationSummary(PrintWriter pw, final SourceState src, long totalTime, long now, boolean dumpAll)560 void dumpActiveDurationSummary(PrintWriter pw, final SourceState src, long totalTime, 561 long now, boolean dumpAll) { 562 long duration = dumpTime(null, null, src, totalTime, now, false, false); 563 final boolean isRunning = duration < 0; 564 if (isRunning) { 565 duration = -duration; 566 } 567 if (dumpAll) { 568 pw.print("Duration "); 569 TimeUtils.formatDuration(duration, pw); 570 pw.print(" / "); 571 } else { 572 pw.print("time "); 573 } 574 DumpUtils.printPercent(pw, (double) duration / (double) totalTime); 575 if (src.mActiveStartUptime > 0) { 576 pw.print(" (running)"); 577 } 578 pw.println(); 579 } 580 dumpTime(PrintWriter pw, String prefix, final SourceState src, long overallTime, long now, boolean dumpDetails, boolean dumpAll)581 long dumpTime(PrintWriter pw, String prefix, final SourceState src, long overallTime, long now, 582 boolean dumpDetails, boolean dumpAll) { 583 long totalTime = 0; 584 boolean isRunning = false; 585 for (int iprocstate = 0; iprocstate < ProcessStats.STATE_COUNT; iprocstate++) { 586 long time; 587 if (src.mDurations != null) { 588 time = src.mDurations.getValueForId((byte)iprocstate); 589 } else { 590 time = src.mActiveProcState == iprocstate ? src.mDuration : 0; 591 } 592 final String running; 593 if (src.mActiveStartUptime != 0 && src.mActiveProcState == iprocstate) { 594 running = " (running)"; 595 isRunning = true; 596 time += now - src.mActiveStartUptime; 597 } else { 598 running = null; 599 } 600 if (time != 0) { 601 if (pw != null) { 602 pw.print(prefix); 603 pw.print(" "); 604 pw.print(DumpUtils.STATE_LABELS[iprocstate]); 605 pw.print(": "); 606 if (dumpAll) { 607 pw.print("Duration "); 608 TimeUtils.formatDuration(time, pw); 609 pw.print(" / "); 610 } else { 611 pw.print("time "); 612 } 613 DumpUtils.printPercent(pw, (double) time / (double) overallTime); 614 if (running != null) { 615 pw.print(running); 616 } 617 pw.println(); 618 } 619 totalTime += time; 620 } 621 } 622 if (totalTime != 0 && pw != null) { 623 pw.print(prefix); 624 pw.print(" "); 625 pw.print(DumpUtils.STATE_LABEL_TOTAL); 626 pw.print(": "); 627 if (dumpAll) { 628 pw.print("Duration "); 629 TimeUtils.formatDuration(totalTime, pw); 630 pw.print(" / "); 631 } else { 632 pw.print("time "); 633 } 634 DumpUtils.printPercent(pw, (double) totalTime / (double) overallTime); 635 pw.println(); 636 } 637 return isRunning ? -totalTime : totalTime; 638 } 639 dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers, String associationName, long now)640 public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers, 641 String associationName, long now) { 642 final int NSRC = mSources.size(); 643 for (int isrc = 0; isrc < NSRC; isrc++) { 644 final SourceKey key = mSources.keyAt(isrc); 645 final SourceState src = mSources.valueAt(isrc); 646 pw.print("pkgasc"); 647 pw.print(","); 648 pw.print(pkgName); 649 pw.print(","); 650 pw.print(uid); 651 pw.print(","); 652 pw.print(vers); 653 pw.print(","); 654 pw.print(associationName); 655 pw.print(","); 656 pw.print(key.mProcess); 657 pw.print(","); 658 pw.print(key.mUid); 659 pw.print(","); 660 pw.print(src.mCount); 661 long duration = src.mDuration; 662 if (src.mNesting > 0) { 663 duration += now - src.mStartUptime; 664 } 665 pw.print(","); 666 pw.print(duration); 667 pw.print(","); 668 pw.print(src.mActiveCount); 669 final long timeNow = src.mActiveStartUptime != 0 ? (now-src.mActiveStartUptime) : 0; 670 if (src.mDurations != null) { 671 final int N = src.mDurations.getKeyCount(); 672 for (int i=0; i<N; i++) { 673 final int dkey = src.mDurations.getKeyAt(i); 674 duration = src.mDurations.getValue(dkey); 675 if (dkey == src.mActiveProcState) { 676 duration += timeNow; 677 } 678 final int procState = SparseMappingTable.getIdFromKey(dkey); 679 pw.print(","); 680 DumpUtils.printArrayEntry(pw, DumpUtils.STATE_TAGS, procState, 1); 681 pw.print(':'); 682 pw.print(duration); 683 } 684 } else { 685 duration = src.mActiveDuration + timeNow; 686 if (duration != 0) { 687 pw.print(","); 688 DumpUtils.printArrayEntry(pw, DumpUtils.STATE_TAGS, src.mActiveProcState, 1); 689 pw.print(':'); 690 pw.print(duration); 691 } 692 } 693 pw.println(); 694 } 695 } 696 writeToProto(ProtoOutputStream proto, long fieldId, long now)697 public void writeToProto(ProtoOutputStream proto, long fieldId, long now) { 698 final long token = proto.start(fieldId); 699 700 proto.write(PackageAssociationProcessStatsProto.COMPONENT_NAME, mName); 701 702 final int NSRC = mSources.size(); 703 for (int isrc = 0; isrc < NSRC; isrc++) { 704 final SourceKey key = mSources.keyAt(isrc); 705 final SourceState src = mSources.valueAt(isrc); 706 final long sourceToken = proto.start(PackageAssociationProcessStatsProto.SOURCES); 707 proto.write(PackageAssociationSourceProcessStatsProto.PROCESS_NAME, key.mProcess); 708 proto.write(PackageAssociationSourceProcessStatsProto.PACKAGE_NAME, key.mPackage); 709 proto.write(PackageAssociationSourceProcessStatsProto.PROCESS_UID, key.mUid); 710 proto.write(PackageAssociationSourceProcessStatsProto.TOTAL_COUNT, src.mCount); 711 long duration = src.mDuration; 712 if (src.mNesting > 0) { 713 duration += now - src.mStartUptime; 714 } 715 proto.write(PackageAssociationSourceProcessStatsProto.TOTAL_DURATION_MS, duration); 716 if (src.mActiveCount != 0) { 717 proto.write(PackageAssociationSourceProcessStatsProto.ACTIVE_COUNT, 718 src.mActiveCount); 719 } 720 final long timeNow = src.mActiveStartUptime != 0 ? (now-src.mActiveStartUptime) : 0; 721 if (src.mDurations != null) { 722 final int N = src.mDurations.getKeyCount(); 723 for (int i=0; i<N; i++) { 724 final int dkey = src.mDurations.getKeyAt(i); 725 duration = src.mDurations.getValue(dkey); 726 if (dkey == src.mActiveProcState) { 727 duration += timeNow; 728 } 729 final int procState = SparseMappingTable.getIdFromKey(dkey); 730 final long stateToken = proto.start( 731 PackageAssociationSourceProcessStatsProto.ACTIVE_STATE_STATS); 732 DumpUtils.printProto(proto, 733 PackageAssociationSourceProcessStatsProto.StateStats.PROCESS_STATE, 734 DumpUtils.STATE_PROTO_ENUMS, procState, 1); 735 proto.write(PackageAssociationSourceProcessStatsProto.StateStats.DURATION_MS, 736 duration); 737 proto.end(stateToken); 738 } 739 } else { 740 duration = src.mActiveDuration + timeNow; 741 if (duration != 0) { 742 final long stateToken = proto.start( 743 PackageAssociationSourceProcessStatsProto.ACTIVE_STATE_STATS); 744 DumpUtils.printProto(proto, 745 PackageAssociationSourceProcessStatsProto.StateStats.PROCESS_STATE, 746 DumpUtils.STATE_PROTO_ENUMS, src.mActiveProcState, 1); 747 proto.write(PackageAssociationSourceProcessStatsProto.StateStats.DURATION_MS, 748 duration); 749 proto.end(stateToken); 750 } 751 } 752 proto.end(sourceToken); 753 } 754 755 proto.end(token); 756 } 757 toString()758 public String toString() { 759 return "AssociationState{" + Integer.toHexString(System.identityHashCode(this)) 760 + " " + mName + " pkg=" + mPackageState.mPackageName + " proc=" 761 + Integer.toHexString(System.identityHashCode(mProc)) + "}"; 762 } 763 } 764