Add dump to Input Classifier

Currently, the InputClassifier stage that is positioned between
InputReader and InputDispatcher is not accounted for when doing a
'dumpsys input'. But that stage may contain important information about
the operation and the InputClassifier HAL. Add the dump(..) command to
both InputClassifier and MotionClassifier.

Test: dumpsys input and inspect the resulting text
Next, crash the InputClassifier HAL (killall android.hardware.input.classifier@1.0-service
Then again 'dumpsys input' to check that the HAL status is 'not
responding'
Bug: 117935272
Change-Id: Ie7ddca2e355e094f93236a9bc667faad7a99ee70
diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h
index b892120..c9eb683 100644
--- a/services/inputflinger/BlockingQueue.h
+++ b/services/inputflinger/BlockingQueue.h
@@ -80,6 +80,16 @@
         mQueue.clear();
     };
 
+    /**
+     * How many elements are currently stored in the queue.
+     * Primary used for debugging.
+     * Does not block.
+     */
+    size_t size() {
+        std::scoped_lock lock(mLock);
+        return mQueue.size();
+    }
+
 private:
     size_t mCapacity;
     /**
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 7ade0d4..09a004c 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -19,6 +19,7 @@
 #include "InputClassifier.h"
 
 #include <algorithm>
+#include <android-base/stringprintf.h>
 #include <cmath>
 #include <inttypes.h>
 #include <log/log.h>
@@ -26,9 +27,17 @@
     #include <pthread.h>
 #endif
 #include <server_configurable_flags/get_flags.h>
+#include <unordered_set>
 
 #include <android/hardware/input/classifier/1.0/IInputClassifier.h>
 
+#define INDENT1 "  "
+#define INDENT2 "    "
+#define INDENT3 "      "
+#define INDENT4 "        "
+#define INDENT5 "          "
+
+using android::base::StringPrintf;
 using android::hardware::hidl_bitfield;
 using android::hardware::hidl_vec;
 using namespace android::hardware::input;
@@ -646,6 +655,30 @@
     mEvents.push(std::make_unique<NotifyDeviceResetArgs>(args));
 }
 
+void MotionClassifier::dump(std::string& dump) {
+    std::scoped_lock lock(mLock);
+    std::string serviceStatus = mService->ping().isOk() ? "running" : " not responding";
+    dump += StringPrintf(INDENT2 "mService status: %s\n", serviceStatus.c_str());
+    dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n",
+            mEvents.size(), MAX_EVENTS);
+    dump += INDENT2 "mClassifications, mLastDownTimes:\n";
+    dump += INDENT3 "Device Id\tClassification\tLast down time";
+    // Combine mClassifications and mLastDownTimes into a single table.
+    // Create a superset of device ids.
+    std::unordered_set<int32_t> deviceIds;
+    std::for_each(mClassifications.begin(), mClassifications.end(),
+            [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
+    std::for_each(mLastDownTimes.begin(), mLastDownTimes.end(),
+            [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
+    for(int32_t deviceId : deviceIds) {
+        const MotionClassification classification =
+                getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
+        const nsecs_t downTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
+        dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64,
+                deviceId, motionClassificationToString(classification), downTime);
+    }
+}
+
 // --- InputClassifier ---
 
 InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) :
@@ -694,4 +727,16 @@
     mListener->notifyDeviceReset(args);
 }
 
+void InputClassifier::dump(std::string& dump) {
+    dump += "Input Classifier State:\n";
+
+    dump += INDENT1 "Motion Classifier:\n";
+    if (mMotionClassifier) {
+        mMotionClassifier->dump(dump);
+    } else {
+        dump += INDENT2 "<nullptr>";
+    }
+    dump += "\n";
+}
+
 } // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index cb46494..4b9dae2 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -70,6 +70,11 @@
     virtual MotionClassification classify(const NotifyMotionArgs& args) = 0;
     virtual void reset() = 0;
     virtual void reset(const NotifyDeviceResetArgs& args) = 0;
+
+    /**
+     * Dump the state of the motion classifier
+     */
+    virtual void dump(std::string& dump) = 0;
 };
 
 /**
@@ -77,6 +82,12 @@
  * Provides classification to events.
  */
 class InputClassifierInterface : public virtual RefBase, public InputListenerInterface {
+public:
+    /**
+     * Dump the state of the input classifier.
+     * This method may be called on any thread (usually by the input manager).
+     */
+    virtual void dump(std::string& dump) = 0;
 protected:
     InputClassifierInterface() { }
     virtual ~InputClassifierInterface() { }
@@ -110,6 +121,8 @@
     virtual void reset() override;
     virtual void reset(const NotifyDeviceResetArgs& args) override;
 
+    virtual void dump(std::string& dump) override;
+
 private:
     // The events that need to be sent to the HAL.
     BlockingQueue<ClassifierEvent> mEvents;
@@ -186,6 +199,8 @@
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
 
+    virtual void dump(std::string& dump) override;
+
 private:
     std::unique_ptr<MotionClassifierInterface> mMotionClassifier = nullptr;
     // The next stage to pass input events to
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index b3b9e3e..a7fd9ba 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -84,6 +84,10 @@
     return mReader;
 }
 
+sp<InputClassifierInterface> InputManager::getClassifier() {
+    return mClassifier;
+}
+
 sp<InputDispatcherInterface> InputManager::getDispatcher() {
     return mDispatcher;
 }
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 142ec0c..e632da3 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -90,6 +90,7 @@
     virtual status_t stop();
 
     virtual sp<InputReaderInterface> getReader();
+    virtual sp<InputClassifierInterface> getClassifier();
     virtual sp<InputDispatcherInterface> getDispatcher();
 
     virtual void setInputWindows(const Vector<InputWindowInfo>& handles);