Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7dc99afc authored by Lee Shombert's avatar Lee Shombert Committed by Android (Google) Code Review
Browse files

Merge "Clean up AnrTimer argument passing" into main

parents 073fe120 23a0529e
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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
+38 −46
Original line number Diff line number Diff line
@@ -139,6 +139,29 @@ public abstract class AnrTimer<V> implements AutoCloseable {
    /** The default 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
     * affected service, a short stack of the bad call, and the stringified arg associated with
@@ -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
+26 −25
Original line number Diff line number Diff line
@@ -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;
}

+1 −1
Original line number Diff line number Diff line
@@ -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) {