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 20 import android.os.Parcel; 21 import android.os.SystemClock; 22 import android.service.procstats.PackageServiceOperationStatsProto; 23 import android.service.procstats.PackageServiceStatsProto; 24 import android.service.procstats.ProcessStatsEnums; 25 import android.util.Slog; 26 import android.util.TimeUtils; 27 import android.util.proto.ProtoOutputStream; 28 29 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING; 30 31 import java.io.PrintWriter; 32 33 public final class ServiceState { 34 private static final String TAG = "ProcessStats"; 35 private static final boolean DEBUG = false; 36 37 public static final int SERVICE_RUN = 0; 38 public static final int SERVICE_STARTED = 1; 39 public static final int SERVICE_BOUND = 2; 40 public static final int SERVICE_EXEC = 3; 41 public static final int SERVICE_FOREGROUND = 4; 42 public static final int SERVICE_COUNT = 5; 43 44 private final String mPackage; 45 private final String mProcessName; 46 private final String mName; 47 private final DurationsTable mDurations; 48 49 private ProcessState mProc; 50 private Object mOwner; 51 52 private int mRunCount; 53 private int mRunState = STATE_NOTHING; 54 private long mRunStartTime; 55 56 private boolean mStarted; 57 private boolean mRestarting; 58 private int mStartedCount; 59 private int mStartedState = STATE_NOTHING; 60 private long mStartedStartTime; 61 62 private int mBoundCount; 63 private int mBoundState = STATE_NOTHING; 64 private long mBoundStartTime; 65 66 private int mExecCount; 67 private int mExecState = STATE_NOTHING; 68 private long mExecStartTime; 69 70 private int mForegroundCount; 71 private int mForegroundState = STATE_NOTHING; 72 private long mForegroundStartTime; 73 ServiceState(ProcessStats processStats, String pkg, String name, String processName, ProcessState proc)74 public ServiceState(ProcessStats processStats, String pkg, String name, 75 String processName, ProcessState proc) { 76 mPackage = pkg; 77 mName = name; 78 mProcessName = processName; 79 mProc = proc; 80 mDurations = new DurationsTable(processStats.mTableData); 81 } 82 getPackage()83 public String getPackage() { 84 return mPackage; 85 } 86 getProcessName()87 public String getProcessName() { 88 return mProcessName; 89 } 90 getName()91 public String getName() { 92 return mName; 93 } 94 getProcess()95 public ProcessState getProcess() { 96 return mProc; 97 } 98 setProcess(ProcessState proc)99 public void setProcess(ProcessState proc) { 100 mProc = proc; 101 } 102 setMemFactor(int memFactor, long now)103 public void setMemFactor(int memFactor, long now) { 104 if (isRestarting()) { 105 setRestarting(true, memFactor, now); 106 } else if (isInUse()) { 107 if (mStartedState != ProcessStats.STATE_NOTHING) { 108 setStarted(true, memFactor, now); 109 } 110 if (mBoundState != ProcessStats.STATE_NOTHING) { 111 setBound(true, memFactor, now); 112 } 113 if (mExecState != ProcessStats.STATE_NOTHING) { 114 setExecuting(true, memFactor, now); 115 } 116 if (mForegroundState != ProcessStats.STATE_NOTHING) { 117 setForeground(true, memFactor, now); 118 } 119 } 120 } 121 applyNewOwner(Object newOwner)122 public void applyNewOwner(Object newOwner) { 123 if (mOwner != newOwner) { 124 if (mOwner == null) { 125 mOwner = newOwner; 126 mProc.incActiveServices(mName); 127 } else { 128 // There was already an old owner, reset this object for its 129 // new owner. 130 mOwner = newOwner; 131 if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING 132 || mForegroundState != STATE_NOTHING) { 133 long now = SystemClock.uptimeMillis(); 134 if (mStarted) { 135 if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner 136 + " from " + mOwner + " while started: pkg=" 137 + mPackage + " service=" + mName + " proc=" + mProc); 138 setStarted(false, 0, now); 139 } 140 if (mBoundState != STATE_NOTHING) { 141 if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner 142 + " from " + mOwner + " while bound: pkg=" 143 + mPackage + " service=" + mName + " proc=" + mProc); 144 setBound(false, 0, now); 145 } 146 if (mExecState != STATE_NOTHING) { 147 if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner 148 + " from " + mOwner + " while executing: pkg=" 149 + mPackage + " service=" + mName + " proc=" + mProc); 150 setExecuting(false, 0, now); 151 } 152 if (mForegroundState != STATE_NOTHING) { 153 if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner 154 + " from " + mOwner + " while foreground: pkg=" 155 + mPackage + " service=" + mName + " proc=" + mProc); 156 setForeground(false, 0, now); 157 } 158 } 159 } 160 } 161 } 162 clearCurrentOwner(Object owner, boolean silently)163 public void clearCurrentOwner(Object owner, boolean silently) { 164 if (mOwner == owner) { 165 mProc.decActiveServices(mName); 166 if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING 167 || mForegroundState != STATE_NOTHING) { 168 long now = SystemClock.uptimeMillis(); 169 if (mStarted) { 170 if (!silently) { 171 Slog.wtfStack(TAG, "Service owner " + owner 172 + " cleared while started: pkg=" + mPackage + " service=" 173 + mName + " proc=" + mProc); 174 } 175 setStarted(false, 0, now); 176 } 177 if (mBoundState != STATE_NOTHING) { 178 if (!silently) { 179 Slog.wtfStack(TAG, "Service owner " + owner 180 + " cleared while bound: pkg=" + mPackage + " service=" 181 + mName + " proc=" + mProc); 182 } 183 setBound(false, 0, now); 184 } 185 if (mExecState != STATE_NOTHING) { 186 if (!silently) { 187 Slog.wtfStack(TAG, "Service owner " + owner 188 + " cleared while exec: pkg=" + mPackage + " service=" 189 + mName + " proc=" + mProc); 190 } 191 setExecuting(false, 0, now); 192 } 193 if (mForegroundState != STATE_NOTHING) { 194 if (!silently) { 195 Slog.wtfStack(TAG, "Service owner " + owner 196 + " cleared while foreground: pkg=" + mPackage + " service=" 197 + mName + " proc=" + mProc); 198 } 199 setForeground(false, 0, now); 200 } 201 } 202 mOwner = null; 203 } 204 } 205 isInUse()206 public boolean isInUse() { 207 return mOwner != null || mRestarting; 208 } 209 isRestarting()210 public boolean isRestarting() { 211 return mRestarting; 212 } 213 add(ServiceState other)214 public void add(ServiceState other) { 215 mDurations.addDurations(other.mDurations); 216 mRunCount += other.mRunCount; 217 mStartedCount += other.mStartedCount; 218 mBoundCount += other.mBoundCount; 219 mExecCount += other.mExecCount; 220 mForegroundCount += other.mForegroundCount; 221 } 222 resetSafely(long now)223 public void resetSafely(long now) { 224 mDurations.resetTable(); 225 mRunCount = mRunState != STATE_NOTHING ? 1 : 0; 226 mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0; 227 mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0; 228 mExecCount = mExecState != STATE_NOTHING ? 1 : 0; 229 mForegroundCount = mForegroundState != STATE_NOTHING ? 1 : 0; 230 mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = 231 mForegroundStartTime = now; 232 } 233 writeToParcel(Parcel out, long now)234 public void writeToParcel(Parcel out, long now) { 235 mDurations.writeToParcel(out); 236 out.writeInt(mRunCount); 237 out.writeInt(mStartedCount); 238 out.writeInt(mBoundCount); 239 out.writeInt(mExecCount); 240 out.writeInt(mForegroundCount); 241 } 242 readFromParcel(Parcel in)243 public boolean readFromParcel(Parcel in) { 244 if (!mDurations.readFromParcel(in)) { 245 return false; 246 } 247 mRunCount = in.readInt(); 248 mStartedCount = in.readInt(); 249 mBoundCount = in.readInt(); 250 mExecCount = in.readInt(); 251 mForegroundCount = in.readInt(); 252 return true; 253 } 254 commitStateTime(long now)255 public void commitStateTime(long now) { 256 if (mRunState != STATE_NOTHING) { 257 mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), 258 now - mRunStartTime); 259 mRunStartTime = now; 260 } 261 if (mStartedState != STATE_NOTHING) { 262 mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT), 263 now - mStartedStartTime); 264 mStartedStartTime = now; 265 } 266 if (mBoundState != STATE_NOTHING) { 267 mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), 268 now - mBoundStartTime); 269 mBoundStartTime = now; 270 } 271 if (mExecState != STATE_NOTHING) { 272 mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), 273 now - mExecStartTime); 274 mExecStartTime = now; 275 } 276 if (mForegroundState != STATE_NOTHING) { 277 mDurations.addDuration(SERVICE_FOREGROUND + (mForegroundState*SERVICE_COUNT), 278 now - mForegroundStartTime); 279 mForegroundStartTime = now; 280 } 281 } 282 updateRunning(int memFactor, long now)283 private void updateRunning(int memFactor, long now) { 284 final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING 285 || mExecState != STATE_NOTHING || mForegroundState != STATE_NOTHING) 286 ? memFactor : STATE_NOTHING; 287 if (mRunState != state) { 288 if (mRunState != STATE_NOTHING) { 289 mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), 290 now - mRunStartTime); 291 } else if (state != STATE_NOTHING) { 292 mRunCount++; 293 } 294 mRunState = state; 295 mRunStartTime = now; 296 } 297 } 298 setStarted(boolean started, int memFactor, long now)299 public void setStarted(boolean started, int memFactor, long now) { 300 if (mOwner == null) { 301 Slog.wtf(TAG, "Starting service " + this + " without owner"); 302 } 303 mStarted = started; 304 updateStartedState(memFactor, now); 305 } 306 setRestarting(boolean restarting, int memFactor, long now)307 public void setRestarting(boolean restarting, int memFactor, long now) { 308 mRestarting = restarting; 309 updateStartedState(memFactor, now); 310 } 311 updateStartedState(int memFactor, long now)312 public void updateStartedState(int memFactor, long now) { 313 final boolean wasStarted = mStartedState != STATE_NOTHING; 314 final boolean started = mStarted || mRestarting; 315 final int state = started ? memFactor : STATE_NOTHING; 316 if (mStartedState != state) { 317 if (mStartedState != STATE_NOTHING) { 318 mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT), 319 now - mStartedStartTime); 320 } else if (started) { 321 mStartedCount++; 322 } 323 mStartedState = state; 324 mStartedStartTime = now; 325 mProc = mProc.pullFixedProc(mPackage); 326 if (wasStarted != started) { 327 if (started) { 328 mProc.incStartedServices(memFactor, now, mName); 329 } else { 330 mProc.decStartedServices(memFactor, now, mName); 331 } 332 } 333 updateRunning(memFactor, now); 334 } 335 } 336 setBound(boolean bound, int memFactor, long now)337 public void setBound(boolean bound, int memFactor, long now) { 338 if (mOwner == null) { 339 Slog.wtf(TAG, "Binding service " + this + " without owner"); 340 } 341 final int state = bound ? memFactor : STATE_NOTHING; 342 if (mBoundState != state) { 343 if (mBoundState != STATE_NOTHING) { 344 mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), 345 now - mBoundStartTime); 346 } else if (bound) { 347 mBoundCount++; 348 } 349 mBoundState = state; 350 mBoundStartTime = now; 351 updateRunning(memFactor, now); 352 } 353 } 354 setExecuting(boolean executing, int memFactor, long now)355 public void setExecuting(boolean executing, int memFactor, long now) { 356 if (mOwner == null) { 357 Slog.wtf(TAG, "Executing service " + this + " without owner"); 358 } 359 final int state = executing ? memFactor : STATE_NOTHING; 360 if (mExecState != state) { 361 if (mExecState != STATE_NOTHING) { 362 mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), 363 now - mExecStartTime); 364 } else if (executing) { 365 mExecCount++; 366 } 367 mExecState = state; 368 mExecStartTime = now; 369 updateRunning(memFactor, now); 370 } 371 } 372 setForeground(boolean foreground, int memFactor, long now)373 public void setForeground(boolean foreground, int memFactor, long now) { 374 if (mOwner == null) { 375 Slog.wtf(TAG, "Foregrounding service " + this + " without owner"); 376 } 377 final int state = foreground ? memFactor : STATE_NOTHING; 378 if (mForegroundState != state) { 379 if (mForegroundState != STATE_NOTHING) { 380 mDurations.addDuration(SERVICE_FOREGROUND + (mForegroundState*SERVICE_COUNT), 381 now - mForegroundStartTime); 382 } else if (foreground) { 383 mForegroundCount++; 384 } 385 mForegroundState = state; 386 mForegroundStartTime = now; 387 updateRunning(memFactor, now); 388 } 389 } 390 getDuration(int opType, int curState, long startTime, int memFactor, long now)391 public long getDuration(int opType, int curState, long startTime, int memFactor, 392 long now) { 393 int state = opType + (memFactor*SERVICE_COUNT); 394 long time = mDurations.getValueForId((byte)state); 395 if (curState == memFactor) { 396 time += now - startTime; 397 } 398 return time; 399 } 400 dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, long now, long totalTime, boolean dumpSummary, boolean dumpAll)401 public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, 402 long now, long totalTime, boolean dumpSummary, boolean dumpAll) { 403 dumpStats(pw, prefix, prefixInner, headerPrefix, "Running", 404 mRunCount, ServiceState.SERVICE_RUN, mRunState, 405 mRunStartTime, now, totalTime, !dumpSummary || dumpAll); 406 dumpStats(pw, prefix, prefixInner, headerPrefix, "Started", 407 mStartedCount, ServiceState.SERVICE_STARTED, mStartedState, 408 mStartedStartTime, now, totalTime, !dumpSummary || dumpAll); 409 dumpStats(pw, prefix, prefixInner, headerPrefix, "Foreground", 410 mForegroundCount, ServiceState.SERVICE_FOREGROUND, mForegroundState, 411 mForegroundStartTime, now, totalTime, !dumpSummary || dumpAll); 412 dumpStats(pw, prefix, prefixInner, headerPrefix, "Bound", 413 mBoundCount, ServiceState.SERVICE_BOUND, mBoundState, 414 mBoundStartTime, now, totalTime, !dumpSummary || dumpAll); 415 dumpStats(pw, prefix, prefixInner, headerPrefix, "Executing", 416 mExecCount, ServiceState.SERVICE_EXEC, mExecState, 417 mExecStartTime, now, totalTime, !dumpSummary || dumpAll); 418 if (dumpAll) { 419 if (mOwner != null) { 420 pw.print(" mOwner="); pw.println(mOwner); 421 } 422 if (mStarted || mRestarting) { 423 pw.print(" mStarted="); pw.print(mStarted); 424 pw.print(" mRestarting="); pw.println(mRestarting); 425 } 426 } 427 } 428 dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, String header, int count, int serviceType, int state, long startTime, long now, long totalTime, boolean dumpAll)429 private void dumpStats(PrintWriter pw, String prefix, String prefixInner, 430 String headerPrefix, String header, 431 int count, int serviceType, int state, long startTime, long now, long totalTime, 432 boolean dumpAll) { 433 if (count != 0) { 434 if (dumpAll) { 435 pw.print(prefix); pw.print(header); 436 pw.print(" op count "); pw.print(count); pw.println(":"); 437 dumpTime(pw, prefixInner, serviceType, state, startTime, now); 438 } else { 439 long myTime = dumpTimeInternal(null, null, serviceType, state, startTime, now, 440 true); 441 pw.print(prefix); pw.print(headerPrefix); pw.print(header); 442 pw.print(" count "); pw.print(count); 443 pw.print(" / time "); 444 boolean isRunning = myTime < 0; 445 if (isRunning) { 446 myTime = -myTime; 447 } 448 DumpUtils.printPercent(pw, (double)myTime/(double)totalTime); 449 if (isRunning) { 450 pw.print(" (running)"); 451 } 452 pw.println(); 453 } 454 } 455 } 456 457 public long dumpTime(PrintWriter pw, String prefix, 458 int serviceType, int curState, long curStartTime, long now) { 459 return dumpTimeInternal(pw, prefix, serviceType, curState, curStartTime, now, false); 460 } 461 462 long dumpTimeInternal(PrintWriter pw, String prefix, 463 int serviceType, int curState, long curStartTime, long now, boolean negativeIfRunning) { 464 long totalTime = 0; 465 int printedScreen = -1; 466 boolean isRunning = false; 467 for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) { 468 int printedMem = -1; 469 for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) { 470 int state = imem+iscreen; 471 long time = getDuration(serviceType, curState, curStartTime, state, now); 472 String running = ""; 473 if (curState == state && pw != null) { 474 running = " (running)"; 475 isRunning = true; 476 } 477 if (time != 0) { 478 if (pw != null) { 479 pw.print(prefix); 480 DumpUtils.printScreenLabel(pw, printedScreen != iscreen 481 ? iscreen : STATE_NOTHING); 482 printedScreen = iscreen; 483 DumpUtils.printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, 484 (char)0); 485 printedMem = imem; 486 pw.print(": "); 487 TimeUtils.formatDuration(time, pw); pw.println(running); 488 } 489 totalTime += time; 490 } 491 } 492 } 493 if (totalTime != 0 && pw != null) { 494 pw.print(prefix); 495 pw.print(" TOTAL: "); 496 TimeUtils.formatDuration(totalTime, pw); 497 pw.println(); 498 } 499 return (isRunning && negativeIfRunning) ? -totalTime : totalTime; 500 } 501 502 public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers, 503 String serviceName, long now) { 504 dumpTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName, 505 ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now); 506 dumpTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName, 507 ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now); 508 dumpTimeCheckin(pw, "pkgsvc-fg", pkgName, uid, vers, serviceName, 509 ServiceState.SERVICE_FOREGROUND, mForegroundCount, mForegroundState, 510 mForegroundStartTime, now); 511 dumpTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName, 512 ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now); 513 dumpTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName, 514 ServiceState.SERVICE_EXEC, mExecCount, mExecState, mExecStartTime, now); 515 } 516 517 private void dumpTimeCheckin(PrintWriter pw, String label, String packageName, 518 int uid, long vers, String serviceName, int serviceType, int opCount, 519 int curState, long curStartTime, long now) { 520 if (opCount <= 0) { 521 return; 522 } 523 pw.print(label); 524 pw.print(","); 525 pw.print(packageName); 526 pw.print(","); 527 pw.print(uid); 528 pw.print(","); 529 pw.print(vers); 530 pw.print(","); 531 pw.print(serviceName); 532 pw.print(","); 533 pw.print(opCount); 534 boolean didCurState = false; 535 final int N = mDurations.getKeyCount(); 536 for (int i=0; i<N; i++) { 537 final int key = mDurations.getKeyAt(i); 538 long time = mDurations.getValue(key); 539 int type = SparseMappingTable.getIdFromKey(key); 540 int memFactor = type / ServiceState.SERVICE_COUNT; 541 type %= ServiceState.SERVICE_COUNT; 542 if (type != serviceType) { 543 continue; 544 } 545 if (curState == memFactor) { 546 didCurState = true; 547 time += now - curStartTime; 548 } 549 DumpUtils.printAdjTagAndValue(pw, memFactor, time); 550 } 551 if (!didCurState && curState != STATE_NOTHING) { 552 DumpUtils.printAdjTagAndValue(pw, curState, now - curStartTime); 553 } 554 pw.println(); 555 } 556 557 public void dumpDebug(ProtoOutputStream proto, long fieldId, long now) { 558 final long token = proto.start(fieldId); 559 proto.write(PackageServiceStatsProto.SERVICE_NAME, mName); 560 561 writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS, 562 ProcessStatsEnums.SERVICE_OPERATION_STATE_RUNNING, 563 ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now); 564 565 writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS, 566 ProcessStatsEnums.SERVICE_OPERATION_STATE_STARTED, 567 ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now); 568 569 writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS, 570 ProcessStatsEnums.SERVICE_OPERATION_STATE_FOREGROUND, 571 ServiceState.SERVICE_FOREGROUND, mForegroundCount, mForegroundState, 572 mForegroundStartTime, now); 573 574 writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS, 575 ProcessStatsEnums.SERVICE_OPERATION_STATE_BOUND, 576 ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now); 577 578 writeTypeToProto(proto, PackageServiceStatsProto.OPERATION_STATS, 579 ProcessStatsEnums.SERVICE_OPERATION_STATE_EXECUTING, 580 ServiceState.SERVICE_EXEC, mExecCount, mExecState, mExecStartTime, now); 581 582 proto.end(token); 583 } 584 585 /** 586 * write the metrics to proto for each operation type. 587 */ 588 public void writeTypeToProto(ProtoOutputStream proto, long fieldId, int opType, int serviceType, 589 int opCount, int curState, long curStartTime, long now) { 590 if (opCount <= 0) { 591 return; 592 } 593 final long token = proto.start(fieldId); 594 595 proto.write(PackageServiceOperationStatsProto.OPERATION, opType); 596 proto.write(PackageServiceOperationStatsProto.COUNT, opCount); 597 598 boolean didCurState = false; 599 final int N = mDurations.getKeyCount(); 600 for (int i=0; i<N; i++) { 601 final int key = mDurations.getKeyAt(i); 602 long time = mDurations.getValue(key); 603 int type = SparseMappingTable.getIdFromKey(key); 604 int memFactor = type / ServiceState.SERVICE_COUNT; 605 type %= ServiceState.SERVICE_COUNT; 606 if (type != serviceType) { 607 continue; 608 } 609 if (curState == memFactor) { 610 didCurState = true; 611 time += now - curStartTime; 612 } 613 final long stateToken = proto.start(PackageServiceOperationStatsProto.STATE_STATS); 614 DumpUtils.printProcStateAdjTagProto(proto, 615 PackageServiceOperationStatsProto.StateStats.SCREEN_STATE, 616 PackageServiceOperationStatsProto.StateStats.MEMORY_STATE, 617 type); 618 proto.write(PackageServiceOperationStatsProto.StateStats.DURATION_MS, time); 619 proto.end(stateToken); 620 } 621 if (!didCurState && curState != STATE_NOTHING) { 622 final long stateToken = proto.start(PackageServiceOperationStatsProto.STATE_STATS); 623 DumpUtils.printProcStateAdjTagProto(proto, 624 PackageServiceOperationStatsProto.StateStats.SCREEN_STATE, 625 PackageServiceOperationStatsProto.StateStats.MEMORY_STATE, 626 curState); 627 proto.write(PackageServiceOperationStatsProto.StateStats.DURATION_MS, 628 now - curStartTime); 629 proto.end(stateToken); 630 } 631 632 proto.end(token); 633 } 634 635 public String toString() { 636 return "ServiceState{" + Integer.toHexString(System.identityHashCode(this)) 637 + " " + mName + " pkg=" + mPackage + " proc=" 638 + Integer.toHexString(System.identityHashCode(mProc)) + "}"; 639 } 640 } 641