LatencyAggregatorWithHistograms for InputEventLatencyReported atom.

Currently, input latency metrics cannot be reported on a per-device/per
-source/per-input-event-type granular level. Moreover, regarding
implementation, the input event latencies are aggregated into KLL
sketches (per day) and serialized into the InputEventLatencySketch,
which is a pulled atom, using LatencyAggregator. This means that only
20,000 input event latencies can be recorded per day, the rest are
dropped.

We want to capture latency statistics that can be broken down by per
input device (characterized by its Product ID and Vendor ID), by
source(s) of the input event (such as stylus, touchpad, touchscreen) and
by specific types of input events (such as MOTION_ACTION_DOWN,
MOTION_ACTION_UP, MOTION_ACTION_MOVE, KEY).

The logic for per device input latency metrics lives in
LatencyAggregatorWithHistograms.
Once the flag is rolled out, this will replace LatencyAggregator.

Input events with the same identifier are mapped to an array of 7
histograms. Each histogram's bin sizes are custom to the latency stage
and input event type. When an input event timeline is received, the
relevant bin counter of the corresponding histogram is incremented.

The InputEventLatencyReported atom is pushed every 6 hours by calling
pushLatencyStatistics from InputDispatcher DispatchOnce. After a push,
histograms are cleared.

processSlowEvent was copied from LatencyAggregator to keep logging the
SLOW_iNPUT_EVENT_REPORTED atom.

Tests will be added in a separate CL.

Bug: 270049345
Test: atest inputflinger_tests
Test: manual tests with statsd_testdrive 932
Flag: com.android.input.flags.enable_per_device_input_latency_metrics
Change-Id: I64fb883f4a01889b3600043d21446613a5a5bce7
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 250e72c..da3ac20 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -155,6 +155,10 @@
 // Number of recent events to keep for debugging purposes.
 constexpr size_t RECENT_QUEUE_MAX_SIZE = 10;
 
+// Interval at which we should push the atom gathering input event latencies in
+// LatencyAggregatorWithHistograms
+constexpr nsecs_t LATENCY_STATISTICS_PUSH_INTERVAL = 6 * 3600 * 1000000000LL; // 6 hours
+
 // Event log tags. See EventLogTags.logtags for reference.
 constexpr int LOGTAG_INPUT_INTERACTION = 62000;
 constexpr int LOGTAG_INPUT_FOCUS = 62001;
@@ -944,8 +948,13 @@
         mFocusedDisplayId(ui::LogicalDisplayId::DEFAULT),
         mWindowTokenWithPointerCapture(nullptr),
         mAwaitedApplicationDisplayId(ui::LogicalDisplayId::INVALID),
-        mLatencyAggregator(),
-        mLatencyTracker(&mLatencyAggregator) {
+        mInputEventTimelineProcessor(
+                input_flags::enable_per_device_input_latency_metrics()
+                        ? std::move(std::unique_ptr<InputEventTimelineProcessor>(
+                                  new LatencyAggregatorWithHistograms()))
+                        : std::move(std::unique_ptr<InputEventTimelineProcessor>(
+                                  new LatencyAggregator()))),
+        mLatencyTracker(*mInputEventTimelineProcessor) {
     mLooper = sp<Looper>::make(false);
     mReporter = createInputReporter();
 
@@ -1017,6 +1026,11 @@
         const nsecs_t nextAnrCheck = processAnrsLocked();
         nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);
 
+        if (input_flags::enable_per_device_input_latency_metrics()) {
+            const nsecs_t nextStatisticsPush = processLatencyStatisticsLocked();
+            nextWakeupTime = std::min(nextWakeupTime, nextStatisticsPush);
+        }
+
         // We are about to enter an infinitely long sleep, because we have no commands or
         // pending or queued events
         if (nextWakeupTime == LLONG_MAX) {
@@ -1097,6 +1111,21 @@
     return LLONG_MIN;
 }
 
+/**
+ * Check if enough time has passed since the last latency statistics push.
+ * Return the time at which we should wake up next.
+ */
+nsecs_t InputDispatcher::processLatencyStatisticsLocked() {
+    const nsecs_t currentTime = now();
+    // Log the atom recording latency statistics if more than 6 hours passed from the last
+    // push
+    if (currentTime - mLastStatisticPushTime >= LATENCY_STATISTICS_PUSH_INTERVAL) {
+        mInputEventTimelineProcessor->pushLatencyStatistics();
+        mLastStatisticPushTime = currentTime;
+    }
+    return mLastStatisticPushTime + LATENCY_STATISTICS_PUSH_INTERVAL;
+}
+
 std::chrono::nanoseconds InputDispatcher::getDispatchingTimeoutLocked(
         const std::shared_ptr<Connection>& connection) {
     if (connection->monitor) {
@@ -6055,7 +6084,7 @@
     dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %" PRId64 "ms\n",
                          ns2ms(mConfig.keyRepeatTimeout));
     dump += mLatencyTracker.dump(INDENT2);
-    dump += mLatencyAggregator.dump(INDENT2);
+    dump += mInputEventTimelineProcessor->dump(INDENT2);
     dump += INDENT "InputTracer: ";
     dump += mTracer == nullptr ? "Disabled" : "Enabled";
 }