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