summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java3
-rw-r--r--services/core/java/com/android/server/utils/AnrTimer.java84
-rw-r--r--services/core/jni/com_android_server_utils_AnrTimer.cpp51
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java2
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) {