Loading services/core/java/com/android/server/utils/AnrTimer.java +4 −69 Original line number Diff line number Diff line Loading @@ -129,14 +129,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return Flags.anrTimerService(); } /** * Return true if freezing is feature-enabled. Freezing must still be enabled on a * per-service basis. */ private static boolean freezerFeatureEnabled() { return false; } /** * Return true if tracing is feature-enabled. This has no effect unless tracing is configured. * Note that this does not represent any per-process overrides via an Injector. Loading @@ -153,10 +145,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return AnrTimer.anrTimerServiceEnabled(); } boolean freezerEnabled() { return AnrTimer.freezerFeatureEnabled(); } boolean traceEnabled() { return AnrTimer.traceFeatureEnabled(); } Loading @@ -176,9 +164,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Grant timer extensions when the system is heavily loaded. */ private boolean mExtend = false; /** Freeze ANR'ed processes. */ boolean mFreeze = false; // This is only used for testing, so it is limited to package visibility. Args injector(@NonNull Injector injector) { mInjector = injector; Loading @@ -189,11 +174,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { mExtend = flag; return this; } public Args freeze(boolean enable) { mFreeze = enable; return this; } } /** Loading @@ -212,11 +192,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // Allow multiple calls to close(). private boolean mClosed = false; // The native timer ID that must be closed. This may be zero. final int mTimerId; TimerLock(int timerId) { mTimerId = timerId; TimerLock() { mGuard.open("AnrTimer.release"); } Loading @@ -224,7 +200,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { public void close() { synchronized (mLock) { if (!mClosed) { AnrTimer.this.release(this); mGuard.close(); mClosed = true; } Loading Loading @@ -450,8 +425,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { abstract boolean discard(@NonNull V arg); abstract void release(@NonNull TimerLock timer); abstract boolean enabled(); abstract void dump(IndentingPrintWriter pw, boolean verbose); Loading Loading @@ -491,11 +464,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return true; } /** release() is a no-op when the feature is disabled. */ @Override void release(@NonNull TimerLock timer) { } /** The feature is not enabled. */ @Override boolean enabled() { Loading Loading @@ -544,9 +512,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Create the native AnrTimerService that will host all timers from this instance. */ FeatureEnabled() { mNative = nativeAnrTimerCreate(mLabel, mArgs.mExtend, mArgs.mFreeze && mArgs.mInjector.freezerEnabled()); 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)); Loading Loading @@ -616,7 +582,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // If "accepted" is true then the native layer has pending operations against this // timer. Wrap the timer ID in a TimerLock and return it to the caller. If // "accepted" is false then the native later does not have any pending operations. return accepted ? new TimerLock(timer) : null; return accepted ? new TimerLock() : null; } } Loading @@ -639,21 +605,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { } } /** * Unfreeze an app that was frozen because its timer had expired. This method catches * errors that might be thrown by the unfreeze method. This method does nothing if * freezing is not enabled or if the AnrTimer never froze the timer. Note that the native * release method returns false only if the timer's process was frozen, is still frozen, * and could not be unfrozen. */ @Override void release(@NonNull TimerLock t) { if (t.mTimerId == 0) return; if (!nativeAnrTimerRelease(mNative, t.mTimerId)) { Log.e(TAG, "failed to release id=" + t.mTimerId, new Exception(TAG)); } } /** The feature is enabled. */ @Override boolean enabled() { Loading Loading @@ -775,13 +726,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return mFeature.discard(arg); } /** * Release an expired timer. */ private void release(@NonNull TimerLock t) { mFeature.release(t); } /** * The notifier that a timer has fired. The timerId and original pid/uid are supplied. The * elapsed time is the actual time since the timer was scheduled, which may be different from Loading Loading @@ -974,7 +918,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { * Unlike the other methods, this is an instance method: the "this" parameter is passed into * the native layer. */ private native long nativeAnrTimerCreate(String name, boolean extend, boolean freeze); private native long nativeAnrTimerCreate(String name, boolean extend); /** Release the native resources. No further operations are premitted. */ private static native int nativeAnrTimerClose(long service); Loading @@ -997,15 +941,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Discard an expired timer by ID. Return true if the timer was found. */ private static native boolean nativeAnrTimerDiscard(long service, int timerId); /** * Release (unfreeze) the process associated with the timer, if the process was previously * frozen by the service. The function returns false if three conditions are true: the timer * does exist, the timer's process was frozen, and the timer's process could not be unfrozen. * Otherwise, the function returns true. In other words, a return value of value means there * is a process that is unexpectedly stuck in the frozen state. */ private static native boolean nativeAnrTimerRelease(long service, int timerId); /** * Configure tracing. The input array is a set of words pulled from the command line. All * parsing happens inside the native layer. The function returns a string which is either an Loading services/core/java/com/android/server/utils/flags.aconfig +0 −8 Original line number Diff line number Diff line Loading @@ -9,14 +9,6 @@ flag { bug: "282428924" } flag { name: "anr_timer_freezer" namespace: "system_performance" is_fixed_read_only: true description: "Enable freezing of a process when an ANR is triggered" bug: "325594551" } flag { name: "anr_timer_trace" namespace: "system_performance" Loading services/core/jni/com_android_server_utils_AnrTimer.cpp +17 −160 Original line number Diff line number Diff line Loading @@ -132,21 +132,6 @@ std::string getProcessName(pid_t pid) { } } /** * Three wrappers of the trace utilities, which hard-code the timer track. */ void traceBegin(const char* msg, int cookie) { ATRACE_ASYNC_FOR_TRACK_BEGIN(ANR_TIMER_TRACK, msg, cookie); } void traceEnd(int cookie) { ATRACE_ASYNC_FOR_TRACK_END(ANR_TIMER_TRACK, cookie); } void traceEvent(const char* msg) { ATRACE_INSTANT_FOR_TRACK(ANR_TIMER_TRACK, msg); } /** * This class captures tracing information for processes tracked by an AnrTimer. A user can * configure tracing to have the AnrTimerService emit extra information for watched processes. Loading Loading @@ -489,7 +474,7 @@ class AnrTimerService { * configuration options. */ AnrTimerService(const char* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker*, bool extend, bool freeze); bool extend); // Delete the service and clean up memory. ~AnrTimerService(); Loading @@ -506,8 +491,8 @@ class AnrTimerService { bool cancel(timer_id_t timerId); // Accept a timer. This is called when the upper layers accept that a timer has expired. // If the timer was Expired and its process was frozen, the timer is pushed to the expired // list and 'true' is returned. Otherwise the function returns false. // If the timer was Expired, the function returns true. Anything else is an error and the // function returns false. bool accept(timer_id_t timerId); // Discard a timer without collecting any statistics. This is called when the upper layers Loading @@ -519,9 +504,6 @@ class AnrTimerService { // A timer has expired. void expire(timer_id_t); // Release a timer. The timer must be in the expired list. bool release(timer_id_t); // Configure a trace specification to trace selected timers. See AnrTimerTracer for details. static std::pair<bool, std::string> trace(const std::vector<std::string>& spec) { return tracer_.setConfig(spec); Loading @@ -545,13 +527,6 @@ class AnrTimerService { // Remove a timer from the lists and return it. The lock must be held by the caller. Timer removeLocked(timer_id_t timerId); // Add a timer to the expired list. void addExpiredLocked(const Timer&); // Scrub the expired list by removing all entries for non-existent processes. The expired // lock must be held by the caller. void scrubExpiredLocked(); // Return a string representation of a status value. static const char* statusString(Status); Loading @@ -568,18 +543,12 @@ class AnrTimerService { // True if extensions can be granted to expired timers. const bool extend_; // True if the service should freeze anr'ed processes. const bool freeze_; // The global lock mutable Mutex lock_; // The list of all timers that are still running. This is sorted by ID for fast lookup. std::set<Timer> running_; // The list of all expired timers that are awaiting release. std::set<Timer> expired_; // The maximum number of active timers. size_t maxRunning_; Loading @@ -592,7 +561,6 @@ class AnrTimerService { size_t discarded; size_t expired; size_t extended; size_t released; // The number of times there were zero active timers. size_t drained; Loading Loading @@ -666,8 +634,6 @@ class AnrTimerService::Timer { const nsecs_t timeout; // True if the timer may be extended. const bool extend; // True if process should be frozen when its timer expires. const bool freeze; // This is a percentage between 0 and 100. If it is non-zero then timer will fire at // timeout*split/100, and the EarlyAction will be invoked. The timer may continue running // or may expire, depending on the action. Thus, this value "splits" the timeout into two Loading @@ -691,9 +657,6 @@ class AnrTimerService::Timer { // True if this timer has been extended. bool extended; // True if the process has been frozen. bool frozen; // Bookkeeping for extensions. The initial state of the process. This is collected only if // the timer is extensible. ProcessStats initial; Loading @@ -710,34 +673,30 @@ class AnrTimerService::Timer { uid(0), timeout(0), extend(false), freeze(false), split(0), action(AnrTimerTracer::None), status(Invalid), started(0), scheduled(0), splitting(false), extended(false), frozen(false) { extended(false) { } // Create a new timer. This starts the timer. Timer(int pid, int uid, nsecs_t timeout, bool extend, bool freeze, AnrTimerTracer::TraceConfig trace) : Timer(int pid, int uid, nsecs_t timeout, bool extend, AnrTimerTracer::TraceConfig trace) : id(nextId()), pid(pid), uid(uid), timeout(timeout), extend(extend), freeze(freeze), split(trace.earlyTimeout), action(trace.action), status(Running), started(now()), scheduled(started + (split > 0 ? (timeout*split)/100 : timeout)), splitting(false), extended(false), frozen(false) { extended(false) { if (extend && pid != 0) { initial.fill(pid); } Loading Loading @@ -773,7 +732,6 @@ class AnrTimerService::Timer { break; case AnrTimerTracer::Expire: status = Expired; maybeFreezeProcess(); event("expire"); break; } Loading @@ -792,7 +750,6 @@ class AnrTimerService::Timer { } if (extension == 0) { status = Expired; maybeFreezeProcess(); event("expire"); } else { scheduled += extension; Loading @@ -808,18 +765,10 @@ class AnrTimerService::Timer { // Discard a timeout. void discard() { maybeUnfreezeProcess(); status = Canceled; event("discard"); } // Release the timer. void release() { // If timer represents a frozen process, unfreeze it at this time. maybeUnfreezeProcess(); event("release"); } // Return true if this timer corresponds to a running process. bool alive() const { return processExists(pid); Loading Loading @@ -857,49 +806,6 @@ class AnrTimerService::Timer { return getProcessName(pid); } /** * Freeze the process identified here. Failures are not logged, as they are primarily due * to a process having died (therefore failed to respond). */ void maybeFreezeProcess() { if (!freeze || !alive()) return; // Construct a unique event ID. The id*2 spans from the beginning of the freeze to the // end of the freeze. The id*2+1 spans the period inside the freeze/unfreeze // operations. const uint32_t cookie = id << 1; char tag[PATH_MAX]; snprintf(tag, sizeof(tag), "freeze(pid=%d,uid=%d)", pid, uid); traceBegin(tag, cookie); if (SetProcessProfiles(uid, pid, {"Frozen"})) { ALOGI("freeze %s name=%s", toString().c_str(), getName().c_str()); frozen = true; traceBegin("frozen", cookie+1); } else { ALOGE("error: freezing %s name=%s error=%s", toString().c_str(), getName().c_str(), strerror(errno)); traceEnd(cookie); } } void maybeUnfreezeProcess() { if (!freeze || !frozen) return; // See maybeFreezeProcess for an explanation of the cookie. const uint32_t cookie = id << 1; traceEnd(cookie+1); if (SetProcessProfiles(uid, pid, {"Unfrozen"})) { ALOGI("unfreeze %s name=%s", toString().c_str(), getName().c_str()); frozen = false; } else { ALOGE("error: unfreezing %s name=%s error=%s", toString().c_str(), getName().c_str(), strerror(errno)); } traceEnd(cookie); } // Get the next free ID. NOTIMER is never returned. static timer_id_t nextId() { timer_id_t id = idGen.fetch_add(1); Loading Loading @@ -930,6 +836,10 @@ class AnrTimerService::Timer { } } static void traceEvent(const char* msg) { ATRACE_INSTANT_FOR_TRACK(ANR_TIMER_TRACK, msg); } // IDs start at 1. A zero ID is invalid. static std::atomic<timer_id_t> idGen; }; Loading Loading @@ -1159,13 +1069,12 @@ std::atomic<size_t> AnrTimerService::Ticker::idGen_; AnrTimerService::AnrTimerService(const char* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker* ticker, bool extend, bool freeze) : jweak jtimer, Ticker* ticker, bool extend) : label_(label), notifier_(notifier), notifierCookie_(cookie), notifierObject_(jtimer), extend_(extend), freeze_(freeze), ticker_(ticker) { // Zero the statistics Loading @@ -1191,11 +1100,8 @@ const char* AnrTimerService::statusString(Status s) { } AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, nsecs_t timeout) { // Use the freezer only if the pid is not 0 (a nonsense value) and the pid is not self. // Freezing the current process is a fatal error. bool useFreezer = freeze_ && (pid != 0) && (pid != sThisProcess); AutoMutex _l(lock_); Timer t(pid, uid, timeout, extend_, useFreezer, tracer_.getConfig(pid)); Timer t(pid, uid, timeout, extend_, tracer_.getConfig(pid)); insertLocked(t); t.start(); counters_.started++; Loading Loading @@ -1225,10 +1131,7 @@ bool AnrTimerService::accept(timer_id_t timerId) { bool result = false; if (timer.status == Expired) { timer.accept(); if (timer.frozen) { addExpiredLocked(timer); result = true; } } else { counters_.error++; } Loading @@ -1251,42 +1154,6 @@ bool AnrTimerService::discard(timer_id_t timerId) { return result; } bool AnrTimerService::release(timer_id_t id) { if (id == NOTIMER) return true; Timer key(id); bool okay = false; AutoMutex _l(lock_); std::set<Timer>::iterator found = expired_.find(key); if (found != expired_.end()) { Timer t = *found; t.release(); counters_.released++; expired_.erase(found); okay = true; } else { ALOGI_IF(DEBUG_ERROR, "error: unable to release (%u)", id); counters_.error++; } scrubExpiredLocked(); return okay; } void AnrTimerService::addExpiredLocked(const Timer& timer) { scrubExpiredLocked(); expired_.insert(timer); } void AnrTimerService::scrubExpiredLocked() { for (auto i = expired_.begin(); i != expired_.end(); ) { if (!i->alive()) { i = expired_.erase(i); } else { i++; } } } // Hold the lock in order to manage the running list. void AnrTimerService::expire(timer_id_t timerId) { // Save the timer attributes for the notification Loading Loading @@ -1364,9 +1231,6 @@ std::vector<std::string> AnrTimerService::getDump() const { counters_.error, running_.size(), maxRunning_)); r.push_back(StringPrintf("released:%zu releasing:%zu", counters_.released, expired_.size())); r.push_back(StringPrintf("ticker:%zu ticking:%zu maxTicking:%zu", ticker_->id(), ticker_->running(), Loading Loading @@ -1420,8 +1284,7 @@ jboolean anrTimerSupported(JNIEnv* env, jclass) { return nativeSupportEnabled; } jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, jboolean extend, jboolean freeze) { jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, jboolean extend) { if (!nativeSupportEnabled) return 0; AutoMutex _l(gAnrLock); if (gAnrArgs.ticker == nullptr) { Loading @@ -1431,7 +1294,7 @@ jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, ScopedUtfChars name(env, jname); jobject timer = env->NewWeakGlobalRef(jtimer); AnrTimerService* service = new AnrTimerService(name.c_str(), anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend, freeze); anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend); return reinterpret_cast<jlong>(service); } Loading Loading @@ -1471,11 +1334,6 @@ jboolean anrTimerDiscard(JNIEnv* env, jclass, jlong ptr, jint timerId) { return toService(ptr)->discard(timerId); } jboolean anrTimerRelease(JNIEnv* env, jclass, jlong ptr, jint timerId) { if (!nativeSupportEnabled) return false; return toService(ptr)->release(timerId); } jstring anrTimerTrace(JNIEnv* env, jclass, jobjectArray jconfig) { if (!nativeSupportEnabled) return nullptr; std::vector<std::string> config; Loading @@ -1502,13 +1360,12 @@ jobjectArray anrTimerDump(JNIEnv *env, jclass, jlong ptr) { static const JNINativeMethod methods[] = { {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, {"nativeAnrTimerCreate", "(Ljava/lang/String;ZZ)J", (void*) anrTimerCreate}, {"nativeAnrTimerCreate", "(Ljava/lang/String;Z)J", (void*) anrTimerCreate}, {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, {"nativeAnrTimerStart", "(JIIJ)I", (void*) anrTimerStart}, {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, {"nativeAnrTimerRelease", "(JI)Z", (void*) anrTimerRelease}, {"nativeAnrTimerTrace", "([Ljava/lang/String;)Ljava/lang/String;", (void*) anrTimerTrace}, {"nativeAnrTimerDump", "(J)[Ljava/lang/String;", (void*) anrTimerDump}, }; Loading Loading
services/core/java/com/android/server/utils/AnrTimer.java +4 −69 Original line number Diff line number Diff line Loading @@ -129,14 +129,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return Flags.anrTimerService(); } /** * Return true if freezing is feature-enabled. Freezing must still be enabled on a * per-service basis. */ private static boolean freezerFeatureEnabled() { return false; } /** * Return true if tracing is feature-enabled. This has no effect unless tracing is configured. * Note that this does not represent any per-process overrides via an Injector. Loading @@ -153,10 +145,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return AnrTimer.anrTimerServiceEnabled(); } boolean freezerEnabled() { return AnrTimer.freezerFeatureEnabled(); } boolean traceEnabled() { return AnrTimer.traceFeatureEnabled(); } Loading @@ -176,9 +164,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Grant timer extensions when the system is heavily loaded. */ private boolean mExtend = false; /** Freeze ANR'ed processes. */ boolean mFreeze = false; // This is only used for testing, so it is limited to package visibility. Args injector(@NonNull Injector injector) { mInjector = injector; Loading @@ -189,11 +174,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { mExtend = flag; return this; } public Args freeze(boolean enable) { mFreeze = enable; return this; } } /** Loading @@ -212,11 +192,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // Allow multiple calls to close(). private boolean mClosed = false; // The native timer ID that must be closed. This may be zero. final int mTimerId; TimerLock(int timerId) { mTimerId = timerId; TimerLock() { mGuard.open("AnrTimer.release"); } Loading @@ -224,7 +200,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { public void close() { synchronized (mLock) { if (!mClosed) { AnrTimer.this.release(this); mGuard.close(); mClosed = true; } Loading Loading @@ -450,8 +425,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { abstract boolean discard(@NonNull V arg); abstract void release(@NonNull TimerLock timer); abstract boolean enabled(); abstract void dump(IndentingPrintWriter pw, boolean verbose); Loading Loading @@ -491,11 +464,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return true; } /** release() is a no-op when the feature is disabled. */ @Override void release(@NonNull TimerLock timer) { } /** The feature is not enabled. */ @Override boolean enabled() { Loading Loading @@ -544,9 +512,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Create the native AnrTimerService that will host all timers from this instance. */ FeatureEnabled() { mNative = nativeAnrTimerCreate(mLabel, mArgs.mExtend, mArgs.mFreeze && mArgs.mInjector.freezerEnabled()); 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)); Loading Loading @@ -616,7 +582,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { // If "accepted" is true then the native layer has pending operations against this // timer. Wrap the timer ID in a TimerLock and return it to the caller. If // "accepted" is false then the native later does not have any pending operations. return accepted ? new TimerLock(timer) : null; return accepted ? new TimerLock() : null; } } Loading @@ -639,21 +605,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { } } /** * Unfreeze an app that was frozen because its timer had expired. This method catches * errors that might be thrown by the unfreeze method. This method does nothing if * freezing is not enabled or if the AnrTimer never froze the timer. Note that the native * release method returns false only if the timer's process was frozen, is still frozen, * and could not be unfrozen. */ @Override void release(@NonNull TimerLock t) { if (t.mTimerId == 0) return; if (!nativeAnrTimerRelease(mNative, t.mTimerId)) { Log.e(TAG, "failed to release id=" + t.mTimerId, new Exception(TAG)); } } /** The feature is enabled. */ @Override boolean enabled() { Loading Loading @@ -775,13 +726,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { return mFeature.discard(arg); } /** * Release an expired timer. */ private void release(@NonNull TimerLock t) { mFeature.release(t); } /** * The notifier that a timer has fired. The timerId and original pid/uid are supplied. The * elapsed time is the actual time since the timer was scheduled, which may be different from Loading Loading @@ -974,7 +918,7 @@ public abstract class AnrTimer<V> implements AutoCloseable { * Unlike the other methods, this is an instance method: the "this" parameter is passed into * the native layer. */ private native long nativeAnrTimerCreate(String name, boolean extend, boolean freeze); private native long nativeAnrTimerCreate(String name, boolean extend); /** Release the native resources. No further operations are premitted. */ private static native int nativeAnrTimerClose(long service); Loading @@ -997,15 +941,6 @@ public abstract class AnrTimer<V> implements AutoCloseable { /** Discard an expired timer by ID. Return true if the timer was found. */ private static native boolean nativeAnrTimerDiscard(long service, int timerId); /** * Release (unfreeze) the process associated with the timer, if the process was previously * frozen by the service. The function returns false if three conditions are true: the timer * does exist, the timer's process was frozen, and the timer's process could not be unfrozen. * Otherwise, the function returns true. In other words, a return value of value means there * is a process that is unexpectedly stuck in the frozen state. */ private static native boolean nativeAnrTimerRelease(long service, int timerId); /** * Configure tracing. The input array is a set of words pulled from the command line. All * parsing happens inside the native layer. The function returns a string which is either an Loading
services/core/java/com/android/server/utils/flags.aconfig +0 −8 Original line number Diff line number Diff line Loading @@ -9,14 +9,6 @@ flag { bug: "282428924" } flag { name: "anr_timer_freezer" namespace: "system_performance" is_fixed_read_only: true description: "Enable freezing of a process when an ANR is triggered" bug: "325594551" } flag { name: "anr_timer_trace" namespace: "system_performance" Loading
services/core/jni/com_android_server_utils_AnrTimer.cpp +17 −160 Original line number Diff line number Diff line Loading @@ -132,21 +132,6 @@ std::string getProcessName(pid_t pid) { } } /** * Three wrappers of the trace utilities, which hard-code the timer track. */ void traceBegin(const char* msg, int cookie) { ATRACE_ASYNC_FOR_TRACK_BEGIN(ANR_TIMER_TRACK, msg, cookie); } void traceEnd(int cookie) { ATRACE_ASYNC_FOR_TRACK_END(ANR_TIMER_TRACK, cookie); } void traceEvent(const char* msg) { ATRACE_INSTANT_FOR_TRACK(ANR_TIMER_TRACK, msg); } /** * This class captures tracing information for processes tracked by an AnrTimer. A user can * configure tracing to have the AnrTimerService emit extra information for watched processes. Loading Loading @@ -489,7 +474,7 @@ class AnrTimerService { * configuration options. */ AnrTimerService(const char* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker*, bool extend, bool freeze); bool extend); // Delete the service and clean up memory. ~AnrTimerService(); Loading @@ -506,8 +491,8 @@ class AnrTimerService { bool cancel(timer_id_t timerId); // Accept a timer. This is called when the upper layers accept that a timer has expired. // If the timer was Expired and its process was frozen, the timer is pushed to the expired // list and 'true' is returned. Otherwise the function returns false. // If the timer was Expired, the function returns true. Anything else is an error and the // function returns false. bool accept(timer_id_t timerId); // Discard a timer without collecting any statistics. This is called when the upper layers Loading @@ -519,9 +504,6 @@ class AnrTimerService { // A timer has expired. void expire(timer_id_t); // Release a timer. The timer must be in the expired list. bool release(timer_id_t); // Configure a trace specification to trace selected timers. See AnrTimerTracer for details. static std::pair<bool, std::string> trace(const std::vector<std::string>& spec) { return tracer_.setConfig(spec); Loading @@ -545,13 +527,6 @@ class AnrTimerService { // Remove a timer from the lists and return it. The lock must be held by the caller. Timer removeLocked(timer_id_t timerId); // Add a timer to the expired list. void addExpiredLocked(const Timer&); // Scrub the expired list by removing all entries for non-existent processes. The expired // lock must be held by the caller. void scrubExpiredLocked(); // Return a string representation of a status value. static const char* statusString(Status); Loading @@ -568,18 +543,12 @@ class AnrTimerService { // True if extensions can be granted to expired timers. const bool extend_; // True if the service should freeze anr'ed processes. const bool freeze_; // The global lock mutable Mutex lock_; // The list of all timers that are still running. This is sorted by ID for fast lookup. std::set<Timer> running_; // The list of all expired timers that are awaiting release. std::set<Timer> expired_; // The maximum number of active timers. size_t maxRunning_; Loading @@ -592,7 +561,6 @@ class AnrTimerService { size_t discarded; size_t expired; size_t extended; size_t released; // The number of times there were zero active timers. size_t drained; Loading Loading @@ -666,8 +634,6 @@ class AnrTimerService::Timer { const nsecs_t timeout; // True if the timer may be extended. const bool extend; // True if process should be frozen when its timer expires. const bool freeze; // This is a percentage between 0 and 100. If it is non-zero then timer will fire at // timeout*split/100, and the EarlyAction will be invoked. The timer may continue running // or may expire, depending on the action. Thus, this value "splits" the timeout into two Loading @@ -691,9 +657,6 @@ class AnrTimerService::Timer { // True if this timer has been extended. bool extended; // True if the process has been frozen. bool frozen; // Bookkeeping for extensions. The initial state of the process. This is collected only if // the timer is extensible. ProcessStats initial; Loading @@ -710,34 +673,30 @@ class AnrTimerService::Timer { uid(0), timeout(0), extend(false), freeze(false), split(0), action(AnrTimerTracer::None), status(Invalid), started(0), scheduled(0), splitting(false), extended(false), frozen(false) { extended(false) { } // Create a new timer. This starts the timer. Timer(int pid, int uid, nsecs_t timeout, bool extend, bool freeze, AnrTimerTracer::TraceConfig trace) : Timer(int pid, int uid, nsecs_t timeout, bool extend, AnrTimerTracer::TraceConfig trace) : id(nextId()), pid(pid), uid(uid), timeout(timeout), extend(extend), freeze(freeze), split(trace.earlyTimeout), action(trace.action), status(Running), started(now()), scheduled(started + (split > 0 ? (timeout*split)/100 : timeout)), splitting(false), extended(false), frozen(false) { extended(false) { if (extend && pid != 0) { initial.fill(pid); } Loading Loading @@ -773,7 +732,6 @@ class AnrTimerService::Timer { break; case AnrTimerTracer::Expire: status = Expired; maybeFreezeProcess(); event("expire"); break; } Loading @@ -792,7 +750,6 @@ class AnrTimerService::Timer { } if (extension == 0) { status = Expired; maybeFreezeProcess(); event("expire"); } else { scheduled += extension; Loading @@ -808,18 +765,10 @@ class AnrTimerService::Timer { // Discard a timeout. void discard() { maybeUnfreezeProcess(); status = Canceled; event("discard"); } // Release the timer. void release() { // If timer represents a frozen process, unfreeze it at this time. maybeUnfreezeProcess(); event("release"); } // Return true if this timer corresponds to a running process. bool alive() const { return processExists(pid); Loading Loading @@ -857,49 +806,6 @@ class AnrTimerService::Timer { return getProcessName(pid); } /** * Freeze the process identified here. Failures are not logged, as they are primarily due * to a process having died (therefore failed to respond). */ void maybeFreezeProcess() { if (!freeze || !alive()) return; // Construct a unique event ID. The id*2 spans from the beginning of the freeze to the // end of the freeze. The id*2+1 spans the period inside the freeze/unfreeze // operations. const uint32_t cookie = id << 1; char tag[PATH_MAX]; snprintf(tag, sizeof(tag), "freeze(pid=%d,uid=%d)", pid, uid); traceBegin(tag, cookie); if (SetProcessProfiles(uid, pid, {"Frozen"})) { ALOGI("freeze %s name=%s", toString().c_str(), getName().c_str()); frozen = true; traceBegin("frozen", cookie+1); } else { ALOGE("error: freezing %s name=%s error=%s", toString().c_str(), getName().c_str(), strerror(errno)); traceEnd(cookie); } } void maybeUnfreezeProcess() { if (!freeze || !frozen) return; // See maybeFreezeProcess for an explanation of the cookie. const uint32_t cookie = id << 1; traceEnd(cookie+1); if (SetProcessProfiles(uid, pid, {"Unfrozen"})) { ALOGI("unfreeze %s name=%s", toString().c_str(), getName().c_str()); frozen = false; } else { ALOGE("error: unfreezing %s name=%s error=%s", toString().c_str(), getName().c_str(), strerror(errno)); } traceEnd(cookie); } // Get the next free ID. NOTIMER is never returned. static timer_id_t nextId() { timer_id_t id = idGen.fetch_add(1); Loading Loading @@ -930,6 +836,10 @@ class AnrTimerService::Timer { } } static void traceEvent(const char* msg) { ATRACE_INSTANT_FOR_TRACK(ANR_TIMER_TRACK, msg); } // IDs start at 1. A zero ID is invalid. static std::atomic<timer_id_t> idGen; }; Loading Loading @@ -1159,13 +1069,12 @@ std::atomic<size_t> AnrTimerService::Ticker::idGen_; AnrTimerService::AnrTimerService(const char* label, notifier_t notifier, void* cookie, jweak jtimer, Ticker* ticker, bool extend, bool freeze) : jweak jtimer, Ticker* ticker, bool extend) : label_(label), notifier_(notifier), notifierCookie_(cookie), notifierObject_(jtimer), extend_(extend), freeze_(freeze), ticker_(ticker) { // Zero the statistics Loading @@ -1191,11 +1100,8 @@ const char* AnrTimerService::statusString(Status s) { } AnrTimerService::timer_id_t AnrTimerService::start(int pid, int uid, nsecs_t timeout) { // Use the freezer only if the pid is not 0 (a nonsense value) and the pid is not self. // Freezing the current process is a fatal error. bool useFreezer = freeze_ && (pid != 0) && (pid != sThisProcess); AutoMutex _l(lock_); Timer t(pid, uid, timeout, extend_, useFreezer, tracer_.getConfig(pid)); Timer t(pid, uid, timeout, extend_, tracer_.getConfig(pid)); insertLocked(t); t.start(); counters_.started++; Loading Loading @@ -1225,10 +1131,7 @@ bool AnrTimerService::accept(timer_id_t timerId) { bool result = false; if (timer.status == Expired) { timer.accept(); if (timer.frozen) { addExpiredLocked(timer); result = true; } } else { counters_.error++; } Loading @@ -1251,42 +1154,6 @@ bool AnrTimerService::discard(timer_id_t timerId) { return result; } bool AnrTimerService::release(timer_id_t id) { if (id == NOTIMER) return true; Timer key(id); bool okay = false; AutoMutex _l(lock_); std::set<Timer>::iterator found = expired_.find(key); if (found != expired_.end()) { Timer t = *found; t.release(); counters_.released++; expired_.erase(found); okay = true; } else { ALOGI_IF(DEBUG_ERROR, "error: unable to release (%u)", id); counters_.error++; } scrubExpiredLocked(); return okay; } void AnrTimerService::addExpiredLocked(const Timer& timer) { scrubExpiredLocked(); expired_.insert(timer); } void AnrTimerService::scrubExpiredLocked() { for (auto i = expired_.begin(); i != expired_.end(); ) { if (!i->alive()) { i = expired_.erase(i); } else { i++; } } } // Hold the lock in order to manage the running list. void AnrTimerService::expire(timer_id_t timerId) { // Save the timer attributes for the notification Loading Loading @@ -1364,9 +1231,6 @@ std::vector<std::string> AnrTimerService::getDump() const { counters_.error, running_.size(), maxRunning_)); r.push_back(StringPrintf("released:%zu releasing:%zu", counters_.released, expired_.size())); r.push_back(StringPrintf("ticker:%zu ticking:%zu maxTicking:%zu", ticker_->id(), ticker_->running(), Loading Loading @@ -1420,8 +1284,7 @@ jboolean anrTimerSupported(JNIEnv* env, jclass) { return nativeSupportEnabled; } jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, jboolean extend, jboolean freeze) { jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, jboolean extend) { if (!nativeSupportEnabled) return 0; AutoMutex _l(gAnrLock); if (gAnrArgs.ticker == nullptr) { Loading @@ -1431,7 +1294,7 @@ jlong anrTimerCreate(JNIEnv* env, jobject jtimer, jstring jname, ScopedUtfChars name(env, jname); jobject timer = env->NewWeakGlobalRef(jtimer); AnrTimerService* service = new AnrTimerService(name.c_str(), anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend, freeze); anrNotify, &gAnrArgs, timer, gAnrArgs.ticker, extend); return reinterpret_cast<jlong>(service); } Loading Loading @@ -1471,11 +1334,6 @@ jboolean anrTimerDiscard(JNIEnv* env, jclass, jlong ptr, jint timerId) { return toService(ptr)->discard(timerId); } jboolean anrTimerRelease(JNIEnv* env, jclass, jlong ptr, jint timerId) { if (!nativeSupportEnabled) return false; return toService(ptr)->release(timerId); } jstring anrTimerTrace(JNIEnv* env, jclass, jobjectArray jconfig) { if (!nativeSupportEnabled) return nullptr; std::vector<std::string> config; Loading @@ -1502,13 +1360,12 @@ jobjectArray anrTimerDump(JNIEnv *env, jclass, jlong ptr) { static const JNINativeMethod methods[] = { {"nativeAnrTimerSupported", "()Z", (void*) anrTimerSupported}, {"nativeAnrTimerCreate", "(Ljava/lang/String;ZZ)J", (void*) anrTimerCreate}, {"nativeAnrTimerCreate", "(Ljava/lang/String;Z)J", (void*) anrTimerCreate}, {"nativeAnrTimerClose", "(J)I", (void*) anrTimerClose}, {"nativeAnrTimerStart", "(JIIJ)I", (void*) anrTimerStart}, {"nativeAnrTimerCancel", "(JI)Z", (void*) anrTimerCancel}, {"nativeAnrTimerAccept", "(JI)Z", (void*) anrTimerAccept}, {"nativeAnrTimerDiscard", "(JI)Z", (void*) anrTimerDiscard}, {"nativeAnrTimerRelease", "(JI)Z", (void*) anrTimerRelease}, {"nativeAnrTimerTrace", "([Ljava/lang/String;)Ljava/lang/String;", (void*) anrTimerTrace}, {"nativeAnrTimerDump", "(J)[Ljava/lang/String;", (void*) anrTimerDump}, }; Loading