Add input system to Watchdog.
Bug: 5094994

Change-Id: I153866958efc64ac19bda8b997c1c9f6ad425ec4
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 0a567fd..960e414 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -1294,4 +1294,11 @@
     } // 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 08f73ca..fae5d4f 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -208,7 +208,11 @@
     /* 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 @@
     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 ce9e14f..22372cf1 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -3919,6 +3919,8 @@
 }
 
 void InputDispatcher::dump(String8& dump) {
+    AutoMutex _l(mLock);
+
     dump.append("Input Dispatcher State:\n");
     dumpDispatchStateLocked(dump);
 
@@ -3928,6 +3930,12 @@
     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 01c7b35..cae1610 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -282,6 +282,9 @@
      * 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 @@
     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 dacc73f..2eacbeb 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -731,6 +731,15 @@
             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 e82c4e7..e9daef5 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -210,6 +210,9 @@
      * 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 @@
     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 4a866a8..87f212b 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -631,6 +631,9 @@
     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 1d0857b..c8b18c8 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 @@
 /*
  * 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 @@
             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 @@
 
         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 @@
         }
     }
 
+    // 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 3414eea..7c84e43 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -1288,6 +1288,15 @@
     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 @@
             (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) \