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 Original line Diff line number Diff line
@@ -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
+38 −46
Original line number Original line Diff line number Diff line
@@ -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
@@ -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;
@@ -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);
    }
    }


@@ -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.
@@ -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());
    }
    }


    /**
    /**
@@ -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));
@@ -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);
@@ -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
+26 −25
Original line number Original line 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
     * 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();
@@ -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
@@ -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_;


@@ -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
@@ -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++;


@@ -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 {
@@ -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;


@@ -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);
}
}


@@ -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) {
@@ -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},
@@ -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;
}
}


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