Loading services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -1336,7 +1336,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private class BroadcastAnrTimer extends AnrTimer<BroadcastProcessQueue> { private class BroadcastAnrTimer extends AnrTimer<BroadcastProcessQueue> { BroadcastAnrTimer(@NonNull Handler handler) { BroadcastAnrTimer(@NonNull Handler handler) { super(Objects.requireNonNull(handler), super(Objects.requireNonNull(handler), MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT", true); MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT", new AnrTimer.Args().extend(true)); } } @Override @Override Loading services/core/java/com/android/server/utils/AnrTimer.java +38 −46 Original line number Original line Diff line number Diff line Loading @@ -139,6 +139,29 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** The default injector. */ /** The default injector. */ private static final Injector sDefaultInjector = new Injector(); 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 * 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 * affected service, a short stack of the bad call, and the stringified arg associated with Loading Loading @@ -229,11 +252,8 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** A label that identifies the AnrTimer associated with a Timer in log messages. */ /** A label that identifies the AnrTimer associated with a Timer in log messages. */ private final String mLabel; private final String mLabel; /** Whether this timer instance supports extending timeouts. */ /** The configuration for this instance. */ private final boolean mExtend; private final Args mArgs; /** The injector used to create this instance. This is only used for testing. */ private final Injector mInjector; /** The top-level switch for the feature enabled or disabled. */ /** The top-level switch for the feature enabled or disabled. */ private final FeatureSwitch mFeature; private final FeatureSwitch mFeature; Loading @@ -254,18 +274,14 @@ public abstract class AnrTimer<V> implements AutoCloseable { * @param handler The handler to which the expiration message will be delivered. * @param handler The handler to which the expiration message will be delivered. * @param what The "what" parameter for the expiration message. * @param what The "what" parameter for the expiration message. * @param label A name for this instance. * @param label A name for this instance. * @param extend A flag to indicate if expired timers can be granted extensions. * @param args Configuration information for this instance. * @param injector An injector to provide overrides for testing. */ */ @VisibleForTesting public AnrTimer(@NonNull Handler handler, int what, @NonNull String label, @NonNull Args args) { AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend, @NonNull Injector injector) { mHandler = handler; mHandler = handler; mWhat = what; mWhat = what; mLabel = label; mLabel = label; mExtend = extend; mArgs = args; mInjector = injector; boolean enabled = args.mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); boolean enabled = mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); mFeature = createFeatureSwitch(enabled); mFeature = createFeatureSwitch(enabled); } } Loading @@ -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 * Create an AnrTimer instance with the default {@link #Injector} and the default configuration. * 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. * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description. * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description. * * * @param handler The handler to which the expiration message will be delivered. * @param handler The handler to which the expiration message will be delivered. Loading @@ -318,7 +312,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { * @param label A name for this instance. * @param label A name for this instance. */ */ public AnrTimer(@NonNull Handler handler, int what, @NonNull String label) { public AnrTimer(@NonNull Handler handler, int what, @NonNull String label) { this(handler, what, label, false); this(handler, what, label, new Args()); } } /** /** Loading Loading @@ -449,7 +443,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Fetch the native tag (an integer) for the given label. */ /** Fetch the native tag (an integer) for the given label. */ FeatureEnabled() { FeatureEnabled() { mNative = nativeAnrTimerCreate(mLabel); mNative = nativeAnrTimerCreate(mLabel, mArgs.mExtend); if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); synchronized (sAnrTimerList) { synchronized (sAnrTimerList) { sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); Loading @@ -466,7 +460,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // exist. // exist. if (cancel(arg)) mTotalRestarted++; if (cancel(arg)) mTotalRestarted++; int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs, mExtend); int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs); if (timerId > 0) { if (timerId > 0) { mTimerIdMap.put(arg, timerId); mTimerIdMap.put(arg, timerId); mTimerArgMap.put(timerId, arg); mTimerArgMap.put(timerId, arg); Loading Loading @@ -828,19 +822,17 @@ public abstract class AnrTimer<V> implements AutoCloseable { private static native boolean nativeAnrTimerSupported(); private static native boolean nativeAnrTimerSupported(); /** /** * Create a new native timer with the given key and name. The key is not used by the native * Create a new native timer with the given name and flags. The name is only for logging. * code but it is returned to the Java layer in the expiration handler. The name is only for * Unlike the other methods, this is an instance method: the "this" parameter is passed into * logging. Unlike the other methods, this is an instance method: the "this" parameter is * the native layer. * 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. */ /** Release the native resources. No further operations are premitted. */ private static native int nativeAnrTimerClose(long service); private static native int nativeAnrTimerClose(long service); /** Start a timer and return its ID. Zero is returned on error. */ /** 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, private static native int nativeAnrTimerStart(long service, int pid, int uid, long timeoutMs); boolean extend); /** /** * Cancel a timer by ID. Return true if the timer was running and canceled. Return false if * Cancel a timer by ID. Return true if the timer was running and canceled. Return false if Loading services/core/jni/com_android_server_utils_AnrTimer.cpp +26 −25 Original line number Original line Diff line number Diff line Loading @@ -130,7 +130,8 @@ class AnrTimerService { * constructor is also given the notifier callback, and two cookies for the callback: the * constructor is also given the notifier callback, and two cookies for the callback: the * traditional void* and an int. * 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. // Delete the service and clean up memory. ~AnrTimerService(); ~AnrTimerService(); Loading @@ -138,7 +139,7 @@ class AnrTimerService { // Start a timer and return the associated timer ID. It does not matter if the same pid/uid // 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 // 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. // 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 // 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 // has occurred. If the timer was Running, the function returns true. The other Loading Loading @@ -192,6 +193,9 @@ class AnrTimerService { void* notifierCookie_; void* notifierCookie_; jweak notifierObject_; jweak notifierObject_; // True if extensions can be granted to expired timers. const bool extend_; // The global lock // The global lock mutable Mutex lock_; mutable Mutex lock_; Loading Loading @@ -636,12 +640,13 @@ class AnrTimerService::Ticker { std::atomic<size_t> AnrTimerService::Ticker::idGen_; std::atomic<size_t> AnrTimerService::Ticker::idGen_; AnrTimerService::AnrTimerService(char const* label, AnrTimerService::AnrTimerService(char const* label, notifier_t notifier, void* cookie, notifier_t notifier, void* cookie, jweak jtimer, Ticker* ticker) : jweak jtimer, Ticker* ticker, bool extend) : label_(label), label_(label), notifier_(notifier), notifier_(notifier), notifierCookie_(cookie), notifierCookie_(cookie), notifierObject_(jtimer), notifierObject_(jtimer), extend_(extend), ticker_(ticker) { ticker_(ticker) { // Zero the statistics // Zero the statistics Loading @@ -666,11 +671,10 @@ char const *AnrTimerService::statusString(Status s) { return "unknown"; return "unknown"; } } AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, nsecs_t timeout) { nsecs_t timeout, bool extend) { ALOGI_IF(DEBUG, "starting"); ALOGI_IF(DEBUG, "starting"); AutoMutex _l(lock_); AutoMutex _l(lock_); Timer t(pid, uid, timeout, extend); Timer t(pid, uid, timeout, extend_); insert(t); insert(t); counters_.started++; counters_.started++; Loading Loading @@ -826,7 +830,8 @@ bool nativeSupportEnabled = false; /** /** * Singleton/globals for the anr timer. Among other things, this includes a Ticker* and a use * 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 * 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; static Mutex gAnrLock; struct AnrArgs { struct AnrArgs { Loading @@ -834,7 +839,6 @@ struct AnrArgs { jmethodID func = NULL; jmethodID func = NULL; JavaVM* vm = NULL; JavaVM* vm = NULL; AnrTimerService::Ticker* ticker = nullptr; AnrTimerService::Ticker* ticker = nullptr; int tickerUseCount = 0;; }; }; static AnrArgs gAnrArgs; static AnrArgs gAnrArgs; Loading Loading @@ -863,18 +867,17 @@ jboolean anrTimerSupported(JNIEnv* env, jclass) { return nativeSupportEnabled; return nativeSupportEnabled; } } jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname) { jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, jboolean extend) { if (!nativeSupportEnabled) return 0; if (!nativeSupportEnabled) return 0; AutoMutex _l(gAnrLock); AutoMutex _l(gAnrLock); if (!gAnrArgs.ticker) { if (gAnrArgs.ticker == nullptr) { gAnrArgs.ticker = new AnrTimerService::Ticker(); gAnrArgs.ticker = new AnrTimerService::Ticker(); } } gAnrArgs.tickerUseCount++; ScopedUtfChars name(env, jname); ScopedUtfChars name(env, jname); jobject timer = env->NewWeakGlobalRef(jtimer); jobject timer = env->NewWeakGlobalRef(jtimer); AnrTimerService* service = AnrTimerService* service = new AnrTimerService(name.c_str(), new AnrTimerService(name.c_str(), anrNotify, &gAnrArgs, timer, gAnrArgs.ticker); anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend); return reinterpret_cast<jlong>(service); return reinterpret_cast<jlong>(service); } } Loading @@ -889,19 +892,14 @@ jint anrTimerClose(JNIEnv* env, jclass, jlong ptr) { AnrTimerService *s = toService(ptr); AnrTimerService *s = toService(ptr); env->DeleteWeakGlobalRef(s->jtimer()); env->DeleteWeakGlobalRef(s->jtimer()); delete s; delete s; if (--gAnrArgs.tickerUseCount <= 0) { delete gAnrArgs.ticker; gAnrArgs.ticker = nullptr; } return 0; return 0; } } jint anrTimerStart(JNIEnv* env, jclass, jlong ptr, jint anrTimerStart(JNIEnv* env, jclass, jlong ptr, jint pid, jint uid, jlong timeout) { jint pid, jint uid, jlong timeout, jboolean extend) { if (!nativeSupportEnabled) return 0; if (!nativeSupportEnabled) return 0; // On the Java side, timeouts are expressed in milliseconds and must be converted to // On the Java side, timeouts are expressed in milliseconds and must be converted to // nanoseconds before being passed to the library code. // 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) { jboolean anrTimerCancel(JNIEnv* env, jclass, jlong ptr, jint timerId) { Loading Loading @@ -932,9 +930,9 @@ jobjectArray anrTimerDump(JNIEnv *env, jclass, jlong ptr) { static const JNINativeMethod methods[] = { static const JNINativeMethod methods[] = { {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, {"nativeAnrTimerCreate", "(Ljava/lang/String;)J", (void*) anrTimerCreate}, {"nativeAnrTimerCreate", "(Ljava/lang/String;Z)J", (void*) anrTimerCreate}, {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, {"nativeAnrTimerStart", "(JIIJZ)I", (void*) anrTimerStart}, {"nativeAnrTimerStart", "(JIIJ)I", (void*) anrTimerStart}, {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, Loading @@ -948,13 +946,16 @@ int register_android_server_utils_AnrTimer(JNIEnv* env) static const char *className = "com/android/server/utils/AnrTimer"; static const char *className = "com/android/server/utils/AnrTimer"; jniRegisterNativeMethods(env, className, methods, NELEM(methods)); 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); jclass service = FindClassOrDie(env, className); gAnrArgs.clazz = MakeGlobalRefOrDie(env, service); gAnrArgs.clazz = MakeGlobalRefOrDie(env, service); gAnrArgs.func = env->GetMethodID(gAnrArgs.clazz, "expire", "(IIIJ)Z"); gAnrArgs.func = env->GetMethodID(gAnrArgs.clazz, "expire", "(IIIJ)Z"); env->GetJavaVM(&gAnrArgs.vm); env->GetJavaVM(&gAnrArgs.vm); nativeSupportEnabled = NATIVE_SUPPORT; return 0; return 0; } } Loading services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -129,7 +129,7 @@ public class AnrTimerTest { */ */ private class TestAnrTimer extends AnrTimer<TestArg> { private class TestAnrTimer extends AnrTimer<TestArg> { private TestAnrTimer(Handler h, int key, String tag) { 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) { TestAnrTimer(Helper helper) { Loading Loading
services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -1336,7 +1336,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { private class BroadcastAnrTimer extends AnrTimer<BroadcastProcessQueue> { private class BroadcastAnrTimer extends AnrTimer<BroadcastProcessQueue> { BroadcastAnrTimer(@NonNull Handler handler) { BroadcastAnrTimer(@NonNull Handler handler) { super(Objects.requireNonNull(handler), super(Objects.requireNonNull(handler), MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT", true); MSG_DELIVERY_TIMEOUT, "BROADCAST_TIMEOUT", new AnrTimer.Args().extend(true)); } } @Override @Override Loading
services/core/java/com/android/server/utils/AnrTimer.java +38 −46 Original line number Original line Diff line number Diff line Loading @@ -139,6 +139,29 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** The default injector. */ /** The default injector. */ private static final Injector sDefaultInjector = new Injector(); 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 * 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 * affected service, a short stack of the bad call, and the stringified arg associated with Loading Loading @@ -229,11 +252,8 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** A label that identifies the AnrTimer associated with a Timer in log messages. */ /** A label that identifies the AnrTimer associated with a Timer in log messages. */ private final String mLabel; private final String mLabel; /** Whether this timer instance supports extending timeouts. */ /** The configuration for this instance. */ private final boolean mExtend; private final Args mArgs; /** The injector used to create this instance. This is only used for testing. */ private final Injector mInjector; /** The top-level switch for the feature enabled or disabled. */ /** The top-level switch for the feature enabled or disabled. */ private final FeatureSwitch mFeature; private final FeatureSwitch mFeature; Loading @@ -254,18 +274,14 @@ public abstract class AnrTimer<V> implements AutoCloseable { * @param handler The handler to which the expiration message will be delivered. * @param handler The handler to which the expiration message will be delivered. * @param what The "what" parameter for the expiration message. * @param what The "what" parameter for the expiration message. * @param label A name for this instance. * @param label A name for this instance. * @param extend A flag to indicate if expired timers can be granted extensions. * @param args Configuration information for this instance. * @param injector An injector to provide overrides for testing. */ */ @VisibleForTesting public AnrTimer(@NonNull Handler handler, int what, @NonNull String label, @NonNull Args args) { AnrTimer(@NonNull Handler handler, int what, @NonNull String label, boolean extend, @NonNull Injector injector) { mHandler = handler; mHandler = handler; mWhat = what; mWhat = what; mLabel = label; mLabel = label; mExtend = extend; mArgs = args; mInjector = injector; boolean enabled = args.mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); boolean enabled = mInjector.anrTimerServiceEnabled() && nativeTimersSupported(); mFeature = createFeatureSwitch(enabled); mFeature = createFeatureSwitch(enabled); } } Loading @@ -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 * Create an AnrTimer instance with the default {@link #Injector} and the default configuration. * 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. * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description. * See {@link AnrTimer(Handler, int, String, boolean, Injector} for a functional description. * * * @param handler The handler to which the expiration message will be delivered. * @param handler The handler to which the expiration message will be delivered. Loading @@ -318,7 +312,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { * @param label A name for this instance. * @param label A name for this instance. */ */ public AnrTimer(@NonNull Handler handler, int what, @NonNull String label) { public AnrTimer(@NonNull Handler handler, int what, @NonNull String label) { this(handler, what, label, false); this(handler, what, label, new Args()); } } /** /** Loading Loading @@ -449,7 +443,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Fetch the native tag (an integer) for the given label. */ /** Fetch the native tag (an integer) for the given label. */ FeatureEnabled() { FeatureEnabled() { mNative = nativeAnrTimerCreate(mLabel); mNative = nativeAnrTimerCreate(mLabel, mArgs.mExtend); if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); if (mNative == 0) throw new IllegalArgumentException("unable to create native timer"); synchronized (sAnrTimerList) { synchronized (sAnrTimerList) { sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); sAnrTimerList.put(mNative, new WeakReference(AnrTimer.this)); Loading @@ -466,7 +460,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // exist. // exist. if (cancel(arg)) mTotalRestarted++; if (cancel(arg)) mTotalRestarted++; int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs, mExtend); int timerId = nativeAnrTimerStart(mNative, pid, uid, timeoutMs); if (timerId > 0) { if (timerId > 0) { mTimerIdMap.put(arg, timerId); mTimerIdMap.put(arg, timerId); mTimerArgMap.put(timerId, arg); mTimerArgMap.put(timerId, arg); Loading Loading @@ -828,19 +822,17 @@ public abstract class AnrTimer<V> implements AutoCloseable { private static native boolean nativeAnrTimerSupported(); private static native boolean nativeAnrTimerSupported(); /** /** * Create a new native timer with the given key and name. The key is not used by the native * Create a new native timer with the given name and flags. The name is only for logging. * code but it is returned to the Java layer in the expiration handler. The name is only for * Unlike the other methods, this is an instance method: the "this" parameter is passed into * logging. Unlike the other methods, this is an instance method: the "this" parameter is * the native layer. * 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. */ /** Release the native resources. No further operations are premitted. */ private static native int nativeAnrTimerClose(long service); private static native int nativeAnrTimerClose(long service); /** Start a timer and return its ID. Zero is returned on error. */ /** 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, private static native int nativeAnrTimerStart(long service, int pid, int uid, long timeoutMs); boolean extend); /** /** * Cancel a timer by ID. Return true if the timer was running and canceled. Return false if * Cancel a timer by ID. Return true if the timer was running and canceled. Return false if Loading
services/core/jni/com_android_server_utils_AnrTimer.cpp +26 −25 Original line number Original line Diff line number Diff line Loading @@ -130,7 +130,8 @@ class AnrTimerService { * constructor is also given the notifier callback, and two cookies for the callback: the * constructor is also given the notifier callback, and two cookies for the callback: the * traditional void* and an int. * 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. // Delete the service and clean up memory. ~AnrTimerService(); ~AnrTimerService(); Loading @@ -138,7 +139,7 @@ class AnrTimerService { // Start a timer and return the associated timer ID. It does not matter if the same pid/uid // 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 // 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. // 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 // 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 // has occurred. If the timer was Running, the function returns true. The other Loading Loading @@ -192,6 +193,9 @@ class AnrTimerService { void* notifierCookie_; void* notifierCookie_; jweak notifierObject_; jweak notifierObject_; // True if extensions can be granted to expired timers. const bool extend_; // The global lock // The global lock mutable Mutex lock_; mutable Mutex lock_; Loading Loading @@ -636,12 +640,13 @@ class AnrTimerService::Ticker { std::atomic<size_t> AnrTimerService::Ticker::idGen_; std::atomic<size_t> AnrTimerService::Ticker::idGen_; AnrTimerService::AnrTimerService(char const* label, AnrTimerService::AnrTimerService(char const* label, notifier_t notifier, void* cookie, notifier_t notifier, void* cookie, jweak jtimer, Ticker* ticker) : jweak jtimer, Ticker* ticker, bool extend) : label_(label), label_(label), notifier_(notifier), notifier_(notifier), notifierCookie_(cookie), notifierCookie_(cookie), notifierObject_(jtimer), notifierObject_(jtimer), extend_(extend), ticker_(ticker) { ticker_(ticker) { // Zero the statistics // Zero the statistics Loading @@ -666,11 +671,10 @@ char const *AnrTimerService::statusString(Status s) { return "unknown"; return "unknown"; } } AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, nsecs_t timeout) { nsecs_t timeout, bool extend) { ALOGI_IF(DEBUG, "starting"); ALOGI_IF(DEBUG, "starting"); AutoMutex _l(lock_); AutoMutex _l(lock_); Timer t(pid, uid, timeout, extend); Timer t(pid, uid, timeout, extend_); insert(t); insert(t); counters_.started++; counters_.started++; Loading Loading @@ -826,7 +830,8 @@ bool nativeSupportEnabled = false; /** /** * Singleton/globals for the anr timer. Among other things, this includes a Ticker* and a use * 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 * 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; static Mutex gAnrLock; struct AnrArgs { struct AnrArgs { Loading @@ -834,7 +839,6 @@ struct AnrArgs { jmethodID func = NULL; jmethodID func = NULL; JavaVM* vm = NULL; JavaVM* vm = NULL; AnrTimerService::Ticker* ticker = nullptr; AnrTimerService::Ticker* ticker = nullptr; int tickerUseCount = 0;; }; }; static AnrArgs gAnrArgs; static AnrArgs gAnrArgs; Loading Loading @@ -863,18 +867,17 @@ jboolean anrTimerSupported(JNIEnv* env, jclass) { return nativeSupportEnabled; return nativeSupportEnabled; } } jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname) { jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, jboolean extend) { if (!nativeSupportEnabled) return 0; if (!nativeSupportEnabled) return 0; AutoMutex _l(gAnrLock); AutoMutex _l(gAnrLock); if (!gAnrArgs.ticker) { if (gAnrArgs.ticker == nullptr) { gAnrArgs.ticker = new AnrTimerService::Ticker(); gAnrArgs.ticker = new AnrTimerService::Ticker(); } } gAnrArgs.tickerUseCount++; ScopedUtfChars name(env, jname); ScopedUtfChars name(env, jname); jobject timer = env->NewWeakGlobalRef(jtimer); jobject timer = env->NewWeakGlobalRef(jtimer); AnrTimerService* service = AnrTimerService* service = new AnrTimerService(name.c_str(), new AnrTimerService(name.c_str(), anrNotify, &gAnrArgs, timer, gAnrArgs.ticker); anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend); return reinterpret_cast<jlong>(service); return reinterpret_cast<jlong>(service); } } Loading @@ -889,19 +892,14 @@ jint anrTimerClose(JNIEnv* env, jclass, jlong ptr) { AnrTimerService *s = toService(ptr); AnrTimerService *s = toService(ptr); env->DeleteWeakGlobalRef(s->jtimer()); env->DeleteWeakGlobalRef(s->jtimer()); delete s; delete s; if (--gAnrArgs.tickerUseCount <= 0) { delete gAnrArgs.ticker; gAnrArgs.ticker = nullptr; } return 0; return 0; } } jint anrTimerStart(JNIEnv* env, jclass, jlong ptr, jint anrTimerStart(JNIEnv* env, jclass, jlong ptr, jint pid, jint uid, jlong timeout) { jint pid, jint uid, jlong timeout, jboolean extend) { if (!nativeSupportEnabled) return 0; if (!nativeSupportEnabled) return 0; // On the Java side, timeouts are expressed in milliseconds and must be converted to // On the Java side, timeouts are expressed in milliseconds and must be converted to // nanoseconds before being passed to the library code. // 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) { jboolean anrTimerCancel(JNIEnv* env, jclass, jlong ptr, jint timerId) { Loading Loading @@ -932,9 +930,9 @@ jobjectArray anrTimerDump(JNIEnv *env, jclass, jlong ptr) { static const JNINativeMethod methods[] = { static const JNINativeMethod methods[] = { {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, {"nativeAnrTimerCreate", "(Ljava/lang/String;)J", (void*) anrTimerCreate}, {"nativeAnrTimerCreate", "(Ljava/lang/String;Z)J", (void*) anrTimerCreate}, {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, {"nativeAnrTimerStart", "(JIIJZ)I", (void*) anrTimerStart}, {"nativeAnrTimerStart", "(JIIJ)I", (void*) anrTimerStart}, {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, Loading @@ -948,13 +946,16 @@ int register_android_server_utils_AnrTimer(JNIEnv* env) static const char *className = "com/android/server/utils/AnrTimer"; static const char *className = "com/android/server/utils/AnrTimer"; jniRegisterNativeMethods(env, className, methods, NELEM(methods)); 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); jclass service = FindClassOrDie(env, className); gAnrArgs.clazz = MakeGlobalRefOrDie(env, service); gAnrArgs.clazz = MakeGlobalRefOrDie(env, service); gAnrArgs.func = env->GetMethodID(gAnrArgs.clazz, "expire", "(IIIJ)Z"); gAnrArgs.func = env->GetMethodID(gAnrArgs.clazz, "expire", "(IIIJ)Z"); env->GetJavaVM(&gAnrArgs.vm); env->GetJavaVM(&gAnrArgs.vm); nativeSupportEnabled = NATIVE_SUPPORT; return 0; return 0; } } Loading
services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -129,7 +129,7 @@ public class AnrTimerTest { */ */ private class TestAnrTimer extends AnrTimer<TestArg> { private class TestAnrTimer extends AnrTimer<TestArg> { private TestAnrTimer(Handler h, int key, String tag) { 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) { TestAnrTimer(Helper helper) { Loading