diff options
4 files changed, 67 insertions, 73 deletions
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index 1379c9b5cb68..935282b59257 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -1336,7 +1336,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private class BroadcastAnrTimer extends AnrTimer<BroadcastProcessQueue> { BroadcastAnrTimer(@NonNull Handler handler) { super(Objects.requireNonNull(handler), - MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT", true); + MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT", + new AnrTimer.Args().extend(true)); } @Override diff --git a/services/core/java/com/android/server/utils/AnrTimer.java b/services/core/java/com/android/server/utils/AnrTimer.java index 12db21dbe41a..c605a47f5635 100644 --- a/services/core/java/com/android/server/utils/AnrTimer.java +++ b/services/core/java/com/android/server/utils/AnrTimer.java @@ -140,6 +140,29 @@ public abstract class AnrTimer<V> implements AutoCloseable { private static final Injector sDefaultInjector = new Injector(); /** + * This class provides build-style arguments to an AnrTimer constructor. This simplifies the + * number of AnrTimer constructors needed, especially as new options are added. + */ + public static class Args { + /** The Injector (used only for testing). */ + private Injector mInjector = AnrTimer.sDefaultInjector; + + /** Grant timer extensions when the system is heavily loaded. */ + private boolean mExtend = false; + + // This is only used for testing, so it is limited to package visibility. + Args injector(@NonNull Injector injector) { + mInjector = injector; + return this; + } + + public Args extend(boolean flag) { + mExtend = flag; + return this; + } + } + + /** * An error is defined by its issue, the operation that detected the error, the tag of the * affected service, a short stack of the bad call, and the stringified arg associated with * the error. @@ -229,11 +252,8 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** A label that identifies the AnrTimer associated with a Timer in log messages. */ private final String mLabel; - /** Whether this timer instance supports extending timeouts. */ - private final boolean mExtend; - - /** The injector used to create this instance. This is only used for testing. */ - private final Injector mInjector; + /** The configuration for this instance. */ + private final Args mArgs; /** The top-level switch for the feature enabled or disabled. */ private final FeatureSwitch mFeature; @@ -254,18 +274,14 @@ public abstract class AnrTimer<V> implements AutoCloseable { * @param handler The handler to which the expiration message will be delivered. * @param what The "what" parameter for the expiration message. * @param label A name for this instance. - * @param extend A flag to indicate if expired timers can be granted extensions. - * @param injector An injector to provide overrides for testing. + * @param args Configuration information for this instance. */ - @VisibleForTesting - AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend, - @NonNull Injector injector) { + public AnrTimer(@NonNull Handler handler, int what, @NonNull String label, @NonNull Args args) { mHandler = handler; mWhat = what; mLabel = label; - mExtend = extend; - mInjector = injector; - boolean enabled = mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); + mArgs = args; + boolean enabled = args.mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); mFeature = createFeatureSwitch(enabled); } @@ -288,29 +304,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { } /** - * Create one AnrTimer instance. The instance is given a handler and a "what". Individual - * timers are started with {@link #start}. If a timer expires, then a {@link Message} is sent - * immediately to the handler with {@link Message.what} set to what and {@link Message.obj} set - * to the timer key. - * - * AnrTimer instances have a label, which must be unique. The label is used for reporting and - * debug. - * - * If an individual timer expires internally, and the "extend" parameter is true, then the - * AnrTimer may extend the individual timer rather than immediately delivering the timeout to - * the client. The extension policy is not part of the instance. - * - * @param handler The handler to which the expiration message will be delivered. - * @param what The "what" parameter for the expiration message. - * @param label A name for this instance. - * @param extend A flag to indicate if expired timers can be granted extensions. - */ - public AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend) { - this(handler, what, label, extend, sDefaultInjector); - } - - /** - * Create an AnrTimer instance with the default {@link #Injector} and with extensions disabled. + * Create an AnrTimer instance with the default {@link #Injector} and the default configuration. * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description. * * @param handler The handler to which the expiration message will be delivered. @@ -318,7 +312,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { * @param label A name for this instance. */ public AnrTimer(@NonNull Handler handler, int what, @NonNull String label) { - this(handler, what, label, false); + this(handler, what, label, new Args()); } /** @@ -449,7 +443,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Fetch the native tag (an integer) for the given label. */ FeatureEnabled() { - mNative = nativeAnrTimerCreate(mLabel); + mNative = nativeAnrTimerCreate(mLabel, mArgs.mExtend); if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); synchronized (sAnrTimerList) { sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); @@ -466,7 +460,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // exist. if (cancel(arg)) mTotalRestarted++; - int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs, mExtend); + int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs); if (timerId > 0) { mTimerIdMap.put(arg, timerId); mTimerArgMap.put(timerId, arg); @@ -828,19 +822,17 @@ public abstract class AnrTimer<V> implements AutoCloseable { private static native boolean nativeAnrTimerSupported(); /** - * Create a new native timer with the given key and name. The key is not used by the native - * code but it is returned to the Java layer in the expiration handler. The name is only for - * logging. Unlike the other methods, this is an instance method: the "this" parameter is - * passed into the native layer. + * Create a new native timer with the given name and flags. The name is only for logging. + * Unlike the other methods, this is an instance method: the "this" parameter is passed into + * the native layer. */ - private native long nativeAnrTimerCreate(String name); + private native long nativeAnrTimerCreate(String name, boolean extend); /** Release the native resources. No further operations are premitted. */ private static native int nativeAnrTimerClose(long service); /** Start a timer and return its ID. Zero is returned on error. */ - private static native int nativeAnrTimerStart(long service, int pid, int uid, long timeoutMs, - boolean extend); + private static native int nativeAnrTimerStart(long service, int pid, int uid, long timeoutMs); /** * Cancel a timer by ID. Return true if the timer was running and canceled. Return false if diff --git a/services/core/jni/com_android_server_utils_AnrTimer.cpp b/services/core/jni/com_android_server_utils_AnrTimer.cpp index 6509958defda..f0bd0378a853 100644 --- a/services/core/jni/com_android_server_utils_AnrTimer.cpp +++ b/services/core/jni/com_android_server_utils_AnrTimer.cpp @@ -130,7 +130,8 @@ class AnrTimerService { * constructor is also given the notifier callback, and two cookies for the callback: the * traditional void* and an int. */ - AnrTimerService(char const* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker*); + AnrTimerService(char const* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker*, + bool extend); // Delete the service and clean up memory. ~AnrTimerService(); @@ -138,7 +139,7 @@ class AnrTimerService { // Start a timer and return the associated timer ID. It does not matter if the same pid/uid // are already in the running list. Once start() is called, one of cancel(), accept(), or // discard() must be called to clean up the internal data structures. - timer_id_t start(int pid, int uid, nsecs_t timeout, bool extend); + timer_id_t start(int pid, int uid, nsecs_t timeout); // Cancel a timer and remove it from all lists. This is called when the event being timed // has occurred. If the timer was Running, the function returns true. The other @@ -192,6 +193,9 @@ class AnrTimerService { void* notifierCookie_; jweak notifierObject_; + // True if extensions can be granted to expired timers. + const bool extend_; + // The global lock mutable Mutex lock_; @@ -636,12 +640,13 @@ class AnrTimerService::Ticker { std::atomic<size_t> AnrTimerService::Ticker::idGen_; -AnrTimerService::AnrTimerService(char const* label, - notifier_t notifier, void* cookie, jweak jtimer, Ticker* ticker) : +AnrTimerService::AnrTimerService(char const* label, notifier_t notifier, void* cookie, + jweak jtimer, Ticker* ticker, bool extend) : label_(label), notifier_(notifier), notifierCookie_(cookie), notifierObject_(jtimer), + extend_(extend), ticker_(ticker) { // Zero the statistics @@ -666,11 +671,10 @@ char const *AnrTimerService::statusString(Status s) { return "unknown"; } -AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, - nsecs_t timeout, bool extend) { +AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, nsecs_t timeout) { ALOGI_IF(DEBUG, "starting"); AutoMutex _l(lock_); - Timer t(pid, uid, timeout, extend); + Timer t(pid, uid, timeout, extend_); insert(t); counters_.started++; @@ -826,7 +830,8 @@ bool nativeSupportEnabled = false; /** * Singleton/globals for the anr timer. Among other things, this includes a Ticker* and a use * count. The JNI layer creates a single Ticker for all operational AnrTimers. The Ticker is - * created when the first AnrTimer is created, and is deleted when the last AnrTimer is closed. + * created when the first AnrTimer is created; this means that the Ticker is only created if + * native anr timers are used. */ static Mutex gAnrLock; struct AnrArgs { @@ -834,7 +839,6 @@ struct AnrArgs { jmethodID func = NULL; JavaVM* vm = NULL; AnrTimerService::Ticker* ticker = nullptr; - int tickerUseCount = 0;; }; static AnrArgs gAnrArgs; @@ -863,18 +867,17 @@ jboolean anrTimerSupported(JNIEnv* env, jclass) { return nativeSupportEnabled; } -jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname) { +jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, jboolean extend) { if (!nativeSupportEnabled) return 0; AutoMutex _l(gAnrLock); - if (!gAnrArgs.ticker) { + if (gAnrArgs.ticker == nullptr) { gAnrArgs.ticker = new AnrTimerService::Ticker(); } - gAnrArgs.tickerUseCount++; ScopedUtfChars name(env, jname); jobject timer = env->NewWeakGlobalRef(jtimer); - AnrTimerService* service = - new AnrTimerService(name.c_str(), anrNotify, &gAnrArgs, timer, gAnrArgs.ticker); + AnrTimerService* service = new AnrTimerService(name.c_str(), + anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend); return reinterpret_cast<jlong>(service); } @@ -889,19 +892,14 @@ jint anrTimerClose(JNIEnv* env, jclass, jlong ptr) { AnrTimerService *s = toService(ptr); env->DeleteWeakGlobalRef(s->jtimer()); delete s; - if (--gAnrArgs.tickerUseCount <= 0) { - delete gAnrArgs.ticker; - gAnrArgs.ticker = nullptr; - } return 0; } -jint anrTimerStart(JNIEnv* env, jclass, jlong ptr, - jint pid, jint uid, jlong timeout, jboolean extend) { +jint anrTimerStart(JNIEnv* env, jclass, jlong ptr, jint pid, jint uid, jlong timeout) { if (!nativeSupportEnabled) return 0; // On the Java side, timeouts are expressed in milliseconds and must be converted to // nanoseconds before being passed to the library code. - return toService(ptr)->start(pid, uid, milliseconds_to_nanoseconds(timeout), extend); + return toService(ptr)->start(pid, uid, milliseconds_to_nanoseconds(timeout)); } jboolean anrTimerCancel(JNIEnv* env, jclass, jlong ptr, jint timerId) { @@ -932,9 +930,9 @@ jobjectArray anrTimerDump(JNIEnv *env, jclass, jlong ptr) { static const JNINativeMethod methods[] = { {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, - {"nativeAnrTimerCreate", "(Ljava/lang/String;)J", (void*) anrTimerCreate}, + {"nativeAnrTimerCreate", "(Ljava/lang/String;Z)J", (void*) anrTimerCreate}, {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, - {"nativeAnrTimerStart", "(JIIJZ)I", (void*) anrTimerStart}, + {"nativeAnrTimerStart", "(JIIJ)I", (void*) anrTimerStart}, {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, @@ -948,13 +946,16 @@ int register_android_server_utils_AnrTimer(JNIEnv* env) static const char *className = "com/android/server/utils/AnrTimer"; jniRegisterNativeMethods(env, className, methods, NELEM(methods)); + nativeSupportEnabled = NATIVE_SUPPORT; + + // Do not perform any further initialization if native support is not enabled. + if (!nativeSupportEnabled) return 0; + jclass service = FindClassOrDie(env, className); gAnrArgs.clazz = MakeGlobalRefOrDie(env, service); gAnrArgs.func = env->GetMethodID(gAnrArgs.clazz, "expire", "(IIIJ)Z"); env->GetJavaVM(&gAnrArgs.vm); - nativeSupportEnabled = NATIVE_SUPPORT; - return 0; } diff --git a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java index 06c3db87ed2d..b09e9b119984 100644 --- a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java @@ -129,7 +129,7 @@ public class AnrTimerTest { */ private class TestAnrTimer extends AnrTimer<TestArg> { private TestAnrTimer(Handler h, int key, String tag) { - super(h, key, tag, false, new TestInjector()); + super(h, key, tag, new AnrTimer.Args().injector(new TestInjector())); } TestAnrTimer(Helper helper) { |