1 /* 2 * Copyright (C) 2023 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.server.utils; 18 19 import static android.text.TextUtils.formatSimple; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.os.SystemClock; 26 import android.os.Trace; 27 import android.text.TextUtils; 28 import android.text.format.TimeMigrationUtils; 29 import android.util.ArrayMap; 30 import android.util.CloseGuard; 31 import android.util.IndentingPrintWriter; 32 import android.util.Log; 33 import android.util.LongSparseArray; 34 import android.util.SparseArray; 35 36 import com.android.internal.annotations.GuardedBy; 37 import com.android.internal.annotations.Keep; 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.internal.util.RingBuffer; 40 41 import java.lang.ref.WeakReference; 42 import java.io.PrintWriter; 43 import java.util.Arrays; 44 import java.util.ArrayList; 45 import java.util.Comparator; 46 import java.util.Objects; 47 48 /** 49 * This class managers AnrTimers. An AnrTimer is a substitute for a delayed Message. In legacy 50 * mode, the timer just sends a delayed message. In modern mode, the timer is implemented in 51 * native code; on expiration, the message is sent without delay. 52 * 53 * <p>There are five external operations on a timer: 54 * <ul> 55 * 56 * <li>{@link #start} starts a timer. The timer is started with an object that the message 57 * argument. The timer is also given the pid and uid of the target. A timer that is started must 58 * be canceled, accepted, or discarded. 59 * 60 * <li>{@link #cancel} stops a timer and removes any in-flight expiration messages. 61 * 62 * <li>{@link #accept} acknowledges that the timer has expired, and that an ANR should be 63 * generated. This clears bookkeeping information for the timer. 64 * 65 * <li>{@link #discard} acknowledges that the timer has expired but, for other reasons, no ANR 66 * will be generated. This clears bookkeeping information for the timer. 67 * 68 *</li></p> 69 * 70 * <p>There is one internal operation on a timer: {@link #expire}. A timer may have automatic 71 * extensions enabled. If so, the extension is computed and if the extension is non-zero, the timer 72 * is restarted with the extension timeout. If extensions are disabled or if the extension is zero, 73 * the client process is notified of the expiration. 74 * 75 * <p>Instances use native resources but not system resources when the feature is enabled. 76 * Instances should be explicitly closed unless they are being closed as part of process 77 * exit. (So, instances in system server generally need not be explicitly closed since they are 78 * created during process start and will last until process exit.) 79 * 80 * <p>AnrTimer parameterized by the type <code>V</code>. The public methods on AnrTimer require 81 * an instance of <code>V</code>; the instance of <code>V</code> is a key that identifies a 82 * specific timer. 83 * 84 * @hide 85 */ 86 public abstract class AnrTimer<V> implements AutoCloseable { 87 88 /** 89 * The log tag. 90 */ 91 final static String TAG = "AnrTimer"; 92 93 /** 94 * The trace track for these events. There is a single track for all AnrTimer instances. The 95 * tracks give a sense of handler latency: the time between timer expiration and ANR 96 * collection. 97 */ 98 private final static String TRACK = "AnrTimerTrack"; 99 100 /** 101 * Enable debug messages. 102 */ 103 private static boolean DEBUG = false; 104 105 /** 106 * The trace tag is the same usd by ActivityManager. 107 */ 108 private static final long TRACE_TAG = Trace.TRACE_TAG_ACTIVITY_MANAGER; 109 110 /** 111 * Fetch the Linux pid from the object. The returned value may be zero to indicate that there 112 * is no valid pid available. 113 * @return a valid pid or zero. 114 */ getPid(V obj)115 public abstract int getPid(V obj); 116 117 /** 118 * Fetch the Linux uid from the object. The returned value may be zero to indicate that there 119 * is no valid uid available. 120 * @return a valid uid or zero. 121 */ getUid(V obj)122 public abstract int getUid(V obj); 123 124 /** 125 * Return true if the feature is enabled. By default, the value is take from the Flags class 126 * but it can be changed for local testing. 127 */ anrTimerServiceEnabled()128 private static boolean anrTimerServiceEnabled() { 129 return Flags.anrTimerService(); 130 } 131 132 /** 133 * Return true if freezing is feature-enabled. Freezing must still be enabled on a 134 * per-service basis. 135 */ freezerFeatureEnabled()136 private static boolean freezerFeatureEnabled() { 137 return false; 138 } 139 140 /** 141 * Return true if tracing is feature-enabled. This has no effect unless tracing is configured. 142 * Note that this does not represent any per-process overrides via an Injector. 143 */ traceFeatureEnabled()144 public static boolean traceFeatureEnabled() { 145 return anrTimerServiceEnabled() && Flags.anrTimerTrace(); 146 } 147 148 /** 149 * This class allows test code to provide instance-specific overrides. 150 */ 151 static class Injector { serviceEnabled()152 boolean serviceEnabled() { 153 return AnrTimer.anrTimerServiceEnabled(); 154 } 155 freezerEnabled()156 boolean freezerEnabled() { 157 return AnrTimer.freezerFeatureEnabled(); 158 } 159 traceEnabled()160 boolean traceEnabled() { 161 return AnrTimer.traceFeatureEnabled(); 162 } 163 } 164 165 /** The default injector. */ 166 private static final Injector sDefaultInjector = new Injector(); 167 168 /** 169 * This class provides build-style arguments to an AnrTimer constructor. This simplifies the 170 * number of AnrTimer constructors needed, especially as new options are added. 171 */ 172 public static class Args { 173 /** The Injector (used only for testing). */ 174 private Injector mInjector = AnrTimer.sDefaultInjector; 175 176 /** Grant timer extensions when the system is heavily loaded. */ 177 private boolean mExtend = false; 178 179 /** Freeze ANR'ed processes. */ 180 boolean mFreeze = false; 181 182 // This is only used for testing, so it is limited to package visibility. injector(@onNull Injector injector)183 Args injector(@NonNull Injector injector) { 184 mInjector = injector; 185 return this; 186 } 187 extend(boolean flag)188 public Args extend(boolean flag) { 189 mExtend = flag; 190 return this; 191 } 192 freeze(boolean enable)193 public Args freeze(boolean enable) { 194 mFreeze = enable; 195 return this; 196 } 197 } 198 199 /** 200 * A target process may be modified when its timer expires. The modification (if any) will be 201 * undone if the expiration is discarded, but is persisted if the expiration is accepted. If 202 * the expiration is accepted, then a TimerLock is returned to the client. The client must 203 * close the TimerLock to complete the state machine. 204 */ 205 private class TimerLock implements AutoCloseable { 206 // Detect failures to close. 207 private final CloseGuard mGuard = new CloseGuard(); 208 209 // A lock to ensure closing is thread-safe. 210 private final Object mLock = new Object(); 211 212 // Allow multiple calls to close(). 213 private boolean mClosed = false; 214 215 // The native timer ID that must be closed. This may be zero. 216 final int mTimerId; 217 TimerLock(int timerId)218 TimerLock(int timerId) { 219 mTimerId = timerId; 220 mGuard.open("AnrTimer.release"); 221 } 222 223 @Override close()224 public void close() { 225 synchronized (mLock) { 226 if (!mClosed) { 227 AnrTimer.this.release(this); 228 mGuard.close(); 229 mClosed = true; 230 } 231 } 232 } 233 234 @Override finalize()235 protected void finalize() throws Throwable { 236 try { 237 // Note that guard could be null if the constructor threw. 238 if (mGuard != null) mGuard.warnIfOpen(); 239 close(); 240 } finally { 241 super.finalize(); 242 } 243 } 244 } 245 246 /** 247 * An error is defined by its issue, the operation that detected the error, the tag of the 248 * affected service, a short stack of the bad call, and the stringified arg associated with 249 * the error. 250 */ 251 private static final class Error { 252 /** The issue is the kind of error that was detected. This is a free-form string. */ 253 final String issue; 254 /** The operation that detected the error: start, cancel, accept, or discard. */ 255 final String operation; 256 /** The argument (stringified) passed in to the operation. */ 257 final String arg; 258 /** The tag of the associated AnrTimer. */ 259 final String tag; 260 /** A partial stack that localizes the caller of the operation. */ 261 final StackTraceElement[] stack; 262 /** The date, in local time, the error was created. */ 263 final long timestamp; 264 Error(@onNull String issue, @NonNull String operation, @NonNull String tag, @NonNull StackTraceElement[] stack, @NonNull String arg)265 Error(@NonNull String issue, @NonNull String operation, @NonNull String tag, 266 @NonNull StackTraceElement[] stack, @NonNull String arg) { 267 this.issue = issue; 268 this.operation = operation; 269 this.tag = tag; 270 this.stack = stack; 271 this.arg = arg; 272 this.timestamp = SystemClock.elapsedRealtime(); 273 } 274 275 /** 276 * Dump a single error to the output stream. 277 */ dump(IndentingPrintWriter ipw, int seq)278 private void dump(IndentingPrintWriter ipw, int seq) { 279 ipw.format("%2d: op:%s tag:%s issue:%s arg:%s\n", seq, operation, tag, issue, arg); 280 281 final long offset = System.currentTimeMillis() - SystemClock.elapsedRealtime(); 282 final long etime = offset + timestamp; 283 ipw.println(" date:" + TimeMigrationUtils.formatMillisWithFixedFormat(etime)); 284 ipw.increaseIndent(); 285 for (int i = 0; i < stack.length; i++) { 286 ipw.println(" " + stack[i].toString()); 287 } 288 ipw.decreaseIndent(); 289 } 290 } 291 292 /** 293 * A list of errors detected during processing. Errors correspond to "timer not found" 294 * conditions. The stack trace identifies the source of the call. The list is 295 * first-in/first-out, and the size is limited to 20. 296 */ 297 @GuardedBy("sErrors") 298 private static final RingBuffer<Error> sErrors = new RingBuffer<>(Error.class, 20); 299 300 /** A lock for the AnrTimer instance. */ 301 private final Object mLock = new Object(); 302 303 /** The map from client argument to the associated timer ID. */ 304 @GuardedBy("mLock") 305 private final ArrayMap<V, Integer> mTimerIdMap = new ArrayMap<>(); 306 307 /** Reverse map from timer ID to client argument. */ 308 @GuardedBy("mLock") 309 private final SparseArray<V> mTimerArgMap = new SparseArray<>(); 310 311 /** The highwater mark of started, but not closed, timers. */ 312 @GuardedBy("mLock") 313 private int mMaxStarted = 0; 314 315 /** The total number of timers started. */ 316 @GuardedBy("mLock") 317 private int mTotalStarted = 0; 318 319 /** The total number of errors detected. */ 320 @GuardedBy("mLock") 321 private int mTotalErrors = 0; 322 323 /** The total number of timers that have expired. */ 324 @GuardedBy("mLock") 325 private int mTotalExpired = 0; 326 327 /** The handler for messages sent from this instance. */ 328 private final Handler mHandler; 329 330 /** The message type for messages sent from this interface. */ 331 private final int mWhat; 332 333 /** A label that identifies the AnrTimer associated with a Timer in log messages. */ 334 private final String mLabel; 335 336 /** The configuration for this instance. */ 337 private final Args mArgs; 338 339 /** The top-level switch for the feature enabled or disabled. */ 340 private final FeatureSwitch mFeature; 341 342 /** 343 * Create one AnrTimer instance. The instance is given a handler and a "what". Individual 344 * timers are started with {@link #start}. If a timer expires, then a {@link Message} is sent 345 * immediately to the handler with {@link Message.what} set to what and {@link Message.obj} set 346 * to the timer key. 347 * 348 * AnrTimer instances have a label, which must be unique. The label is used for reporting and 349 * debug. 350 * 351 * If an individual timer expires internally, and the "extend" parameter is true, then the 352 * AnrTimer may extend the individual timer rather than immediately delivering the timeout to 353 * the client. The extension policy is not part of the instance. 354 * 355 * @param handler The handler to which the expiration message will be delivered. 356 * @param what The "what" parameter for the expiration message. 357 * @param label A name for this instance. 358 * @param args Configuration information for this instance. 359 */ AnrTimer(@onNull Handler handler, int what, @NonNull String label, @NonNull Args args)360 public AnrTimer(@NonNull Handler handler, int what, @NonNull String label, @NonNull Args args) { 361 mHandler = handler; 362 mWhat = what; 363 mLabel = label; 364 mArgs = args; 365 boolean enabled = args.mInjector.serviceEnabled() && nativeTimersSupported(); 366 mFeature = createFeatureSwitch(enabled); 367 } 368 369 // Return the correct feature. FeatureEnabled is returned if and only if the feature is 370 // flag-enabled and if the native shadow was successfully created. Otherwise, FeatureDisabled 371 // is returned. createFeatureSwitch(boolean enabled)372 private FeatureSwitch createFeatureSwitch(boolean enabled) { 373 if (!enabled) { 374 return new FeatureDisabled(); 375 } else { 376 try { 377 return new FeatureEnabled(); 378 } catch (RuntimeException e) { 379 // Something went wrong in the native layer. Log the error and fall back on the 380 // feature-disabled logic. 381 Log.e(TAG, e.toString()); 382 return new FeatureDisabled(); 383 } 384 } 385 } 386 387 /** 388 * Create an AnrTimer instance with the default {@link #Injector} and the default configuration. 389 * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description. 390 * 391 * @param handler The handler to which the expiration message will be delivered. 392 * @param what The "what" parameter for the expiration message. 393 * @param label A name for this instance. 394 */ AnrTimer(@onNull Handler handler, int what, @NonNull String label)395 public AnrTimer(@NonNull Handler handler, int what, @NonNull String label) { 396 this(handler, what, label, new Args()); 397 } 398 399 /** 400 * Return true if the service is enabled on this instance. Clients should use this method to 401 * decide if the feature is enabled, and not read the flags directly. This method should be 402 * deleted if and when the feature is enabled permanently. 403 * 404 * @return true if the service is flag-enabled. 405 */ serviceEnabled()406 public boolean serviceEnabled() { 407 return mFeature.enabled(); 408 } 409 410 /** 411 * Generate a trace point with full timer information. The meaning of milliseconds depends on 412 * the caller. 413 */ trace(String op, int timerId, int pid, int uid, long milliseconds)414 private void trace(String op, int timerId, int pid, int uid, long milliseconds) { 415 final String label = 416 formatSimple("%s(%d,%d,%d,%s,%d)", op, timerId, pid, uid, mLabel, milliseconds); 417 Trace.instantForTrack(TRACE_TAG, TRACK, label); 418 if (DEBUG) Log.i(TAG, label); 419 } 420 421 /** 422 * Generate a trace point with just the timer ID. 423 */ trace(String op, int timerId)424 private void trace(String op, int timerId) { 425 final String label = formatSimple("%s(%d)", op, timerId); 426 Trace.instantForTrack(TRACE_TAG, TRACK, label); 427 if (DEBUG) Log.i(TAG, label); 428 } 429 430 /** 431 * Generate a trace point with a pid and uid but no timer ID. 432 */ trace(String op, int pid, int uid)433 private static void trace(String op, int pid, int uid) { 434 final String label = formatSimple("%s(%d,%d)", op, pid, uid); 435 Trace.instantForTrack(TRACE_TAG, TRACK, label); 436 if (DEBUG) Log.i(TAG, label); 437 } 438 439 /** 440 * The FeatureSwitch class provides a quick switch between feature-enabled behavior and 441 * feature-disabled behavior. 442 */ 443 private abstract class FeatureSwitch { start(@onNull V arg, int pid, int uid, long timeoutMs)444 abstract void start(@NonNull V arg, int pid, int uid, long timeoutMs); 445 cancel(@onNull V arg)446 abstract boolean cancel(@NonNull V arg); 447 448 @Nullable accept(@onNull V arg)449 abstract TimerLock accept(@NonNull V arg); 450 discard(@onNull V arg)451 abstract boolean discard(@NonNull V arg); 452 release(@onNull TimerLock timer)453 abstract void release(@NonNull TimerLock timer); 454 enabled()455 abstract boolean enabled(); 456 dump(IndentingPrintWriter pw, boolean verbose)457 abstract void dump(IndentingPrintWriter pw, boolean verbose); 458 close()459 abstract void close(); 460 } 461 462 /** 463 * The FeatureDisabled class bypasses almost all AnrTimer logic. It is used when the AnrTimer 464 * service is disabled via Flags.anrTimerService(). 465 */ 466 private class FeatureDisabled extends FeatureSwitch { 467 /** Start a timer by sending a message to the client's handler. */ 468 @Override start(@onNull V arg, int pid, int uid, long timeoutMs)469 void start(@NonNull V arg, int pid, int uid, long timeoutMs) { 470 final Message msg = mHandler.obtainMessage(mWhat, arg); 471 mHandler.sendMessageDelayed(msg, timeoutMs); 472 } 473 474 /** Cancel a timer by removing the message from the client's handler. */ 475 @Override cancel(@onNull V arg)476 boolean cancel(@NonNull V arg) { 477 mHandler.removeMessages(mWhat, arg); 478 return true; 479 } 480 481 /** accept() is a no-op when the feature is disabled. */ 482 @Override 483 @Nullable accept(@onNull V arg)484 TimerLock accept(@NonNull V arg) { 485 return null; 486 } 487 488 /** discard() is a no-op when the feature is disabled. */ 489 @Override discard(@onNull V arg)490 boolean discard(@NonNull V arg) { 491 return true; 492 } 493 494 /** release() is a no-op when the feature is disabled. */ 495 @Override release(@onNull TimerLock timer)496 void release(@NonNull TimerLock timer) { 497 } 498 499 /** The feature is not enabled. */ 500 @Override enabled()501 boolean enabled() { 502 return false; 503 } 504 505 /** Dump the limited statistics captured when the feature is disabled. */ 506 @Override dump(IndentingPrintWriter pw, boolean verbose)507 void dump(IndentingPrintWriter pw, boolean verbose) { 508 synchronized (mLock) { 509 pw.format("started=%d maxStarted=%d running=%d expired=%d errors=%d\n", 510 mTotalStarted, mMaxStarted, mTimerIdMap.size(), 511 mTotalExpired, mTotalErrors); 512 } 513 } 514 515 /** close() is a no-op when the feature is disabled. */ 516 @Override close()517 void close() { 518 } 519 } 520 521 /** 522 * A static list of AnrTimer instances. The list is traversed by dumpsys. Only instances 523 * using native resources are included. 524 */ 525 @GuardedBy("sAnrTimerList") 526 private static final LongSparseArray<WeakReference<AnrTimer>> sAnrTimerList = 527 new LongSparseArray<>(); 528 529 /** 530 * The FeatureEnabled class enables the AnrTimer logic. It is used when the AnrTimer service 531 * is enabled via Flags.anrTimerService(). 532 */ 533 private class FeatureEnabled extends FeatureSwitch { 534 535 /** 536 * The native timer that supports this instance. The value is set to non-zero when the 537 * native timer is created and it is set back to zero when the native timer is freed. 538 */ 539 private long mNative = 0; 540 541 /** The total number of timers that were restarted without an explicit cancel. */ 542 @GuardedBy("mLock") 543 private int mTotalRestarted = 0; 544 545 /** Create the native AnrTimerService that will host all timers from this instance. */ FeatureEnabled()546 FeatureEnabled() { 547 mNative = nativeAnrTimerCreate(mLabel, 548 mArgs.mExtend, 549 mArgs.mFreeze && mArgs.mInjector.freezerEnabled()); 550 if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); 551 synchronized (sAnrTimerList) { 552 sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); 553 } 554 } 555 556 /** 557 * Start a timer. 558 */ 559 @Override start(@onNull V arg, int pid, int uid, long timeoutMs)560 void start(@NonNull V arg, int pid, int uid, long timeoutMs) { 561 synchronized (mLock) { 562 // If there is an existing timer, cancel it. This is a nop if the timer does not 563 // exist. 564 if (cancel(arg)) mTotalRestarted++; 565 566 final int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs); 567 if (timerId > 0) { 568 mTimerIdMap.put(arg, timerId); 569 mTimerArgMap.put(timerId, arg); 570 mTotalStarted++; 571 mMaxStarted = Math.max(mMaxStarted, mTimerIdMap.size()); 572 } else { 573 throw new RuntimeException("unable to start timer"); 574 } 575 } 576 } 577 578 /** 579 * Cancel a timer. No error is reported if the timer is not found because some clients 580 * cancel timers from common code that runs even if a timer was never started. 581 */ 582 @Override cancel(@onNull V arg)583 boolean cancel(@NonNull V arg) { 584 synchronized (mLock) { 585 Integer timer = removeLocked(arg); 586 if (timer == null) { 587 return false; 588 } 589 if (!nativeAnrTimerCancel(mNative, timer)) { 590 // There may be an expiration message in flight. Cancel it. 591 mHandler.removeMessages(mWhat, arg); 592 return false; 593 } 594 return true; 595 } 596 } 597 598 /** 599 * Accept a timer in the framework-level handler. The timeout has been accepted and the 600 * client's timeout handler is executing. If the function returns a non-null TimerLock then 601 * the associated process may have been paused (or otherwise modified in preparation for 602 * debugging). The TimerLock must be closed to allow the process to continue, or to be 603 * dumped in an AnrReport. 604 */ 605 @Override 606 @Nullable accept(@onNull V arg)607 TimerLock accept(@NonNull V arg) { 608 synchronized (mLock) { 609 Integer timer = removeLocked(arg); 610 if (timer == null) { 611 notFoundLocked("accept", arg); 612 return null; 613 } 614 boolean accepted = nativeAnrTimerAccept(mNative, timer); 615 trace("accept", timer); 616 // If "accepted" is true then the native layer has pending operations against this 617 // timer. Wrap the timer ID in a TimerLock and return it to the caller. If 618 // "accepted" is false then the native later does not have any pending operations. 619 return accepted ? new TimerLock(timer) : null; 620 } 621 } 622 623 /** 624 * Discard a timer in the framework-level handler. For whatever reason, the timer is no 625 * longer interesting. No statistics are collected. Return false if the time was not 626 * found. 627 */ 628 @Override discard(@onNull V arg)629 boolean discard(@NonNull V arg) { 630 synchronized (mLock) { 631 Integer timer = removeLocked(arg); 632 if (timer == null) { 633 notFoundLocked("discard", arg); 634 return false; 635 } 636 nativeAnrTimerDiscard(mNative, timer); 637 trace("discard", timer); 638 return true; 639 } 640 } 641 642 /** 643 * Unfreeze an app that was frozen because its timer had expired. This method catches 644 * errors that might be thrown by the unfreeze method. This method does nothing if 645 * freezing is not enabled or if the AnrTimer never froze the timer. Note that the native 646 * release method returns false only if the timer's process was frozen, is still frozen, 647 * and could not be unfrozen. 648 */ 649 @Override release(@onNull TimerLock t)650 void release(@NonNull TimerLock t) { 651 if (t.mTimerId == 0) return; 652 if (!nativeAnrTimerRelease(mNative, t.mTimerId)) { 653 Log.e(TAG, "failed to release id=" + t.mTimerId, new Exception(TAG)); 654 } 655 } 656 657 /** The feature is enabled. */ 658 @Override enabled()659 boolean enabled() { 660 return true; 661 } 662 663 /** Dump statistics from the native layer. */ 664 @Override dump(IndentingPrintWriter pw, boolean verbose)665 void dump(IndentingPrintWriter pw, boolean verbose) { 666 synchronized (mLock) { 667 if (mNative == 0) { 668 pw.println("closed"); 669 return; 670 } 671 String[] nativeDump = nativeAnrTimerDump(mNative); 672 if (nativeDump == null) { 673 pw.println("no-data"); 674 return; 675 } 676 for (String s : nativeDump) { 677 pw.println(s); 678 } 679 // The following counter is only available at the Java level. 680 pw.println("restarted:" + mTotalRestarted); 681 } 682 } 683 684 /** Free native resources. */ 685 @Override close()686 void close() { 687 // Remove self from the list of active timers. 688 synchronized (sAnrTimerList) { 689 sAnrTimerList.remove(mNative); 690 } 691 synchronized (mLock) { 692 if (mNative != 0) nativeAnrTimerClose(mNative); 693 mNative = 0; 694 } 695 } 696 697 /** 698 * Delete the entries associated with arg from the maps and return the ID of the timer, if 699 * any. 700 */ 701 @GuardedBy("mLock") removeLocked(V arg)702 private Integer removeLocked(V arg) { 703 Integer r = mTimerIdMap.remove(arg); 704 if (r != null) { 705 mTimerArgMap.remove(r); 706 } 707 return r; 708 } 709 } 710 711 /** 712 * Start a timer associated with arg. The same object must be used to cancel, accept, or 713 * discard a timer later. If a timer already exists with the same arg, then the existing timer 714 * is canceled and a new timer is created. The timeout is signed but negative delays are 715 * nonsensical. Rather than throw an exception, timeouts less than 0ms are forced to 0ms. This 716 * allows a client to deliver an immediate timeout via the AnrTimer. 717 * 718 * @param arg The key by which the timer is known. This is never examined or modified. 719 * @param timeoutMs The timer timeout, in milliseconds. 720 */ start(@onNull V arg, long timeoutMs)721 public void start(@NonNull V arg, long timeoutMs) { 722 if (timeoutMs < 0) timeoutMs = 0; 723 mFeature.start(arg, getPid(arg), getUid(arg), timeoutMs); 724 } 725 726 /** 727 * Cancel the running timer associated with arg. The timer is forgotten. If the timer has 728 * expired, the call is treated as a discard. The function returns true if a running timer was 729 * found, and false if an expired timer was found or if no timer was found. After this call, 730 * the timer does not exist. 731 * 732 * Note: the return value is always true if the feature is not enabled. 733 * 734 * @param arg The key by which the timer is known. This is never examined or modified. 735 * @return True if a running timer was canceled. 736 */ cancel(@onNull V arg)737 public boolean cancel(@NonNull V arg) { 738 return mFeature.cancel(arg); 739 } 740 741 /** 742 * Accept the expired timer associated with arg. This indicates that the caller considers the 743 * timer expiration to be a true ANR. (See {@link #discard} for an alternate response.) The 744 * function returns a {@link TimerLock} if an expired timer was found and null otherwise. 745 * After this call, the timer does not exist. It is an error to accept a running timer, 746 * however, the running timer will be canceled. 747 * 748 * If a non-null TimerLock is returned, the TimerLock must be closed before the target process 749 * is dumped (for an ANR report) or continued. 750 * 751 * Note: the return value is always null if the feature is not enabled. 752 * 753 * @param arg The key by which the timer is known. This is never examined or modified. 754 * @return A TimerLock if an expired timer was accepted. 755 */ 756 @Nullable accept(@onNull V arg)757 public TimerLock accept(@NonNull V arg) { 758 return mFeature.accept(arg); 759 } 760 761 /** 762 * Discard the expired timer associated with arg. This indicates that the caller considers the 763 * timer expiration to be a false ANR. ((See {@link #accept} for an alternate response.) One 764 * reason to discard an expired timer is if the process being timed was also being debugged: 765 * such a process could be stopped at a breakpoint and its failure to respond would not be an 766 * error. After this call thie timer does not exist. It is an error to discard a running timer, 767 * however the running timer will be canceled. 768 * 769 * Note: the return value is always true if the feature is not enabled. 770 * 771 * @param arg The key by which the timer is known. This is never examined or modified. 772 * @return True if an expired timer was discarded. 773 */ discard(@onNull V arg)774 public boolean discard(@NonNull V arg) { 775 return mFeature.discard(arg); 776 } 777 778 /** 779 * Release an expired timer. 780 */ release(@onNull TimerLock t)781 private void release(@NonNull TimerLock t) { 782 mFeature.release(t); 783 } 784 785 /** 786 * The notifier that a timer has fired. The timerId and original pid/uid are supplied. The 787 * elapsed time is the actual time since the timer was scheduled, which may be different from 788 * the original timeout if the timer was extended or if other delays occurred. This method 789 * takes mLock so that a timer cannot expire in the middle of another operation (like start or 790 * cancel). 791 * 792 * This method is called from native code. The function must return true if the expiration 793 * message is delivered to the upper layers and false if it could not be delivered. 794 */ 795 @Keep expire(int timerId, int pid, int uid, long elapsedMs)796 private boolean expire(int timerId, int pid, int uid, long elapsedMs) { 797 trace("expired", timerId, pid, uid, elapsedMs); 798 V arg = null; 799 synchronized (mLock) { 800 arg = mTimerArgMap.get(timerId); 801 if (arg == null) { 802 Log.e(TAG, formatSimple("failed to expire timer %s:%d : arg not found", 803 mLabel, timerId)); 804 mTotalErrors++; 805 return false; 806 } 807 mTotalExpired++; 808 } 809 mHandler.sendMessage(Message.obtain(mHandler, mWhat, arg)); 810 return true; 811 } 812 813 /** 814 * Close the object and free any native resources. 815 */ close()816 public void close() { 817 mFeature.close(); 818 } 819 820 /** 821 * Ensure any native resources are freed when the object is GC'ed. Best practice is to close 822 * the object explicitly, but overriding finalize() avoids accidental leaks. 823 */ 824 @SuppressWarnings("Finalize") 825 @Override finalize()826 protected void finalize() throws Throwable { 827 close(); 828 super.finalize(); 829 } 830 831 /** 832 * Dump a single AnrTimer. 833 */ dump(IndentingPrintWriter pw)834 private void dump(IndentingPrintWriter pw) { 835 synchronized (mLock) { 836 pw.format("timer: %s\n", mLabel); 837 pw.increaseIndent(); 838 mFeature.dump(pw, false); 839 pw.decreaseIndent(); 840 } 841 } 842 843 /** 844 * Enable or disable debugging. 845 */ debug(boolean f)846 static void debug(boolean f) { 847 DEBUG = f; 848 } 849 850 /** 851 * The current time in milliseconds. 852 */ now()853 private static long now() { 854 return SystemClock.uptimeMillis(); 855 } 856 857 /** 858 * Dump all errors to the output stream. 859 */ dumpErrors(IndentingPrintWriter ipw)860 private static void dumpErrors(IndentingPrintWriter ipw) { 861 Error errors[]; 862 synchronized (sErrors) { 863 if (sErrors.size() == 0) return; 864 errors = sErrors.toArray(); 865 } 866 ipw.println("Errors"); 867 ipw.increaseIndent(); 868 for (int i = 0; i < errors.length; i++) { 869 if (errors[i] != null) errors[i].dump(ipw, i); 870 } 871 ipw.decreaseIndent(); 872 } 873 874 /** 875 * Log an error. A limited stack trace leading to the client call that triggered the error is 876 * recorded. The stack trace assumes that this method is not called directly. 877 * 878 * If DEBUG is true, a log message is generated as well. 879 */ 880 @GuardedBy("mLock") recordErrorLocked(String operation, String errorMsg, Object arg)881 private void recordErrorLocked(String operation, String errorMsg, Object arg) { 882 StackTraceElement[] s = Thread.currentThread().getStackTrace(); 883 final String what = Objects.toString(arg); 884 // The copy range starts at the caller of the timer operation, and includes three levels. 885 // This should be enough to isolate the location of the call. 886 StackTraceElement[] location = Arrays.copyOfRange(s, 6, 9); 887 synchronized (sErrors) { 888 sErrors.append(new Error(errorMsg, operation, mLabel, location, what)); 889 } 890 if (DEBUG) Log.w(TAG, operation + " " + errorMsg + " " + mLabel + " timer " + what); 891 mTotalErrors++; 892 } 893 894 /** Record an error about a timer not found. */ 895 @GuardedBy("mLock") notFoundLocked(String operation, Object arg)896 private void notFoundLocked(String operation, Object arg) { 897 recordErrorLocked(operation, "notFound", arg); 898 } 899 900 /** Compare two AnrTimers in display order. */ 901 private static final Comparator<AnrTimer> sComparator = 902 Comparator.nullsLast(new Comparator<>() { 903 @Override 904 public int compare(AnrTimer o1, AnrTimer o2) { 905 return o1.mLabel.compareTo(o2.mLabel); 906 }}); 907 908 /** Dumpsys output, allowing for overrides. */ 909 @VisibleForTesting dump(@onNull PrintWriter pw, boolean verbose, @NonNull Injector injector)910 static void dump(@NonNull PrintWriter pw, boolean verbose, @NonNull Injector injector) { 911 if (!injector.serviceEnabled()) return; 912 913 final IndentingPrintWriter ipw = new IndentingPrintWriter(pw); 914 ipw.println("AnrTimer statistics"); 915 ipw.increaseIndent(); 916 synchronized (sAnrTimerList) { 917 // Find the currently live instances and sort them by their label. The goal is to 918 // have consistent output ordering. 919 final int size = sAnrTimerList.size(); 920 AnrTimer[] active = new AnrTimer[size]; 921 int valid = 0; 922 for (int i = 0; i < size; i++) { 923 AnrTimer a = sAnrTimerList.valueAt(i).get(); 924 if (a != null) active[valid++] = a; 925 } 926 Arrays.sort(active, 0, valid, sComparator); 927 for (int i = 0; i < valid; i++) { 928 if (active[i] != null) active[i].dump(ipw); 929 } 930 } 931 if (verbose) dumpErrors(ipw); 932 ipw.format("AnrTimerEnd\n"); 933 ipw.decreaseIndent(); 934 } 935 936 /** Dumpsys output. There is no output if the feature is not enabled. */ dump(@onNull PrintWriter pw, boolean verbose)937 public static void dump(@NonNull PrintWriter pw, boolean verbose) { 938 dump(pw, verbose, sDefaultInjector); 939 } 940 941 /** 942 * Set a trace specification. The input is a set of strings. On success, the function pushes 943 * the trace specification to all timers, and then returns a response message. On failure, 944 * the function throws IllegalArgumentException and tracing is disabled. 945 * 946 * An empty specification has no effect other than returning the current trace specification. 947 */ 948 @Nullable traceTimers(@ullable String[] spec)949 public static String traceTimers(@Nullable String[] spec) { 950 return nativeAnrTimerTrace(spec); 951 } 952 953 /** 954 * Return true if the native timers are supported. Native timers are supported if the method 955 * nativeAnrTimerSupported() can be executed and it returns true. 956 */ nativeTimersSupported()957 public static boolean nativeTimersSupported() { 958 try { 959 return nativeAnrTimerSupported(); 960 } catch (java.lang.UnsatisfiedLinkError e) { 961 return false; 962 } 963 } 964 965 /** 966 * Native methods 967 */ 968 969 /** Return true if the native AnrTimer code is operational. */ nativeAnrTimerSupported()970 private static native boolean nativeAnrTimerSupported(); 971 972 /** 973 * Create a new native timer with the given name and flags. The name is only for logging. 974 * Unlike the other methods, this is an instance method: the "this" parameter is passed into 975 * the native layer. 976 */ nativeAnrTimerCreate(String name, boolean extend, boolean freeze)977 private native long nativeAnrTimerCreate(String name, boolean extend, boolean freeze); 978 979 /** Release the native resources. No further operations are premitted. */ nativeAnrTimerClose(long service)980 private static native int nativeAnrTimerClose(long service); 981 982 /** Start a timer and return its ID. Zero is returned on error. */ nativeAnrTimerStart(long service, int pid, int uid, long timeoutMs)983 private static native int nativeAnrTimerStart(long service, int pid, int uid, long timeoutMs); 984 985 /** 986 * Cancel a timer by ID. Return true if the timer was running and canceled. Return false if 987 * the timer was not found or if the timer had already expired. 988 */ nativeAnrTimerCancel(long service, int timerId)989 private static native boolean nativeAnrTimerCancel(long service, int timerId); 990 991 /** 992 * Accept an expired timer by ID. Return true if the timer must be released. Return false if 993 * the native layer is completely finished with this timer. 994 */ nativeAnrTimerAccept(long service, int timerId)995 private static native boolean nativeAnrTimerAccept(long service, int timerId); 996 997 /** Discard an expired timer by ID. Return true if the timer was found. */ nativeAnrTimerDiscard(long service, int timerId)998 private static native boolean nativeAnrTimerDiscard(long service, int timerId); 999 1000 /** 1001 * Release (unfreeze) the process associated with the timer, if the process was previously 1002 * frozen by the service. The function returns false if three conditions are true: the timer 1003 * does exist, the timer's process was frozen, and the timer's process could not be unfrozen. 1004 * Otherwise, the function returns true. In other words, a return value of value means there 1005 * is a process that is unexpectedly stuck in the frozen state. 1006 */ nativeAnrTimerRelease(long service, int timerId)1007 private static native boolean nativeAnrTimerRelease(long service, int timerId); 1008 1009 /** 1010 * Configure tracing. The input array is a set of words pulled from the command line. All 1011 * parsing happens inside the native layer. The function returns a string which is either an 1012 * error message (so nothing happened) or the current configuration after applying the config. 1013 * Passing an null array or an empty array simply returns the current configuration. 1014 * The function returns null if the native layer is not implemented. 1015 */ nativeAnrTimerTrace(@ullable String[] config)1016 private static native @Nullable String nativeAnrTimerTrace(@Nullable String[] config); 1017 1018 /** Retrieve runtime dump information from the native layer. */ nativeAnrTimerDump(long service)1019 private static native String[] nativeAnrTimerDump(long service); 1020 } 1021