diff options
| -rw-r--r-- | services/input/EventHub.cpp | 7 | ||||
| -rw-r--r-- | services/input/EventHub.h | 5 | ||||
| -rw-r--r-- | services/input/InputDispatcher.cpp | 8 | ||||
| -rw-r--r-- | services/input/InputDispatcher.h | 4 | ||||
| -rw-r--r-- | services/input/InputReader.cpp | 9 | ||||
| -rw-r--r-- | services/input/InputReader.h | 4 | ||||
| -rw-r--r-- | services/input/tests/InputReader_test.cpp | 3 | ||||
| -rw-r--r-- | services/java/com/android/server/wm/InputManager.java | 13 | ||||
| -rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 11 |
9 files changed, 63 insertions, 1 deletions
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 0a567fd37d5e..960e4143e659 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -1294,4 +1294,11 @@ void EventHub::dump(String8& dump) { } // release lock } +void EventHub::monitor() { + // Acquire and release the lock to ensure that the event hub has not deadlocked. + mLock.lock(); + mLock.unlock(); +} + + }; // namespace android diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 08f73ca71dd4..fae5d4f4ead9 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -208,7 +208,11 @@ public: /* Wakes up getEvents() if it is blocked on a read. */ virtual void wake() = 0; + /* Dump EventHub state to a string. */ virtual void dump(String8& dump) = 0; + + /* Called by the heatbeat to ensures that the reader has not deadlocked. */ + virtual void monitor() = 0; }; class EventHub : public EventHubInterface @@ -259,6 +263,7 @@ public: virtual void wake(); virtual void dump(String8& dump); + virtual void monitor(); protected: virtual ~EventHub(); diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index ce9e14f2ad8a..22372cf174df 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -3919,6 +3919,8 @@ void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const } void InputDispatcher::dump(String8& dump) { + AutoMutex _l(mLock); + dump.append("Input Dispatcher State:\n"); dumpDispatchStateLocked(dump); @@ -3928,6 +3930,12 @@ void InputDispatcher::dump(String8& dump) { dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f); } +void InputDispatcher::monitor() { + // Acquire and release the lock to ensure that the dispatcher has not deadlocked. + mLock.lock(); + mLock.unlock(); +} + // --- InputDispatcher::Queue --- diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 01c7b35a606e..cae1610a8bc2 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -282,6 +282,9 @@ public: * This method may be called on any thread (usually by the input manager). */ virtual void dump(String8& dump) = 0; + /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ + virtual void monitor() = 0; + /* Runs a single iteration of the dispatch loop. * Nominally processes one queued event, a timeout, or a response from an input consumer. * @@ -370,6 +373,7 @@ public: explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); virtual void dump(String8& dump); + virtual void monitor(); virtual void dispatchOnce(); diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index dacc73f41d25..2eacbeb34172 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -731,6 +731,15 @@ void InputReader::dump(String8& dump) { mConfig.pointerGestureZoomSpeedRatio); } +void InputReader::monitor() { + // Acquire and release the lock to ensure that the reader has not deadlocked. + mLock.lock(); + mLock.unlock(); + + // Check the EventHub + mEventHub->monitor(); +} + // --- InputReader::ContextImpl --- diff --git a/services/input/InputReader.h b/services/input/InputReader.h index e82c4e7d5896..e9daef5845d3 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -210,6 +210,9 @@ public: * This method may be called on any thread (usually by the input manager). */ virtual void dump(String8& dump) = 0; + /* Called by the heatbeat to ensures that the reader has not deadlocked. */ + virtual void monitor() = 0; + /* Runs a single iteration of the processing loop. * Nominally reads and processes one incoming message from the EventHub. * @@ -297,6 +300,7 @@ public: virtual ~InputReader(); virtual void dump(String8& dump); + virtual void monitor(); virtual void loopOnce(); diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 4a866a834c14..87f212b3e038 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -631,6 +631,9 @@ private: virtual void dump(String8& dump) { } + virtual void monitor() { + } + virtual void requestReopenDevices() { } diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java index 1d0857baf3eb..c8b18c8d0a73 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/wm/InputManager.java @@ -17,6 +17,7 @@ package com.android.server.wm; import com.android.internal.util.XmlUtils; +import com.android.server.Watchdog; import org.xmlpull.v1.XmlPullParser; @@ -52,7 +53,7 @@ import java.util.ArrayList; /* * Wraps the C++ InputManager and provides its callbacks. */ -public class InputManager { +public class InputManager implements Watchdog.Monitor { static final String TAG = "InputManager"; private static final boolean DEBUG = false; @@ -94,6 +95,7 @@ public class InputManager { InputChannel toChannel); private static native void nativeSetPointerSpeed(int speed); private static native String nativeDump(); + private static native void nativeMonitor(); // Input event injection constants defined in InputDispatcher.h. static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0; @@ -135,6 +137,9 @@ public class InputManager { Slog.i(TAG, "Initializing input manager"); nativeInit(mContext, mCallbacks, looper.getQueue()); + + // Add ourself to the Watchdog monitors. + Watchdog.getInstance().addMonitor(this); } public void start() { @@ -456,6 +461,12 @@ public class InputManager { } } + // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection). + public void monitor() { + synchronized (mInputFilterLock) { } + nativeMonitor(); + } + private final class InputFilterHost implements InputFilter.Host { private boolean mDisconnected; diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 3414eea518b8..7c84e4355b04 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -1288,6 +1288,15 @@ static jstring android_server_InputManager_nativeDump(JNIEnv* env, jclass clazz) return env->NewStringUTF(dump.string()); } +static void android_server_InputManager_nativeMonitor(JNIEnv* env, jclass clazz) { + if (checkInputManagerUnitialized(env)) { + return; + } + + gNativeInputManager->getInputManager()->getReader()->monitor(); + gNativeInputManager->getInputManager()->getDispatcher()->monitor(); +} + // ---------------------------------------------------------------------------- static JNINativeMethod gInputManagerMethods[] = { @@ -1338,6 +1347,8 @@ static JNINativeMethod gInputManagerMethods[] = { (void*) android_server_InputManager_nativeSetPointerSpeed }, { "nativeDump", "()Ljava/lang/String;", (void*) android_server_InputManager_nativeDump }, + { "nativeMonitor", "()V", + (void*) android_server_InputManager_nativeMonitor }, }; #define FIND_CLASS(var, className) \ |