Notify MetricsCollector of device interaction from Dispatcher
InputDispatcher will notify the metrics collector whenever an
interaction occurs between an input device and a UID through its policy.
Bug: 275726706
Test: atest inputflinger_tests
Test: statsd_testdrive
Change-Id: Ic62b351263542577328db00c7feb5ff6042f6fe0
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fbbb388..2054329 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1955,7 +1955,7 @@
ALOGD("dispatchEventToCurrentInputTargets");
}
- updateInteractionTokensLocked(*eventEntry, inputTargets);
+ processInteractionsLocked(*eventEntry, inputTargets);
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
@@ -2830,6 +2830,7 @@
}
InputTarget inputTarget;
inputTarget.inputChannel = inputChannel;
+ inputTarget.windowHandle = windowHandle;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowHandle->getInfo()->globalScaleFactor;
inputTarget.firstDownTimeInTarget = firstDownTimeInTarget;
@@ -3408,38 +3409,49 @@
}
/**
- * This function is purely for debugging. It helps us understand where the user interaction
- * was taking place. For example, if user is touching launcher, we will see a log that user
- * started interacting with launcher. In that example, the event would go to the wallpaper as well.
- * We will see both launcher and wallpaper in that list.
- * Once the interaction with a particular set of connections starts, no new logs will be printed
- * until the set of interacted connections changes.
+ * This function is for debugging and metrics collection. It has two roles.
*
- * The following items are skipped, to reduce the logspam:
- * ACTION_OUTSIDE: any windows that are receiving ACTION_OUTSIDE are not logged
- * ACTION_UP: any windows that receive ACTION_UP are not logged (for both keys and motions).
- * This includes situations like the soft BACK button key. When the user releases (lifts up the
- * finger) the back button, then navigation bar will inject KEYCODE_BACK with ACTION_UP.
- * Both of those ACTION_UP events would not be logged
+ * The first role is to log input interaction with windows, which helps determine what the user was
+ * interacting with. For example, if user is touching launcher, we will see an input_interaction log
+ * that user started interacting with launcher window, as well as any other window that received
+ * that gesture, such as the wallpaper or other spy windows. A new input_interaction is only logged
+ * when the set of tokens that received the event changes. It is not logged again as long as the
+ * user is interacting with the same windows.
+ *
+ * The second role is to track input device activity for metrics collection. For each input event,
+ * we report the set of UIDs that the input device interacted with to the policy. Unlike for the
+ * input_interaction logs, the device interaction is reported even when the set of interaction
+ * tokens do not change.
+ *
+ * For these purposes, we do not count ACTION_OUTSIDE, ACTION_UP and ACTION_CANCEL actions as
+ * interaction. This includes up and cancel events for both keys and motions.
*/
-void InputDispatcher::updateInteractionTokensLocked(const EventEntry& entry,
- const std::vector<InputTarget>& targets) {
+void InputDispatcher::processInteractionsLocked(const EventEntry& entry,
+ const std::vector<InputTarget>& targets) {
+ int32_t deviceId;
+ nsecs_t eventTime;
// Skip ACTION_UP events, and all events other than keys and motions
if (entry.type == EventEntry::Type::KEY) {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
return;
}
+ deviceId = keyEntry.deviceId;
+ eventTime = keyEntry.eventTime;
} else if (entry.type == EventEntry::Type::MOTION) {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);
if (motionEntry.action == AMOTION_EVENT_ACTION_UP ||
- motionEntry.action == AMOTION_EVENT_ACTION_CANCEL) {
+ motionEntry.action == AMOTION_EVENT_ACTION_CANCEL ||
+ MotionEvent::getActionMasked(motionEntry.action) == AMOTION_EVENT_ACTION_POINTER_UP) {
return;
}
+ deviceId = motionEntry.deviceId;
+ eventTime = motionEntry.eventTime;
} else {
return; // Not a key or a motion
}
+ std::set<int32_t> interactionUids;
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> newConnectionTokens;
std::vector<std::shared_ptr<Connection>> newConnections;
for (const InputTarget& target : targets) {
@@ -3454,7 +3466,18 @@
}
newConnectionTokens.insert(std::move(token));
newConnections.emplace_back(connection);
+ if (target.windowHandle) {
+ interactionUids.emplace(target.windowHandle->getInfo()->ownerUid);
+ }
}
+
+ auto command = [this, deviceId, eventTime, uids = std::move(interactionUids)]()
+ REQUIRES(mLock) {
+ scoped_unlock unlock(mLock);
+ mPolicy.notifyDeviceInteraction(deviceId, eventTime, uids);
+ };
+ postCommandLocked(std::move(command));
+
if (newConnectionTokens == mInteractionConnectionTokens) {
return; // no change
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 6b22f2f..ae365cd 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -447,8 +447,8 @@
// when switching touch mode state).
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens
GUARDED_BY(mLock);
- void updateInteractionTokensLocked(const EventEntry& entry,
- const std::vector<InputTarget>& targets) REQUIRES(mLock);
+ void processInteractionsLocked(const EventEntry& entry, const std::vector<InputTarget>& targets)
+ REQUIRES(mLock);
// Dispatch inbound events.
bool dispatchConfigurationChangedLocked(nsecs_t currentTime,
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 7b12f81..3bf8b68 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -17,6 +17,7 @@
#pragma once
#include <ftl/flags.h>
+#include <gui/WindowInfo.h>
#include <gui/constants.h>
#include <input/InputTransport.h>
#include <ui/Transform.h>
@@ -114,6 +115,10 @@
// Transform per pointerId.
ui::Transform pointerTransforms[MAX_POINTERS];
+ // The window that this input target is being dispatched to. It is possible for this to be
+ // null for cases like global monitors.
+ sp<gui::WindowInfoHandle> windowHandle;
+
void addPointers(std::bitset<MAX_POINTER_ID + 1> pointerIds, const ui::Transform& transform);
void setDefaultPointerTransform(const ui::Transform& transform);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 5539915..69caa99 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -22,6 +22,7 @@
#include <gui/InputApplication.h>
#include <input/Input.h>
#include <utils/RefBase.h>
+#include <set>
namespace android {
@@ -136,6 +137,10 @@
/* Notifies the policy that the drag window has moved over to another window */
virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0;
+
+ /* Notifies the policy that there was an input device interaction with apps. */
+ virtual void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
+ const std::set<int32_t>& uids) = 0;
};
} // namespace android