• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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