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