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.Parcelable; 22 import android.os.SystemClock; 23 import android.os.SystemProperties; 24 import android.os.UserHandle; 25 import android.text.format.DateFormat; 26 import android.util.ArrayMap; 27 import android.util.ArraySet; 28 import android.util.DebugUtils; 29 import android.util.Log; 30 import android.util.Slog; 31 import android.util.SparseArray; 32 import android.util.TimeUtils; 33 34 import com.android.internal.app.procstats.ProcessStats; 35 import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING; 36 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.io.PrintWriter; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.Collections; 43 import java.util.Comparator; 44 import java.util.Objects; 45 46 public final class ServiceState { 47 private static final String TAG = "ProcessStats"; 48 private static final boolean DEBUG = false; 49 50 public static final int SERVICE_RUN = 0; 51 public static final int SERVICE_STARTED = 1; 52 public static final int SERVICE_BOUND = 2; 53 public static final int SERVICE_EXEC = 3; 54 public static final int SERVICE_COUNT = 4; 55 56 private final String mPackage; 57 private final String mProcessName; 58 private final String mName; 59 private final DurationsTable mDurations; 60 61 private ProcessState mProc; 62 private Object mOwner; 63 64 private int mRunCount; 65 private int mRunState = STATE_NOTHING; 66 private long mRunStartTime; 67 68 private boolean mStarted; 69 private boolean mRestarting; 70 private int mStartedCount; 71 private int mStartedState = STATE_NOTHING; 72 private long mStartedStartTime; 73 74 private int mBoundCount; 75 private int mBoundState = STATE_NOTHING; 76 private long mBoundStartTime; 77 78 private int mExecCount; 79 private int mExecState = STATE_NOTHING; 80 private long mExecStartTime; 81 ServiceState(ProcessStats processStats, String pkg, String name, String processName, ProcessState proc)82 public ServiceState(ProcessStats processStats, String pkg, String name, 83 String processName, ProcessState proc) { 84 mPackage = pkg; 85 mName = name; 86 mProcessName = processName; 87 mProc = proc; 88 mDurations = new DurationsTable(processStats.mTableData); 89 } 90 getPackage()91 public String getPackage() { 92 return mPackage; 93 } 94 getProcessName()95 public String getProcessName() { 96 return mProcessName; 97 } 98 getName()99 public String getName() { 100 return mName; 101 } 102 getProcess()103 public ProcessState getProcess() { 104 return mProc; 105 } 106 setProcess(ProcessState proc)107 public void setProcess(ProcessState proc) { 108 mProc = proc; 109 } 110 setMemFactor(int memFactor, long now)111 public void setMemFactor(int memFactor, long now) { 112 if (isRestarting()) { 113 setRestarting(true, memFactor, now); 114 } else if (isInUse()) { 115 if (mStartedState != ProcessStats.STATE_NOTHING) { 116 setStarted(true, memFactor, now); 117 } 118 if (mBoundState != ProcessStats.STATE_NOTHING) { 119 setBound(true, memFactor, now); 120 } 121 if (mExecState != ProcessStats.STATE_NOTHING) { 122 setExecuting(true, memFactor, now); 123 } 124 } 125 } 126 applyNewOwner(Object newOwner)127 public void applyNewOwner(Object newOwner) { 128 if (mOwner != newOwner) { 129 if (mOwner == null) { 130 mOwner = newOwner; 131 mProc.incActiveServices(mName); 132 } else { 133 // There was already an old owner, reset this object for its 134 // new owner. 135 mOwner = newOwner; 136 if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) { 137 long now = SystemClock.uptimeMillis(); 138 if (mStarted) { 139 if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner 140 + " from " + mOwner + " while started: pkg=" 141 + mPackage + " service=" + mName + " proc=" + mProc); 142 setStarted(false, 0, now); 143 } 144 if (mBoundState != STATE_NOTHING) { 145 if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner 146 + " from " + mOwner + " while bound: pkg=" 147 + mPackage + " service=" + mName + " proc=" + mProc); 148 setBound(false, 0, now); 149 } 150 if (mExecState != STATE_NOTHING) { 151 if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner 152 + " from " + mOwner + " while executing: pkg=" 153 + mPackage + " service=" + mName + " proc=" + mProc); 154 setExecuting(false, 0, now); 155 } 156 } 157 } 158 } 159 } 160 clearCurrentOwner(Object owner, boolean silently)161 public void clearCurrentOwner(Object owner, boolean silently) { 162 if (mOwner == owner) { 163 mProc.decActiveServices(mName); 164 if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) { 165 long now = SystemClock.uptimeMillis(); 166 if (mStarted) { 167 if (!silently) { 168 Slog.wtfStack(TAG, "Service owner " + owner 169 + " cleared while started: pkg=" + mPackage + " service=" 170 + mName + " proc=" + mProc); 171 } 172 setStarted(false, 0, now); 173 } 174 if (mBoundState != STATE_NOTHING) { 175 if (!silently) { 176 Slog.wtfStack(TAG, "Service owner " + owner 177 + " cleared while bound: pkg=" + mPackage + " service=" 178 + mName + " proc=" + mProc); 179 } 180 setBound(false, 0, now); 181 } 182 if (mExecState != STATE_NOTHING) { 183 if (!silently) { 184 Slog.wtfStack(TAG, "Service owner " + owner 185 + " cleared while exec: pkg=" + mPackage + " service=" 186 + mName + " proc=" + mProc); 187 } 188 setExecuting(false, 0, now); 189 } 190 } 191 mOwner = null; 192 } 193 } 194 isInUse()195 public boolean isInUse() { 196 return mOwner != null || mRestarting; 197 } 198 isRestarting()199 public boolean isRestarting() { 200 return mRestarting; 201 } 202 add(ServiceState other)203 public void add(ServiceState other) { 204 mDurations.addDurations(other.mDurations); 205 mRunCount += other.mRunCount; 206 mStartedCount += other.mStartedCount; 207 mBoundCount += other.mBoundCount; 208 mExecCount += other.mExecCount; 209 } 210 resetSafely(long now)211 public void resetSafely(long now) { 212 mDurations.resetTable(); 213 mRunCount = mRunState != STATE_NOTHING ? 1 : 0; 214 mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0; 215 mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0; 216 mExecCount = mExecState != STATE_NOTHING ? 1 : 0; 217 mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now; 218 } 219 writeToParcel(Parcel out, long now)220 public void writeToParcel(Parcel out, long now) { 221 mDurations.writeToParcel(out); 222 out.writeInt(mRunCount); 223 out.writeInt(mStartedCount); 224 out.writeInt(mBoundCount); 225 out.writeInt(mExecCount); 226 } 227 readFromParcel(Parcel in)228 public boolean readFromParcel(Parcel in) { 229 if (!mDurations.readFromParcel(in)) { 230 return false; 231 } 232 mRunCount = in.readInt(); 233 mStartedCount = in.readInt(); 234 mBoundCount = in.readInt(); 235 mExecCount = in.readInt(); 236 return true; 237 } 238 commitStateTime(long now)239 public void commitStateTime(long now) { 240 if (mRunState != STATE_NOTHING) { 241 mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), 242 now - mRunStartTime); 243 mRunStartTime = now; 244 } 245 if (mStartedState != STATE_NOTHING) { 246 mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT), 247 now - mStartedStartTime); 248 mStartedStartTime = now; 249 } 250 if (mBoundState != STATE_NOTHING) { 251 mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), 252 now - mBoundStartTime); 253 mBoundStartTime = now; 254 } 255 if (mExecState != STATE_NOTHING) { 256 mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), 257 now - mExecStartTime); 258 mExecStartTime = now; 259 } 260 } 261 updateRunning(int memFactor, long now)262 private void updateRunning(int memFactor, long now) { 263 final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING 264 || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING; 265 if (mRunState != state) { 266 if (mRunState != STATE_NOTHING) { 267 mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), 268 now - mRunStartTime); 269 } else if (state != STATE_NOTHING) { 270 mRunCount++; 271 } 272 mRunState = state; 273 mRunStartTime = now; 274 } 275 } 276 setStarted(boolean started, int memFactor, long now)277 public void setStarted(boolean started, int memFactor, long now) { 278 if (mOwner == null) { 279 Slog.wtf(TAG, "Starting service " + this + " without owner"); 280 } 281 mStarted = started; 282 updateStartedState(memFactor, now); 283 } 284 setRestarting(boolean restarting, int memFactor, long now)285 public void setRestarting(boolean restarting, int memFactor, long now) { 286 mRestarting = restarting; 287 updateStartedState(memFactor, now); 288 } 289 updateStartedState(int memFactor, long now)290 public void updateStartedState(int memFactor, long now) { 291 final boolean wasStarted = mStartedState != STATE_NOTHING; 292 final boolean started = mStarted || mRestarting; 293 final int state = started ? memFactor : STATE_NOTHING; 294 if (mStartedState != state) { 295 if (mStartedState != STATE_NOTHING) { 296 mDurations.addDuration(SERVICE_STARTED + (mStartedState*SERVICE_COUNT), 297 now - mStartedStartTime); 298 } else if (started) { 299 mStartedCount++; 300 } 301 mStartedState = state; 302 mStartedStartTime = now; 303 mProc = mProc.pullFixedProc(mPackage); 304 if (wasStarted != started) { 305 if (started) { 306 mProc.incStartedServices(memFactor, now, mName); 307 } else { 308 mProc.decStartedServices(memFactor, now, mName); 309 } 310 } 311 updateRunning(memFactor, now); 312 } 313 } 314 setBound(boolean bound, int memFactor, long now)315 public void setBound(boolean bound, int memFactor, long now) { 316 if (mOwner == null) { 317 Slog.wtf(TAG, "Binding service " + this + " without owner"); 318 } 319 final int state = bound ? memFactor : STATE_NOTHING; 320 if (mBoundState != state) { 321 if (mBoundState != STATE_NOTHING) { 322 mDurations.addDuration(SERVICE_BOUND + (mBoundState*SERVICE_COUNT), 323 now - mBoundStartTime); 324 } else if (bound) { 325 mBoundCount++; 326 } 327 mBoundState = state; 328 mBoundStartTime = now; 329 updateRunning(memFactor, now); 330 } 331 } 332 setExecuting(boolean executing, int memFactor, long now)333 public void setExecuting(boolean executing, int memFactor, long now) { 334 if (mOwner == null) { 335 Slog.wtf(TAG, "Executing service " + this + " without owner"); 336 } 337 final int state = executing ? memFactor : STATE_NOTHING; 338 if (mExecState != state) { 339 if (mExecState != STATE_NOTHING) { 340 mDurations.addDuration(SERVICE_EXEC + (mExecState*SERVICE_COUNT), 341 now - mExecStartTime); 342 } else if (executing) { 343 mExecCount++; 344 } 345 mExecState = state; 346 mExecStartTime = now; 347 updateRunning(memFactor, now); 348 } 349 } 350 getDuration(int opType, int curState, long startTime, int memFactor, long now)351 public long getDuration(int opType, int curState, long startTime, int memFactor, 352 long now) { 353 int state = opType + (memFactor*SERVICE_COUNT); 354 long time = mDurations.getValueForId((byte)state); 355 if (curState == memFactor) { 356 time += now - startTime; 357 } 358 return time; 359 } 360 dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, long now, long totalTime, boolean dumpSummary, boolean dumpAll)361 public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, 362 long now, long totalTime, boolean dumpSummary, boolean dumpAll) { 363 dumpStats(pw, prefix, prefixInner, headerPrefix, "Running", 364 mRunCount, ServiceState.SERVICE_RUN, mRunState, 365 mRunStartTime, now, totalTime, !dumpSummary || dumpAll); 366 dumpStats(pw, prefix, prefixInner, headerPrefix, "Started", 367 mStartedCount, ServiceState.SERVICE_STARTED, mStartedState, 368 mStartedStartTime, now, totalTime, !dumpSummary || dumpAll); 369 dumpStats(pw, prefix, prefixInner, headerPrefix, "Bound", 370 mBoundCount, ServiceState.SERVICE_BOUND, mBoundState, 371 mBoundStartTime, now, totalTime, !dumpSummary || dumpAll); 372 dumpStats(pw, prefix, prefixInner, headerPrefix, "Executing", 373 mExecCount, ServiceState.SERVICE_EXEC, mExecState, 374 mExecStartTime, now, totalTime, !dumpSummary || dumpAll); 375 if (dumpAll) { 376 if (mOwner != null) { 377 pw.print(" mOwner="); pw.println(mOwner); 378 } 379 if (mStarted || mRestarting) { 380 pw.print(" mStarted="); pw.print(mStarted); 381 pw.print(" mRestarting="); pw.println(mRestarting); 382 } 383 } 384 } 385 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)386 private void dumpStats(PrintWriter pw, String prefix, String prefixInner, 387 String headerPrefix, String header, 388 int count, int serviceType, int state, long startTime, long now, long totalTime, 389 boolean dumpAll) { 390 if (count != 0) { 391 if (dumpAll) { 392 pw.print(prefix); pw.print(header); 393 pw.print(" op count "); pw.print(count); pw.println(":"); 394 dumpTime(pw, prefixInner, serviceType, state, startTime, now); 395 } else { 396 long myTime = dumpTime(null, null, serviceType, state, startTime, now); 397 pw.print(prefix); pw.print(headerPrefix); pw.print(header); 398 pw.print(" count "); pw.print(count); 399 pw.print(" / time "); 400 DumpUtils.printPercent(pw, (double)myTime/(double)totalTime); 401 pw.println(); 402 } 403 } 404 } 405 dumpTime(PrintWriter pw, String prefix, int serviceType, int curState, long curStartTime, long now)406 public long dumpTime(PrintWriter pw, String prefix, 407 int serviceType, int curState, long curStartTime, long now) { 408 long totalTime = 0; 409 int printedScreen = -1; 410 for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) { 411 int printedMem = -1; 412 for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) { 413 int state = imem+iscreen; 414 long time = getDuration(serviceType, curState, curStartTime, state, now); 415 String running = ""; 416 if (curState == state && pw != null) { 417 running = " (running)"; 418 } 419 if (time != 0) { 420 if (pw != null) { 421 pw.print(prefix); 422 DumpUtils.printScreenLabel(pw, printedScreen != iscreen 423 ? iscreen : STATE_NOTHING); 424 printedScreen = iscreen; 425 DumpUtils.printMemLabel(pw, printedMem != imem ? imem : STATE_NOTHING, 426 (char)0); 427 printedMem = imem; 428 pw.print(": "); 429 TimeUtils.formatDuration(time, pw); pw.println(running); 430 } 431 totalTime += time; 432 } 433 } 434 } 435 if (totalTime != 0 && pw != null) { 436 pw.print(prefix); 437 pw.print(" TOTAL: "); 438 TimeUtils.formatDuration(totalTime, pw); 439 pw.println(); 440 } 441 return totalTime; 442 } 443 dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, int vers, String serviceName, long now)444 public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, int vers, 445 String serviceName, long now) { 446 dumpTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName, 447 ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now); 448 dumpTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName, 449 ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now); 450 dumpTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName, 451 ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now); 452 dumpTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName, 453 ServiceState.SERVICE_EXEC, mExecCount, mExecState, mExecStartTime, now); 454 } 455 dumpTimeCheckin(PrintWriter pw, String label, String packageName, int uid, int vers, String serviceName, int serviceType, int opCount, int curState, long curStartTime, long now)456 private void dumpTimeCheckin(PrintWriter pw, String label, String packageName, 457 int uid, int vers, String serviceName, int serviceType, int opCount, 458 int curState, long curStartTime, long now) { 459 if (opCount <= 0) { 460 return; 461 } 462 pw.print(label); 463 pw.print(","); 464 pw.print(packageName); 465 pw.print(","); 466 pw.print(uid); 467 pw.print(","); 468 pw.print(vers); 469 pw.print(","); 470 pw.print(serviceName); 471 pw.print(","); 472 pw.print(opCount); 473 boolean didCurState = false; 474 final int N = mDurations.getKeyCount(); 475 for (int i=0; i<N; i++) { 476 final int key = mDurations.getKeyAt(i); 477 long time = mDurations.getValue(key); 478 int type = SparseMappingTable.getIdFromKey(key); 479 int memFactor = type / ServiceState.SERVICE_COUNT; 480 type %= ServiceState.SERVICE_COUNT; 481 if (type != serviceType) { 482 continue; 483 } 484 if (curState == memFactor) { 485 didCurState = true; 486 time += now - curStartTime; 487 } 488 DumpUtils.printAdjTagAndValue(pw, memFactor, time); 489 } 490 if (!didCurState && curState != STATE_NOTHING) { 491 DumpUtils.printAdjTagAndValue(pw, curState, now - curStartTime); 492 } 493 pw.println(); 494 } 495 496 toString()497 public String toString() { 498 return "ServiceState{" + Integer.toHexString(System.identityHashCode(this)) 499 + " " + mName + " pkg=" + mPackage + " proc=" 500 + Integer.toHexString(System.identityHashCode(this)) + "}"; 501 } 502 } 503