summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/input/EventHub.cpp7
-rw-r--r--services/input/EventHub.h5
-rw-r--r--services/input/InputDispatcher.cpp8
-rw-r--r--services/input/InputDispatcher.h4
-rw-r--r--services/input/InputReader.cpp9
-rw-r--r--services/input/InputReader.h4
-rw-r--r--services/input/tests/InputReader_test.cpp3
-rw-r--r--services/java/com/android/server/wm/InputManager.java13
-rw-r--r--services/jni/com_android_server_InputManager.cpp11
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) \