From 18050095be7d5b7d13861d721f2daf26605ed22b Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 1 Sep 2021 13:32:49 -0700 Subject: Remove RefBase from InputListener interface We don't need refbase for inputlisteners. Remove it, and switch to references, which cannot be null. This way, we can avoid dereferencing the pointers without checking for nullness. Bug: 198472780 Test: atest inputflinger_tests Change-Id: I2f469fd268472c7e78d36812353cff5c52a90163 --- services/inputflinger/InputClassifier.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'services/inputflinger/InputClassifier.cpp') diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index a9cbd5ad02..29d8a0f441 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -345,7 +345,7 @@ void InputClassifier::HalDeathRecipient::serviceDied( // --- InputClassifier --- -InputClassifier::InputClassifier(const sp& listener) +InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {} void InputClassifier::setMotionClassifierEnabled(bool enabled) { @@ -369,12 +369,12 @@ void InputClassifier::setMotionClassifierEnabled(bool enabled) { void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { // pass through - mListener->notifyConfigurationChanged(args); + mListener.notifyConfigurationChanged(args); } void InputClassifier::notifyKey(const NotifyKeyArgs* args) { // pass through - mListener->notifyKey(args); + mListener.notifyKey(args); } void InputClassifier::notifyMotion(const NotifyMotionArgs* args) { @@ -382,28 +382,28 @@ void InputClassifier::notifyMotion(const NotifyMotionArgs* args) { // MotionClassifier is only used for touch events, for now const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args); if (!sendToMotionClassifier) { - mListener->notifyMotion(args); + mListener.notifyMotion(args); return; } NotifyMotionArgs newArgs(*args); newArgs.classification = mMotionClassifier->classify(newArgs); - mListener->notifyMotion(&newArgs); + mListener.notifyMotion(&newArgs); } void InputClassifier::notifySensor(const NotifySensorArgs* args) { // pass through - mListener->notifySensor(args); + mListener.notifySensor(args); } void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) { // pass through - mListener->notifyVibratorState(args); + mListener.notifyVibratorState(args); } void InputClassifier::notifySwitch(const NotifySwitchArgs* args) { // pass through - mListener->notifySwitch(args); + mListener.notifySwitch(args); } void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { @@ -412,12 +412,12 @@ void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mMotionClassifier->reset(*args); } // continue to next stage - mListener->notifyDeviceReset(args); + mListener.notifyDeviceReset(args); } void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { // pass through - mListener->notifyPointerCaptureChanged(args); + mListener.notifyPointerCaptureChanged(args); } void InputClassifier::setMotionClassifier( -- cgit v1.2.3-59-g8ed1b From d948957b396a9301e6e247023d8509f44f6cf87c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 12 Nov 2021 20:08:38 -0800 Subject: Look up source using & instead of equality Source for an input device may be composite. On some devices, the source is specified as TOUCHSCREEN | STYLUS. That means a regular lookup of a MotionRange using just SOURCE_TOUCHSCREEN fails. Update the code to allow composite sources. Also, improve the source dump by printing words instead of numbers. Bug: 198472780 Test: adb shell dumpsys input Change-Id: I8d395f2bb5a6db031e5c2aa6c1f5152ff067a2bb --- include/input/Input.h | 4 ++ libs/input/Input.cpp | 47 ++++++++++++++++++++-- libs/input/InputDevice.cpp | 6 +-- services/inputflinger/InputClassifier.cpp | 3 +- services/inputflinger/dispatcher/Entry.cpp | 20 ++++----- .../inputflinger/dispatcher/InputDispatcher.cpp | 4 -- 6 files changed, 62 insertions(+), 22 deletions(-) (limited to 'services/inputflinger/InputClassifier.cpp') diff --git a/include/input/Input.h b/include/input/Input.h index 7cc595a264..263ade40fb 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -203,6 +203,10 @@ class Parcel; const char* inputEventTypeToString(int32_t type); +std::string inputEventSourceToString(int32_t source); + +bool isFromSource(uint32_t source, uint32_t test); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 24a77209c4..a1d75d5fb1 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -66,10 +66,6 @@ vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) return transformedXy - transformedOrigin; } -bool isFromSource(uint32_t source, uint32_t test) { - return (source & test) == test; -} - bool shouldDisregardTransformation(uint32_t source) { // Do not apply any transformations to axes from joysticks or touchpads. return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK) || @@ -148,6 +144,49 @@ const char* inputEventTypeToString(int32_t type) { return "UNKNOWN"; } +std::string inputEventSourceToString(int32_t source) { + if (source == AINPUT_SOURCE_UNKNOWN) { + return "UNKNOWN"; + } + if (source == static_cast(AINPUT_SOURCE_ANY)) { + return "ANY"; + } + static const std::map SOURCES{ + {AINPUT_SOURCE_KEYBOARD, "KEYBOARD"}, + {AINPUT_SOURCE_DPAD, "DPAD"}, + {AINPUT_SOURCE_GAMEPAD, "GAMEPAD"}, + {AINPUT_SOURCE_TOUCHSCREEN, "TOUCHSCREEN"}, + {AINPUT_SOURCE_MOUSE, "MOUSE"}, + {AINPUT_SOURCE_STYLUS, "STYLUS"}, + {AINPUT_SOURCE_BLUETOOTH_STYLUS, "BLUETOOTH_STYLUS"}, + {AINPUT_SOURCE_TRACKBALL, "TRACKBALL"}, + {AINPUT_SOURCE_MOUSE_RELATIVE, "MOUSE_RELATIVE"}, + {AINPUT_SOURCE_TOUCHPAD, "TOUCHPAD"}, + {AINPUT_SOURCE_TOUCH_NAVIGATION, "TOUCH_NAVIGATION"}, + {AINPUT_SOURCE_JOYSTICK, "JOYSTICK"}, + {AINPUT_SOURCE_HDMI, "HDMI"}, + {AINPUT_SOURCE_SENSOR, "SENSOR"}, + {AINPUT_SOURCE_ROTARY_ENCODER, "ROTARY_ENCODER"}, + }; + std::string result; + for (const auto& [source_entry, str] : SOURCES) { + if ((source & source_entry) == source_entry) { + if (!result.empty()) { + result += " | "; + } + result += str; + } + } + if (result.empty()) { + result = StringPrintf("0x%08x", source); + } + return result; +} + +bool isFromSource(uint32_t source, uint32_t test) { + return (source & test) == test; +} + VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), event.getSource(), event.getDisplayId()}, diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index 015bd81361..ac84627b3f 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -208,10 +208,8 @@ void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t control const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( int32_t axis, uint32_t source) const { - size_t numRanges = mMotionRanges.size(); - for (size_t i = 0; i < numRanges; i++) { - const MotionRange& range = mMotionRanges[i]; - if (range.axis == axis && range.source == source) { + for (const MotionRange& range : mMotionRanges) { + if (range.axis == axis && isFromSource(range.source, source)) { return ⦥ } } diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 29d8a0f441..19cad7b9ad 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -68,7 +68,8 @@ static MotionClassification getMotionClassification(common::V1_0::Classification } static bool isTouchEvent(const NotifyMotionArgs& args) { - return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN; + return isFromSource(args.source, AINPUT_SOURCE_TOUCHPAD) || + isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN); } // --- ClassifierEvent --- diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index c03581d8da..1674afd02e 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -175,13 +175,13 @@ std::string KeyEntry::getDescription() const { if (!GetBoolProperty("ro.debuggable", false)) { return "KeyEvent"; } - return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 - ", source=0x%08x, displayId=%" PRId32 ", action=%s, " + return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 ", source=%s, displayId=%" PRId32 + ", action=%s, " "flags=0x%08x, keyCode=%s(%d), scanCode=%d, metaState=0x%08x, " "repeatCount=%d), policyFlags=0x%08x", - deviceId, eventTime, source, displayId, KeyEvent::actionToString(action), - flags, KeyEvent::getLabel(keyCode), keyCode, scanCode, metaState, - repeatCount, policyFlags); + deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, + KeyEvent::actionToString(action), flags, KeyEvent::getLabel(keyCode), + keyCode, scanCode, metaState, repeatCount, policyFlags); } void KeyEntry::recycle() { @@ -249,12 +249,12 @@ std::string MotionEntry::getDescription() const { } std::string msg; msg += StringPrintf("MotionEvent(deviceId=%d, eventTime=%" PRIu64 - ", source=0x%08x, displayId=%" PRId32 + ", source=%s, displayId=%" PRId32 ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, " "buttonState=0x%08x, " "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, " "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[", - deviceId, eventTime, source, displayId, + deviceId, eventTime, inputEventSourceToString(source).c_str(), displayId, MotionEvent::actionToString(action).c_str(), actionButton, flags, metaState, buttonState, motionClassificationToString(classification), edgeFlags, xPrecision, yPrecision, xCursorPosition, yCursorPosition); @@ -289,9 +289,11 @@ SensorEntry::~SensorEntry() {} std::string SensorEntry::getDescription() const { std::string msg; - msg += StringPrintf("SensorEntry(deviceId=%d, source=0x%08x, sensorType=0x%08x, " + std::string sensorTypeStr(ftl::enum_name(sensorType).value_or("?")); + msg += StringPrintf("SensorEntry(deviceId=%d, source=%s, sensorType=%s, " "accuracy=0x%08x, hwTimestamp=%" PRId64, - deviceId, source, sensorType, accuracy, hwTimestamp); + deviceId, inputEventSourceToString(source).c_str(), sensorTypeStr.c_str(), + accuracy, hwTimestamp); if (!GetBoolProperty("ro.debuggable", false)) { for (size_t i = 0; i < values.size(); i++) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 1b19311b2f..44409a262e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -516,10 +516,6 @@ bool isConnectionResponsive(const Connection& connection) { return true; } -bool isFromSource(uint32_t source, uint32_t test) { - return (source & test) == test; -} - vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) { const vec2 transformedXy = transform.transform(x, y); const vec2 transformedOrigin = transform.transform(0, 0); -- cgit v1.2.3-59-g8ed1b From 6dbd0ce22d86e487b000d4eac75af35c1ffec58e Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 13 Jan 2022 01:24:14 -0800 Subject: Use std::vector in Input.h Convert old code from android's Vector to std::vector. Bug: 167946763 Test: atest libinput_tests Change-Id: I5c53583f6f1e5d577882d94d356f23bdd516be1e --- include/input/Input.h | 12 +++++------ libs/input/Input.cpp | 33 +++++++++++++++++-------------- services/inputflinger/InputClassifier.cpp | 2 -- services/inputflinger/InputManager.h | 1 - 4 files changed, 23 insertions(+), 25 deletions(-) (limited to 'services/inputflinger/InputClassifier.cpp') diff --git a/include/input/Input.h b/include/input/Input.h index ddff144954..f4147a0409 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -31,10 +31,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -88,7 +86,7 @@ enum { */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40, -#ifdef __linux__ +#if defined(__linux__) /** * This event was generated or modified by accessibility service. */ @@ -799,11 +797,11 @@ public: // Low-level accessors. inline const PointerProperties* getPointerProperties() const { - return mPointerProperties.array(); + return mPointerProperties.data(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.data(); } inline const PointerCoords* getSamplePointerCoords() const { - return mSamplePointerCoords.array(); + return mSamplePointerCoords.data(); } static const char* getLabel(int32_t axis); @@ -834,9 +832,9 @@ protected: float mRawYCursorPosition; ui::Transform mRawTransform; nsecs_t mDownTime; - Vector mPointerProperties; + std::vector mPointerProperties; std::vector mSampleEventTimes; - Vector mSamplePointerCoords; + std::vector mSamplePointerCoords; }; /* diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 84dba84e2b..3073d94dbe 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -456,7 +456,8 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int3 mRawTransform = rawTransform; mDownTime = downTime; mPointerProperties.clear(); - mPointerProperties.appendArray(pointerProperties, pointerCount); + mPointerProperties.insert(mPointerProperties.end(), &pointerProperties[0], + &pointerProperties[pointerCount]); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); addSample(eventTime, pointerCoords); @@ -490,8 +491,10 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { mSamplePointerCoords.clear(); size_t pointerCount = other->getPointerCount(); size_t historySize = other->getHistorySize(); - mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() - + (historySize * pointerCount), pointerCount); + mSamplePointerCoords + .insert(mSamplePointerCoords.end(), + &other->mSamplePointerCoords[historySize * pointerCount], + &other->mSamplePointerCoords[historySize * pointerCount + pointerCount]); } } @@ -499,7 +502,8 @@ void MotionEvent::addSample( int64_t eventTime, const PointerCoords* pointerCoords) { mSampleEventTimes.push_back(eventTime); - mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); + mSamplePointerCoords.insert(mSamplePointerCoords.end(), &pointerCoords[0], + &pointerCoords[getPointerCount()]); } int MotionEvent::getSurfaceRotation() const { @@ -569,7 +573,7 @@ float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { size_t pointerCount = mPointerProperties.size(); for (size_t i = 0; i < pointerCount; i++) { - if (mPointerProperties.itemAt(i).id == pointerId) { + if (mPointerProperties[i].id == pointerId) { return i; } } @@ -591,8 +595,7 @@ void MotionEvent::scale(float globalScaleFactor) { size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { - mSamplePointerCoords.editItemAt(i).scale(globalScaleFactor, globalScaleFactor, - globalScaleFactor); + mSamplePointerCoords[i].scale(globalScaleFactor, globalScaleFactor, globalScaleFactor); } } @@ -686,15 +689,15 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mDownTime = parcel->readInt64(); mPointerProperties.clear(); - mPointerProperties.setCapacity(pointerCount); + mPointerProperties.reserve(pointerCount); mSampleEventTimes.clear(); mSampleEventTimes.reserve(sampleCount); mSamplePointerCoords.clear(); - mSamplePointerCoords.setCapacity(sampleCount * pointerCount); + mSamplePointerCoords.reserve(sampleCount * pointerCount); for (size_t i = 0; i < pointerCount; i++) { - mPointerProperties.push(); - PointerProperties& properties = mPointerProperties.editTop(); + mPointerProperties.push_back({}); + PointerProperties& properties = mPointerProperties.back(); properties.id = parcel->readInt32(); properties.toolType = parcel->readInt32(); } @@ -703,8 +706,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { sampleCount--; mSampleEventTimes.push_back(parcel->readInt64()); for (size_t i = 0; i < pointerCount; i++) { - mSamplePointerCoords.push(); - status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); + mSamplePointerCoords.push_back({}); + status_t status = mSamplePointerCoords.back().readFromParcel(parcel); if (status) { return status; } @@ -750,12 +753,12 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { - const PointerProperties& properties = mPointerProperties.itemAt(i); + const PointerProperties& properties = mPointerProperties[i]; parcel->writeInt32(properties.id); parcel->writeInt32(properties.toolType); } - const PointerCoords* pc = mSamplePointerCoords.array(); + const PointerCoords* pc = mSamplePointerCoords.data(); for (size_t h = 0; h < sampleCount; h++) { parcel->writeInt64(mSampleEventTimes[h]); for (size_t i = 0; i < pointerCount; i++) { diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 19cad7b9ad..6c4b11e0e5 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -29,8 +29,6 @@ #endif #include -#include - #define INDENT1 " " #define INDENT2 " " #define INDENT3 " " diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index a6baf2f56d..e00028364a 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -33,7 +33,6 @@ #include #include #include -#include using android::os::BnInputFlinger; -- cgit v1.2.3-59-g8ed1b From 34d6fef6b1b33991677f0d9d0ac74f8f43c95092 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 1 Feb 2022 19:03:45 -0800 Subject: Use InputProcessor instead of InputClassifier Convert InputClassifier to aidl and use it inside framework's InputClassifier. Bug: 167946763 Test: verified on the actual device Change-Id: I62520d424a42bead59904d5a9accea5325b9e8cb --- services/inputflinger/Android.bp | 5 +- services/inputflinger/InputClassifier.cpp | 184 ++++++---- services/inputflinger/InputClassifier.h | 69 ++-- services/inputflinger/InputClassifierConverter.cpp | 379 --------------------- services/inputflinger/InputClassifierConverter.h | 34 -- services/inputflinger/InputCommonConverter.cpp | 339 ++++++++++++++++++ services/inputflinger/InputCommonConverter.h | 31 ++ .../tests/InputClassifierConverter_test.cpp | 21 +- .../inputflinger/tests/InputClassifier_test.cpp | 51 ++- 9 files changed, 556 insertions(+), 557 deletions(-) delete mode 100644 services/inputflinger/InputClassifierConverter.cpp delete mode 100644 services/inputflinger/InputClassifierConverter.h create mode 100644 services/inputflinger/InputCommonConverter.cpp create mode 100644 services/inputflinger/InputCommonConverter.h (limited to 'services/inputflinger/InputClassifier.cpp') diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 22a69e5a30..5d4225dc75 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -48,7 +48,7 @@ filegroup { name: "libinputflinger_sources", srcs: [ "InputClassifier.cpp", - "InputClassifierConverter.cpp", + "InputCommonConverter.cpp", "UnwantedInteractionBlocker.cpp", "InputManager.cpp", ], @@ -58,9 +58,10 @@ cc_defaults { name: "libinputflinger_defaults", srcs: [":libinputflinger_sources"], shared_libs: [ - "android.hardware.input.classifier@1.0", + "android.hardware.input.processor-V1-ndk", "libbase", "libbinder", + "libbinder_ndk", "libchrome", "libcrypto", "libcutils", diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 6c4b11e0e5..3ea0986d41 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -17,13 +17,15 @@ #define LOG_TAG "InputClassifier" #include "InputClassifier.h" -#include "InputClassifierConverter.h" +#include "InputCommonConverter.h" -#include #include -#include +#include +#include #include #include +#include +#include #if defined(__linux__) #include #endif @@ -36,10 +38,9 @@ #define INDENT5 " " using android::base::StringPrintf; -using android::hardware::hidl_bitfield; -using android::hardware::hidl_vec; -using android::hardware::Return; -using namespace android::hardware::input; +using namespace std::chrono_literals; +using namespace ::aidl::android::hardware::input; +using aidl::android::hardware::input::processor::IInputProcessor; namespace android { @@ -55,13 +56,13 @@ static V getValueForKey(const std::unordered_map& map, K key, V defaultVal return it->second; } -static MotionClassification getMotionClassification(common::V1_0::Classification classification) { +static MotionClassification getMotionClassification(common::Classification classification) { static_assert(MotionClassification::NONE == - static_cast(common::V1_0::Classification::NONE)); + static_cast(common::Classification::NONE)); static_assert(MotionClassification::AMBIGUOUS_GESTURE == - static_cast(common::V1_0::Classification::AMBIGUOUS_GESTURE)); + static_cast(common::Classification::AMBIGUOUS_GESTURE)); static_assert(MotionClassification::DEEP_PRESS == - static_cast(common::V1_0::Classification::DEEP_PRESS)); + static_cast(common::Classification::DEEP_PRESS)); return static_cast(classification); } @@ -70,6 +71,56 @@ static bool isTouchEvent(const NotifyMotionArgs& args) { isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN); } +static void setCurrentThreadName(const char* name) { +#if defined(__linux__) + // Set the thread name for debugging + pthread_setname_np(pthread_self(), name); +#else + (void*)(name); // prevent unused variable warning +#endif +} + +static std::shared_ptr getService() { + const std::string aidl_instance_name = std::string(IInputProcessor::descriptor) + "/default"; + + if (!AServiceManager_isDeclared(aidl_instance_name.c_str())) { + ALOGI("HAL %s is not declared", aidl_instance_name.c_str()); + return nullptr; + } + + ndk::SpAIBinder binder(AServiceManager_waitForService(aidl_instance_name.c_str())); + return IInputProcessor::fromBinder(binder); +} + +// Temporarily releases a held mutex for the lifetime of the instance. +// Named to match std::scoped_lock +class scoped_unlock { +public: + explicit scoped_unlock(std::mutex& mutex) : mMutex(mutex) { mMutex.unlock(); } + ~scoped_unlock() { mMutex.lock(); } + +private: + std::mutex& mMutex; +}; + +// --- ScopedDeathRecipient --- +ScopedDeathRecipient::ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied, + void* cookie) + : mCookie(cookie) { + mRecipient = AIBinder_DeathRecipient_new(onBinderDied); +} + +void ScopedDeathRecipient::linkToDeath(AIBinder* binder) { + binder_status_t linked = AIBinder_linkToDeath(binder, mRecipient, mCookie); + if (linked != STATUS_OK) { + ALOGE("Could not link death recipient to the HAL death"); + } +} + +ScopedDeathRecipient::~ScopedDeathRecipient() { + AIBinder_DeathRecipient_delete(mRecipient); +} + // --- ClassifierEvent --- ClassifierEvent::ClassifierEvent(std::unique_ptr args) : @@ -118,9 +169,8 @@ std::optional ClassifierEvent::getDeviceId() const { // --- MotionClassifier --- -MotionClassifier::MotionClassifier( - sp service) - : mEvents(MAX_EVENTS), mService(service) { +MotionClassifier::MotionClassifier(std::shared_ptr service) + : mEvents(MAX_EVENTS), mService(std::move(service)) { // Under normal operation, we do not need to reset the HAL here. But in the case where system // crashed, but HAL didn't, we may be connecting to an existing HAL process that might already // have received events in the past. That means, that HAL could be in an inconsistent state @@ -135,23 +185,10 @@ MotionClassifier::MotionClassifier( } std::unique_ptr MotionClassifier::create( - sp deathRecipient) { - sp service = - classifier::V1_0::IInputClassifier::getService(); - if (!service) { - // Not really an error, maybe the device does not have this HAL, - // but somehow the feature flag is flipped - ALOGI("Could not obtain InputClassifier HAL"); - return nullptr; - } - - const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false); - if (!linked) { - ALOGE("Could not link death recipient to the HAL death"); - return nullptr; - } + std::shared_ptr service) { + LOG_ALWAYS_FATAL_IF(service == nullptr); // Using 'new' to access a non-public constructor - return std::unique_ptr(new MotionClassifier(service)); + return std::unique_ptr(new MotionClassifier(std::move(service))); } MotionClassifier::~MotionClassifier() { @@ -176,14 +213,12 @@ void MotionClassifier::processEvents() { switch (event.type) { case ClassifierEventType::MOTION: { NotifyMotionArgs* motionArgs = static_cast(event.args.get()); - common::V1_0::MotionEvent motionEvent = - notifyMotionArgsToHalMotionEvent(*motionArgs); - Return response = mService->classify(motionEvent); - halResponseOk = response.isOk(); - if (halResponseOk) { - common::V1_0::Classification halClassification = response; + common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs); + common::Classification classification; + ndk::ScopedAStatus response = mService->classify(motionEvent, &classification); + if (response.isOk()) { updateClassification(motionArgs->deviceId, motionArgs->eventTime, - getMotionClassification(halClassification)); + getMotionClassification(classification)); } break; } @@ -300,7 +335,8 @@ const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) { if (!mService) { return "null"; } - if (mService->ping().isOk()) { + + if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) { return "running"; } return "not responding"; @@ -329,40 +365,53 @@ void MotionClassifier::dump(std::string& dump) { } } -// --- HalDeathRecipient +// --- InputClassifier --- -InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {} +InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {} -void InputClassifier::HalDeathRecipient::serviceDied( - uint64_t cookie, const wp& who) { - sp service = who.promote(); - if (service) { - service->unlinkToDeath(this); +void InputClassifier::onBinderDied(void* cookie) { + InputClassifier* classifier = static_cast(cookie); + if (classifier == nullptr) { + LOG_ALWAYS_FATAL("Cookie is not valid"); + return; } - mParent.setMotionClassifier(nullptr); + classifier->setMotionClassifierEnabled(false); } -// --- InputClassifier --- - -InputClassifier::InputClassifier(InputListenerInterface& listener) - : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {} - void InputClassifier::setMotionClassifierEnabled(bool enabled) { + std::scoped_lock lock(mLock); if (enabled) { ALOGI("Enabling motion classifier"); - if (mInitializeMotionClassifierThread.joinable()) { - mInitializeMotionClassifierThread.join(); + if (mInitializeMotionClassifier.valid()) { + scoped_unlock unlock(mLock); + std::future_status status = mInitializeMotionClassifier.wait_for(5s); + if (status != std::future_status::ready) { + /** + * We don't have a better option here than to crash. We can't stop the thread, + * and we can't continue because 'mInitializeMotionClassifier' will block in its + * destructor. + */ + LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!"); + } } - mInitializeMotionClassifierThread = std::thread( - [this] { setMotionClassifier(MotionClassifier::create(mHalDeathRecipient)); }); -#if defined(__linux__) - // Set the thread name for debugging - pthread_setname_np(mInitializeMotionClassifierThread.native_handle(), - "Create MotionClassifier"); -#endif + mInitializeMotionClassifier = std::async(std::launch::async, [this] { + setCurrentThreadName("Create MotionClassifier"); + std::shared_ptr service = getService(); + if (service == nullptr) { + // Keep the MotionClassifier null, no service was found + return; + } + { // acquire lock + std::scoped_lock threadLock(mLock); + mHalDeathRecipient = + std::make_unique(onBinderDied, this /*cookie*/); + mHalDeathRecipient->linkToDeath(service->asBinder().get()); + setMotionClassifierLocked(MotionClassifier::create(std::move(service))); + } // release lock + }); } else { ALOGI("Disabling motion classifier"); - setMotionClassifier(nullptr); + setMotionClassifierLocked(nullptr); } } @@ -419,9 +468,13 @@ void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChan mListener.notifyPointerCaptureChanged(args); } -void InputClassifier::setMotionClassifier( - std::unique_ptr motionClassifier) { - std::scoped_lock lock(mLock); +void InputClassifier::setMotionClassifierLocked( + std::unique_ptr motionClassifier) REQUIRES(mLock) { + if (motionClassifier == nullptr) { + // Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath. + // We can't call 'unlink' here because we don't have the binder handle. + mHalDeathRecipient = nullptr; + } mMotionClassifier = std::move(motionClassifier); } @@ -438,9 +491,6 @@ void InputClassifier::dump(std::string& dump) { } InputClassifier::~InputClassifier() { - if (mInitializeMotionClassifierThread.joinable()) { - mInitializeMotionClassifierThread.join(); - } } } // namespace android diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index deeae7c6f4..e2a0bc26f6 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -18,13 +18,13 @@ #define _UI_INPUT_CLASSIFIER_H #include +#include #include #include +#include #include "BlockingQueue.h" #include "InputListener.h" -#include - namespace android { enum class ClassifierEventType : uint8_t { @@ -102,6 +102,19 @@ public: // --- Implementations --- +class ScopedDeathRecipient { +public: + explicit ScopedDeathRecipient(AIBinder_DeathRecipient_onBinderDied onBinderDied, void* cookie); + ScopedDeathRecipient(const ScopedDeathRecipient&) = delete; + ScopedDeathRecipient& operator=(ScopedDeathRecipient const&) = delete; + void linkToDeath(AIBinder* binder); + ~ScopedDeathRecipient(); + +private: + AIBinder_DeathRecipient* mRecipient; + void* mCookie; +}; + /** * Implementation of MotionClassifierInterface that calls the InputClassifier HAL * in order to determine the classification for the current gesture. @@ -121,7 +134,7 @@ public: * This function should be called asynchronously, because getService takes a long time. */ static std::unique_ptr create( - sp deathRecipient); + std::shared_ptr service); ~MotionClassifier(); @@ -143,7 +156,7 @@ public: private: friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation explicit MotionClassifier( - sp service); + std::shared_ptr service); // The events that need to be sent to the HAL. BlockingQueue mEvents; @@ -162,14 +175,14 @@ private: */ void processEvents(); /** - * Access to the InputClassifier HAL. May be null if init() hasn't completed yet. + * Access to the InputProcessor HAL. May be null if init() hasn't completed yet. * When init() successfully completes, mService is guaranteed to remain non-null and to not * change its value until MotionClassifier is destroyed. * This variable is *not* guarded by mLock in the InputClassifier thread, because * that thread knows exactly when this variable is initialized. * When accessed in any other thread, mService is checked for nullness with a lock. */ - sp mService; + std::shared_ptr mService; std::mutex mLock; /** * Per-device input classifications. Should only be accessed using the @@ -224,21 +237,21 @@ class InputClassifier : public InputClassifierInterface { public: explicit InputClassifier(InputListenerInterface& listener); - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; - virtual void notifyKey(const NotifyKeyArgs* args) override; - virtual void notifyMotion(const NotifyMotionArgs* args) override; - virtual void notifySwitch(const NotifySwitchArgs* args) override; - virtual void notifySensor(const NotifySensorArgs* args) override; - virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; + void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; + void notifyKey(const NotifyKeyArgs* args) override; + void notifyMotion(const NotifyMotionArgs* args) override; + void notifySwitch(const NotifySwitchArgs* args) override; + void notifySensor(const NotifySensorArgs* args) override; + void notifyVibratorState(const NotifyVibratorStateArgs* args) override; + void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; - virtual void dump(std::string& dump) override; + void dump(std::string& dump) override; ~InputClassifier(); // Called from InputManager - virtual void setMotionClassifierEnabled(bool enabled) override; + void setMotionClassifierEnabled(bool enabled) override; private: // Protect access to mMotionClassifier, since it may become null via a hidl callback @@ -247,7 +260,8 @@ private: InputListenerInterface& mListener; std::unique_ptr mMotionClassifier GUARDED_BY(mLock); - std::thread mInitializeMotionClassifierThread; + std::future mInitializeMotionClassifier GUARDED_BY(mLock); + /** * Set the value of mMotionClassifier. * This is called from 2 different threads: @@ -255,25 +269,12 @@ private: * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause * mMotionClassifier to become nullptr. */ - void setMotionClassifier(std::unique_ptr motionClassifier); + void setMotionClassifierLocked(std::unique_ptr motionClassifier) + REQUIRES(mLock); - /** - * The deathRecipient will call setMotionClassifier(null) when the HAL dies. - */ - class HalDeathRecipient : public android::hardware::hidl_death_recipient { - public: - explicit HalDeathRecipient(InputClassifier& parent); - virtual void serviceDied(uint64_t cookie, - const wp& who) override; - - private: - InputClassifier& mParent; - }; - // We retain a reference to death recipient, because the death recipient will be calling - // ~MotionClassifier if the HAL dies. - // If we don't retain a reference, and MotionClassifier is the only owner of the death - // recipient, the serviceDied call will cause death recipient to call its own destructor. - sp mHalDeathRecipient; + static void onBinderDied(void* cookie); + + std::unique_ptr mHalDeathRecipient GUARDED_BY(mLock); }; } // namespace android diff --git a/services/inputflinger/InputClassifierConverter.cpp b/services/inputflinger/InputClassifierConverter.cpp deleted file mode 100644 index b58a188a82..0000000000 --- a/services/inputflinger/InputClassifierConverter.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "InputClassifierConverter.h" - -using android::hardware::hidl_bitfield; -using namespace android::hardware::input; - -namespace android { - -static common::V1_0::Source getSource(uint32_t source) { - static_assert(static_cast(AINPUT_SOURCE_UNKNOWN) == - common::V1_0::Source::UNKNOWN, "SOURCE_UNKNOWN mismatch"); - static_assert(static_cast(AINPUT_SOURCE_KEYBOARD) == - common::V1_0::Source::KEYBOARD, "SOURCE_KEYBOARD mismatch"); - static_assert(static_cast(AINPUT_SOURCE_DPAD) == - common::V1_0::Source::DPAD, "SOURCE_DPAD mismatch"); - static_assert(static_cast(AINPUT_SOURCE_GAMEPAD) == - common::V1_0::Source::GAMEPAD, "SOURCE_GAMEPAD mismatch"); - static_assert(static_cast(AINPUT_SOURCE_TOUCHSCREEN) == - common::V1_0::Source::TOUCHSCREEN, "SOURCE_TOUCHSCREEN mismatch"); - static_assert(static_cast(AINPUT_SOURCE_MOUSE) == - common::V1_0::Source::MOUSE, "SOURCE_MOUSE mismatch"); - static_assert(static_cast(AINPUT_SOURCE_STYLUS) == - common::V1_0::Source::STYLUS, "SOURCE_STYLUS mismatch"); - static_assert(static_cast(AINPUT_SOURCE_BLUETOOTH_STYLUS) == - common::V1_0::Source::BLUETOOTH_STYLUS, "SOURCE_BLUETOOTH_STYLUS mismatch"); - static_assert(static_cast(AINPUT_SOURCE_TRACKBALL) == - common::V1_0::Source::TRACKBALL, "SOURCE_TRACKBALL mismatch"); - static_assert(static_cast(AINPUT_SOURCE_MOUSE_RELATIVE) == - common::V1_0::Source::MOUSE_RELATIVE, "SOURCE_MOUSE_RELATIVE mismatch"); - static_assert(static_cast(AINPUT_SOURCE_TOUCHPAD) == - common::V1_0::Source::TOUCHPAD, "SOURCE_TOUCHPAD mismatch"); - static_assert(static_cast(AINPUT_SOURCE_TOUCH_NAVIGATION) == - common::V1_0::Source::TOUCH_NAVIGATION, "SOURCE_TOUCH_NAVIGATION mismatch"); - static_assert(static_cast(AINPUT_SOURCE_JOYSTICK) == - common::V1_0::Source::JOYSTICK, "SOURCE_JOYSTICK mismatch"); - static_assert(static_cast(AINPUT_SOURCE_ROTARY_ENCODER) == - common::V1_0::Source::ROTARY_ENCODER, "SOURCE_ROTARY_ENCODER mismatch"); - static_assert(static_cast(AINPUT_SOURCE_ANY) == - common::V1_0::Source::ANY, "SOURCE_ANY mismatch"); - return static_cast(source); -} - -static common::V1_0::Action getAction(int32_t actionMasked) { - static_assert(static_cast(AMOTION_EVENT_ACTION_DOWN) == - common::V1_0::Action::DOWN, "ACTION_DOWN mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_UP) == - common::V1_0::Action::UP, "ACTION_UP mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_MOVE) == - common::V1_0::Action::MOVE, "ACTION_MOVE mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_CANCEL) == - common::V1_0::Action::CANCEL, "ACTION_CANCEL mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_OUTSIDE) == - common::V1_0::Action::OUTSIDE, "ACTION_OUTSIDE mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_POINTER_DOWN) == - common::V1_0::Action::POINTER_DOWN, "ACTION_POINTER_DOWN mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_POINTER_UP) == - common::V1_0::Action::POINTER_UP, "ACTION_POINTER_UP mismatch"); - static_assert(static_cast( AMOTION_EVENT_ACTION_HOVER_MOVE) == - common::V1_0::Action::HOVER_MOVE, "ACTION_HOVER_MOVE mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_SCROLL) == - common::V1_0::Action::SCROLL, "ACTION_SCROLL mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_HOVER_ENTER) == - common::V1_0::Action::HOVER_ENTER, "ACTION_HOVER_ENTER mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_HOVER_EXIT) == - common::V1_0::Action::HOVER_EXIT, "ACTION_HOVER_EXIT mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_BUTTON_PRESS) == - common::V1_0::Action::BUTTON_PRESS, "ACTION_BUTTON_PRESS mismatch"); - static_assert(static_cast(AMOTION_EVENT_ACTION_BUTTON_RELEASE) == - common::V1_0::Action::BUTTON_RELEASE, "ACTION_BUTTON_RELEASE mismatch"); - return static_cast(actionMasked); -} - -static common::V1_0::Button getActionButton(int32_t actionButton) { - static_assert(static_cast(0) == - common::V1_0::Button::NONE, "BUTTON_NONE mismatch"); - static_assert(static_cast(AMOTION_EVENT_BUTTON_PRIMARY) == - common::V1_0::Button::PRIMARY, "BUTTON_PRIMARY mismatch"); - static_assert(static_cast(AMOTION_EVENT_BUTTON_SECONDARY) == - common::V1_0::Button::SECONDARY, "BUTTON_SECONDARY mismatch"); - static_assert(static_cast(AMOTION_EVENT_BUTTON_TERTIARY) == - common::V1_0::Button::TERTIARY, "BUTTON_TERTIARY mismatch"); - static_assert(static_cast(AMOTION_EVENT_BUTTON_BACK) == - common::V1_0::Button::BACK, "BUTTON_BACK mismatch"); - static_assert(static_cast(AMOTION_EVENT_BUTTON_FORWARD) == - common::V1_0::Button::FORWARD, "BUTTON_FORWARD mismatch"); - static_assert(static_cast(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) == - common::V1_0::Button::STYLUS_PRIMARY, "BUTTON_STYLUS_PRIMARY mismatch"); - static_assert(static_cast(AMOTION_EVENT_BUTTON_STYLUS_SECONDARY) == - common::V1_0::Button::STYLUS_SECONDARY, "BUTTON_STYLUS_SECONDARY mismatch"); - return static_cast(actionButton); -} - -static hidl_bitfield getFlags(int32_t flags) { - static_assert(static_cast(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) == - common::V1_0::Flag::WINDOW_IS_OBSCURED); - static_assert(static_cast(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE) == - common::V1_0::Flag::IS_GENERATED_GESTURE); - static_assert(static_cast(AMOTION_EVENT_FLAG_TAINTED) == - common::V1_0::Flag::TAINTED); - return static_cast>(flags); -} - -static hidl_bitfield getPolicyFlags(int32_t flags) { - static_assert(static_cast(POLICY_FLAG_WAKE) == - common::V1_0::PolicyFlag::WAKE); - static_assert(static_cast(POLICY_FLAG_VIRTUAL) == - common::V1_0::PolicyFlag::VIRTUAL); - static_assert(static_cast(POLICY_FLAG_FUNCTION) == - common::V1_0::PolicyFlag::FUNCTION); - static_assert(static_cast(POLICY_FLAG_GESTURE) == - common::V1_0::PolicyFlag::GESTURE); - static_assert(static_cast(POLICY_FLAG_INJECTED) == - common::V1_0::PolicyFlag::INJECTED); - static_assert(static_cast(POLICY_FLAG_TRUSTED) == - common::V1_0::PolicyFlag::TRUSTED); - static_assert(static_cast(POLICY_FLAG_FILTERED) == - common::V1_0::PolicyFlag::FILTERED); - static_assert(static_cast(POLICY_FLAG_DISABLE_KEY_REPEAT) == - common::V1_0::PolicyFlag::DISABLE_KEY_REPEAT); - static_assert(static_cast(POLICY_FLAG_INTERACTIVE) == - common::V1_0::PolicyFlag::INTERACTIVE); - static_assert(static_cast(POLICY_FLAG_PASS_TO_USER) == - common::V1_0::PolicyFlag::PASS_TO_USER); - return static_cast>(flags); -} - -static hidl_bitfield getEdgeFlags(int32_t flags) { - static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_NONE) == - common::V1_0::EdgeFlag::NONE); - static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_TOP) == - common::V1_0::EdgeFlag::TOP); - static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_BOTTOM) == - common::V1_0::EdgeFlag::BOTTOM); - static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_LEFT) == - common::V1_0::EdgeFlag::LEFT); - static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_RIGHT) == - common::V1_0::EdgeFlag::RIGHT); - return static_cast>(flags); -} - -static hidl_bitfield getMetastate(int32_t state) { - static_assert(static_cast(AMETA_NONE) == - common::V1_0::Meta::NONE); - static_assert(static_cast(AMETA_ALT_ON) == - common::V1_0::Meta::ALT_ON); - static_assert(static_cast(AMETA_ALT_LEFT_ON) == - common::V1_0::Meta::ALT_LEFT_ON); - static_assert(static_cast(AMETA_ALT_RIGHT_ON) == - common::V1_0::Meta::ALT_RIGHT_ON); - static_assert(static_cast(AMETA_SHIFT_ON) == - common::V1_0::Meta::SHIFT_ON); - static_assert(static_cast(AMETA_SHIFT_LEFT_ON) == - common::V1_0::Meta::SHIFT_LEFT_ON); - static_assert(static_cast(AMETA_SHIFT_RIGHT_ON) == - common::V1_0::Meta::SHIFT_RIGHT_ON); - static_assert(static_cast(AMETA_SYM_ON) == - common::V1_0::Meta::SYM_ON); - static_assert(static_cast(AMETA_FUNCTION_ON) == - common::V1_0::Meta::FUNCTION_ON); - static_assert(static_cast(AMETA_CTRL_ON) == - common::V1_0::Meta::CTRL_ON); - static_assert(static_cast(AMETA_CTRL_LEFT_ON) == - common::V1_0::Meta::CTRL_LEFT_ON); - static_assert(static_cast(AMETA_CTRL_RIGHT_ON) == - common::V1_0::Meta::CTRL_RIGHT_ON); - static_assert(static_cast(AMETA_META_ON) == - common::V1_0::Meta::META_ON); - static_assert(static_cast(AMETA_META_LEFT_ON) == - common::V1_0::Meta::META_LEFT_ON); - static_assert(static_cast(AMETA_META_RIGHT_ON) == - common::V1_0::Meta::META_RIGHT_ON); - static_assert(static_cast(AMETA_CAPS_LOCK_ON) == - common::V1_0::Meta::CAPS_LOCK_ON); - static_assert(static_cast(AMETA_NUM_LOCK_ON) == - common::V1_0::Meta::NUM_LOCK_ON); - static_assert(static_cast(AMETA_SCROLL_LOCK_ON) == - common::V1_0::Meta::SCROLL_LOCK_ON); - return static_cast>(state); -} - -static hidl_bitfield getButtonState(int32_t buttonState) { - // No need for static_assert here. - // The button values have already been asserted in getActionButton(..) above - return static_cast>(buttonState); -} - -static common::V1_0::ToolType getToolType(int32_t toolType) { - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) == - common::V1_0::ToolType::UNKNOWN); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_FINGER) == - common::V1_0::ToolType::FINGER); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_STYLUS) == - common::V1_0::ToolType::STYLUS); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_MOUSE) == - common::V1_0::ToolType::MOUSE); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_ERASER) == - common::V1_0::ToolType::ERASER); - return static_cast(toolType); -} - -// MotionEvent axes asserts -static_assert(static_cast(AMOTION_EVENT_AXIS_X) == - common::V1_0::Axis::X); -static_assert(static_cast(AMOTION_EVENT_AXIS_Y) == - common::V1_0::Axis::Y); -static_assert(static_cast(AMOTION_EVENT_AXIS_PRESSURE) == - common::V1_0::Axis::PRESSURE); -static_assert(static_cast(AMOTION_EVENT_AXIS_SIZE) == - common::V1_0::Axis::SIZE); -static_assert(static_cast(AMOTION_EVENT_AXIS_TOUCH_MAJOR) == - common::V1_0::Axis::TOUCH_MAJOR); -static_assert(static_cast(AMOTION_EVENT_AXIS_TOUCH_MINOR) == - common::V1_0::Axis::TOUCH_MINOR); -static_assert(static_cast(AMOTION_EVENT_AXIS_TOOL_MAJOR) == - common::V1_0::Axis::TOOL_MAJOR); -static_assert(static_cast(AMOTION_EVENT_AXIS_TOOL_MINOR) == - common::V1_0::Axis::TOOL_MINOR); -static_assert(static_cast(AMOTION_EVENT_AXIS_ORIENTATION) == - common::V1_0::Axis::ORIENTATION); -static_assert(static_cast(AMOTION_EVENT_AXIS_VSCROLL) == - common::V1_0::Axis::VSCROLL); -static_assert(static_cast(AMOTION_EVENT_AXIS_HSCROLL) == - common::V1_0::Axis::HSCROLL); -static_assert(static_cast(AMOTION_EVENT_AXIS_Z) == - common::V1_0::Axis::Z); -static_assert(static_cast(AMOTION_EVENT_AXIS_RX) == - common::V1_0::Axis::RX); -static_assert(static_cast(AMOTION_EVENT_AXIS_RY) == - common::V1_0::Axis::RY); -static_assert(static_cast(AMOTION_EVENT_AXIS_RZ) == - common::V1_0::Axis::RZ); -static_assert(static_cast(AMOTION_EVENT_AXIS_HAT_X) == - common::V1_0::Axis::HAT_X); -static_assert(static_cast(AMOTION_EVENT_AXIS_HAT_Y) == - common::V1_0::Axis::HAT_Y); -static_assert(static_cast(AMOTION_EVENT_AXIS_LTRIGGER) == - common::V1_0::Axis::LTRIGGER); -static_assert(static_cast(AMOTION_EVENT_AXIS_RTRIGGER) == - common::V1_0::Axis::RTRIGGER); -static_assert(static_cast(AMOTION_EVENT_AXIS_THROTTLE) == - common::V1_0::Axis::THROTTLE); -static_assert(static_cast(AMOTION_EVENT_AXIS_RUDDER) == - common::V1_0::Axis::RUDDER); -static_assert(static_cast(AMOTION_EVENT_AXIS_WHEEL) == - common::V1_0::Axis::WHEEL); -static_assert(static_cast(AMOTION_EVENT_AXIS_GAS) == - common::V1_0::Axis::GAS); -static_assert(static_cast(AMOTION_EVENT_AXIS_BRAKE) == - common::V1_0::Axis::BRAKE); -static_assert(static_cast(AMOTION_EVENT_AXIS_DISTANCE) == - common::V1_0::Axis::DISTANCE); -static_assert(static_cast(AMOTION_EVENT_AXIS_TILT) == - common::V1_0::Axis::TILT); -static_assert(static_cast(AMOTION_EVENT_AXIS_SCROLL) == - common::V1_0::Axis::SCROLL); -static_assert(static_cast(AMOTION_EVENT_AXIS_RELATIVE_X) == - common::V1_0::Axis::RELATIVE_X); -static_assert(static_cast(AMOTION_EVENT_AXIS_RELATIVE_Y) == - common::V1_0::Axis::RELATIVE_Y); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_1) == - common::V1_0::Axis::GENERIC_1); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_2) == - common::V1_0::Axis::GENERIC_2); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_3) == - common::V1_0::Axis::GENERIC_3); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_4) == - common::V1_0::Axis::GENERIC_4); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_5) == - common::V1_0::Axis::GENERIC_5); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_6) == - common::V1_0::Axis::GENERIC_6); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_7) == - common::V1_0::Axis::GENERIC_7); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_8) == - common::V1_0::Axis::GENERIC_8); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_9) == - common::V1_0::Axis::GENERIC_9); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_10) == - common::V1_0::Axis::GENERIC_10); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_11) == - common::V1_0::Axis::GENERIC_11); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_12) == - common::V1_0::Axis::GENERIC_12); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_13) == - common::V1_0::Axis::GENERIC_13); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_14) == - common::V1_0::Axis::GENERIC_14); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_15) == - common::V1_0::Axis::GENERIC_15); -static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_16) == - common::V1_0::Axis::GENERIC_16); - -static common::V1_0::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) { - common::V1_0::VideoFrame out; - out.width = frame.getWidth(); - out.height = frame.getHeight(); - out.data = frame.getData(); - struct timeval timestamp = frame.getTimestamp(); - out.timestamp = seconds_to_nanoseconds(timestamp.tv_sec) + - microseconds_to_nanoseconds(timestamp.tv_usec); - return out; -} - -static std::vector convertVideoFrames( - const std::vector& frames) { - std::vector out; - for (const TouchVideoFrame& frame : frames) { - out.push_back(getHalVideoFrame(frame)); - } - return out; -} - -static void getHidlPropertiesAndCoords(const NotifyMotionArgs& args, - std::vector* outPointerProperties, - std::vector* outPointerCoords) { - outPointerProperties->reserve(args.pointerCount); - outPointerCoords->reserve(args.pointerCount); - for (size_t i = 0; i < args.pointerCount; i++) { - common::V1_0::PointerProperties properties; - properties.id = args.pointerProperties[i].id; - properties.toolType = getToolType(args.pointerProperties[i].toolType); - outPointerProperties->push_back(properties); - - common::V1_0::PointerCoords coords; - // OK to copy bits because we have static_assert for pointerCoords axes - coords.bits = args.pointerCoords[i].bits; - coords.values = std::vector( - args.pointerCoords[i].values, - args.pointerCoords[i].values + BitSet64::count(args.pointerCoords[i].bits)); - outPointerCoords->push_back(coords); - } -} - -common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArgs& args) { - common::V1_0::MotionEvent event; - event.deviceId = args.deviceId; - event.source = getSource(args.source); - event.displayId = args.displayId; - event.downTime = args.downTime; - event.eventTime = args.eventTime; - event.deviceTimestamp = 0; - event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK); - event.actionIndex = MotionEvent::getActionIndex(args.action); - event.actionButton = getActionButton(args.actionButton); - event.flags = getFlags(args.flags); - event.policyFlags = getPolicyFlags(args.policyFlags); - event.edgeFlags = getEdgeFlags(args.edgeFlags); - event.metaState = getMetastate(args.metaState); - event.buttonState = getButtonState(args.buttonState); - event.xPrecision = args.xPrecision; - event.yPrecision = args.yPrecision; - - std::vector pointerProperties; - std::vector pointerCoords; - getHidlPropertiesAndCoords(args, /*out*/&pointerProperties, /*out*/&pointerCoords); - event.pointerProperties = pointerProperties; - event.pointerCoords = pointerCoords; - - event.frames = convertVideoFrames(args.videoFrames); - - return event; -} - -} // namespace android diff --git a/services/inputflinger/InputClassifierConverter.h b/services/inputflinger/InputClassifierConverter.h deleted file mode 100644 index 5154b0bd06..0000000000 --- a/services/inputflinger/InputClassifierConverter.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUT_CLASSIFIER_CONVERTER_H -#define _UI_INPUT_CLASSIFIER_CONVERTER_H - -#include "InputListener.h" -#include - - -namespace android { - -/** - * Convert from framework's NotifyMotionArgs to hidl's common::V1_0::MotionEvent - */ -::android::hardware::input::common::V1_0::MotionEvent notifyMotionArgsToHalMotionEvent( - const NotifyMotionArgs& args); - -} // namespace android - -#endif // _UI_INPUT_CLASSIFIER_CONVERTER_H diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp new file mode 100644 index 0000000000..8aee39fd0b --- /dev/null +++ b/services/inputflinger/InputCommonConverter.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "InputCommonConverter.h" + +using namespace ::aidl::android::hardware::input; + +namespace android { + +static common::Source getSource(uint32_t source) { + static_assert(static_cast(AINPUT_SOURCE_UNKNOWN) == common::Source::UNKNOWN, + "SOURCE_UNKNOWN mismatch"); + static_assert(static_cast(AINPUT_SOURCE_KEYBOARD) == common::Source::KEYBOARD, + "SOURCE_KEYBOARD mismatch"); + static_assert(static_cast(AINPUT_SOURCE_DPAD) == common::Source::DPAD, + "SOURCE_DPAD mismatch"); + static_assert(static_cast(AINPUT_SOURCE_GAMEPAD) == common::Source::GAMEPAD, + "SOURCE_GAMEPAD mismatch"); + static_assert(static_cast(AINPUT_SOURCE_TOUCHSCREEN) == + common::Source::TOUCHSCREEN, + "SOURCE_TOUCHSCREEN mismatch"); + static_assert(static_cast(AINPUT_SOURCE_MOUSE) == common::Source::MOUSE, + "SOURCE_MOUSE mismatch"); + static_assert(static_cast(AINPUT_SOURCE_STYLUS) == common::Source::STYLUS, + "SOURCE_STYLUS mismatch"); + static_assert(static_cast(AINPUT_SOURCE_BLUETOOTH_STYLUS) == + common::Source::BLUETOOTH_STYLUS, + "SOURCE_BLUETOOTH_STYLUS mismatch"); + static_assert(static_cast(AINPUT_SOURCE_TRACKBALL) == common::Source::TRACKBALL, + "SOURCE_TRACKBALL mismatch"); + static_assert(static_cast(AINPUT_SOURCE_MOUSE_RELATIVE) == + common::Source::MOUSE_RELATIVE, + "SOURCE_MOUSE_RELATIVE mismatch"); + static_assert(static_cast(AINPUT_SOURCE_TOUCHPAD) == common::Source::TOUCHPAD, + "SOURCE_TOUCHPAD mismatch"); + static_assert(static_cast(AINPUT_SOURCE_TOUCH_NAVIGATION) == + common::Source::TOUCH_NAVIGATION, + "SOURCE_TOUCH_NAVIGATION mismatch"); + static_assert(static_cast(AINPUT_SOURCE_JOYSTICK) == common::Source::JOYSTICK, + "SOURCE_JOYSTICK mismatch"); + static_assert(static_cast(AINPUT_SOURCE_ROTARY_ENCODER) == + common::Source::ROTARY_ENCODER, + "SOURCE_ROTARY_ENCODER mismatch"); + static_assert(static_cast(AINPUT_SOURCE_HDMI) == common::Source::HDMI); + static_assert(static_cast(AINPUT_SOURCE_SENSOR) == common::Source::SENSOR); + static_assert(static_cast(AINPUT_SOURCE_ANY) == common::Source::ANY, + "SOURCE_ANY mismatch"); + return static_cast(source); +} + +static common::Action getAction(int32_t actionMasked) { + static_assert(static_cast(AMOTION_EVENT_ACTION_DOWN) == common::Action::DOWN, + "ACTION_DOWN mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_UP) == common::Action::UP, + "ACTION_UP mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_MOVE) == common::Action::MOVE, + "ACTION_MOVE mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_CANCEL) == + common::Action::CANCEL, + "ACTION_CANCEL mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_OUTSIDE) == + common::Action::OUTSIDE, + "ACTION_OUTSIDE mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_POINTER_DOWN) == + common::Action::POINTER_DOWN, + "ACTION_POINTER_DOWN mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_POINTER_UP) == + common::Action::POINTER_UP, + "ACTION_POINTER_UP mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_HOVER_MOVE) == + common::Action::HOVER_MOVE, + "ACTION_HOVER_MOVE mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_SCROLL) == + common::Action::SCROLL, + "ACTION_SCROLL mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_HOVER_ENTER) == + common::Action::HOVER_ENTER, + "ACTION_HOVER_ENTER mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_HOVER_EXIT) == + common::Action::HOVER_EXIT, + "ACTION_HOVER_EXIT mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_BUTTON_PRESS) == + common::Action::BUTTON_PRESS, + "ACTION_BUTTON_PRESS mismatch"); + static_assert(static_cast(AMOTION_EVENT_ACTION_BUTTON_RELEASE) == + common::Action::BUTTON_RELEASE, + "ACTION_BUTTON_RELEASE mismatch"); + return static_cast(actionMasked); +} + +static common::Button getActionButton(int32_t actionButton) { + static_assert(static_cast(0) == common::Button::NONE, "BUTTON_NONE mismatch"); + static_assert(static_cast(AMOTION_EVENT_BUTTON_PRIMARY) == + common::Button::PRIMARY, + "BUTTON_PRIMARY mismatch"); + static_assert(static_cast(AMOTION_EVENT_BUTTON_SECONDARY) == + common::Button::SECONDARY, + "BUTTON_SECONDARY mismatch"); + static_assert(static_cast(AMOTION_EVENT_BUTTON_TERTIARY) == + common::Button::TERTIARY, + "BUTTON_TERTIARY mismatch"); + static_assert(static_cast(AMOTION_EVENT_BUTTON_BACK) == common::Button::BACK, + "BUTTON_BACK mismatch"); + static_assert(static_cast(AMOTION_EVENT_BUTTON_FORWARD) == + common::Button::FORWARD, + "BUTTON_FORWARD mismatch"); + static_assert(static_cast(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) == + common::Button::STYLUS_PRIMARY, + "BUTTON_STYLUS_PRIMARY mismatch"); + static_assert(static_cast(AMOTION_EVENT_BUTTON_STYLUS_SECONDARY) == + common::Button::STYLUS_SECONDARY, + "BUTTON_STYLUS_SECONDARY mismatch"); + return static_cast(actionButton); +} + +static common::Flag getFlags(int32_t flags) { + static_assert(static_cast(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED) == + common::Flag::WINDOW_IS_OBSCURED); + static_assert(static_cast(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE) == + common::Flag::IS_GENERATED_GESTURE); + static_assert(static_cast(AMOTION_EVENT_FLAG_TAINTED) == common::Flag::TAINTED); + return static_cast(flags); +} + +static common::PolicyFlag getPolicyFlags(int32_t flags) { + static_assert(static_cast(POLICY_FLAG_WAKE) == common::PolicyFlag::WAKE); + static_assert(static_cast(POLICY_FLAG_VIRTUAL) == + common::PolicyFlag::VIRTUAL); + static_assert(static_cast(POLICY_FLAG_FUNCTION) == + common::PolicyFlag::FUNCTION); + static_assert(static_cast(POLICY_FLAG_GESTURE) == + common::PolicyFlag::GESTURE); + static_assert(static_cast(POLICY_FLAG_INJECTED) == + common::PolicyFlag::INJECTED); + static_assert(static_cast(POLICY_FLAG_TRUSTED) == + common::PolicyFlag::TRUSTED); + static_assert(static_cast(POLICY_FLAG_FILTERED) == + common::PolicyFlag::FILTERED); + static_assert(static_cast(POLICY_FLAG_DISABLE_KEY_REPEAT) == + common::PolicyFlag::DISABLE_KEY_REPEAT); + static_assert(static_cast(POLICY_FLAG_INTERACTIVE) == + common::PolicyFlag::INTERACTIVE); + static_assert(static_cast(POLICY_FLAG_PASS_TO_USER) == + common::PolicyFlag::PASS_TO_USER); + return static_cast(flags); +} + +static common::EdgeFlag getEdgeFlags(int32_t flags) { + static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_NONE) == + common::EdgeFlag::NONE); + static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_TOP) == + common::EdgeFlag::TOP); + static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_BOTTOM) == + common::EdgeFlag::BOTTOM); + static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_LEFT) == + common::EdgeFlag::LEFT); + static_assert(static_cast(AMOTION_EVENT_EDGE_FLAG_RIGHT) == + common::EdgeFlag::RIGHT); + return static_cast(flags); +} + +static common::Meta getMetastate(int32_t state) { + static_assert(static_cast(AMETA_NONE) == common::Meta::NONE); + static_assert(static_cast(AMETA_ALT_ON) == common::Meta::ALT_ON); + static_assert(static_cast(AMETA_ALT_LEFT_ON) == common::Meta::ALT_LEFT_ON); + static_assert(static_cast(AMETA_ALT_RIGHT_ON) == common::Meta::ALT_RIGHT_ON); + static_assert(static_cast(AMETA_SHIFT_ON) == common::Meta::SHIFT_ON); + static_assert(static_cast(AMETA_SHIFT_LEFT_ON) == common::Meta::SHIFT_LEFT_ON); + static_assert(static_cast(AMETA_SHIFT_RIGHT_ON) == common::Meta::SHIFT_RIGHT_ON); + static_assert(static_cast(AMETA_SYM_ON) == common::Meta::SYM_ON); + static_assert(static_cast(AMETA_FUNCTION_ON) == common::Meta::FUNCTION_ON); + static_assert(static_cast(AMETA_CTRL_ON) == common::Meta::CTRL_ON); + static_assert(static_cast(AMETA_CTRL_LEFT_ON) == common::Meta::CTRL_LEFT_ON); + static_assert(static_cast(AMETA_CTRL_RIGHT_ON) == common::Meta::CTRL_RIGHT_ON); + static_assert(static_cast(AMETA_META_ON) == common::Meta::META_ON); + static_assert(static_cast(AMETA_META_LEFT_ON) == common::Meta::META_LEFT_ON); + static_assert(static_cast(AMETA_META_RIGHT_ON) == common::Meta::META_RIGHT_ON); + static_assert(static_cast(AMETA_CAPS_LOCK_ON) == common::Meta::CAPS_LOCK_ON); + static_assert(static_cast(AMETA_NUM_LOCK_ON) == common::Meta::NUM_LOCK_ON); + static_assert(static_cast(AMETA_SCROLL_LOCK_ON) == common::Meta::SCROLL_LOCK_ON); + return static_cast(state); +} + +static common::Button getButtonState(int32_t buttonState) { + // No need for static_assert here. + // The button values have already been asserted in getActionButton(..) above + return static_cast(buttonState); +} + +static common::ToolType getToolType(int32_t toolType) { + static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) == + common::ToolType::UNKNOWN); + static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_FINGER) == + common::ToolType::FINGER); + static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_STYLUS) == + common::ToolType::STYLUS); + static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_MOUSE) == + common::ToolType::MOUSE); + static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_ERASER) == + common::ToolType::ERASER); + return static_cast(toolType); +} + +// MotionEvent axes asserts +static_assert(static_cast(AMOTION_EVENT_AXIS_X) == common::Axis::X); +static_assert(static_cast(AMOTION_EVENT_AXIS_Y) == common::Axis::Y); +static_assert(static_cast(AMOTION_EVENT_AXIS_PRESSURE) == common::Axis::PRESSURE); +static_assert(static_cast(AMOTION_EVENT_AXIS_SIZE) == common::Axis::SIZE); +static_assert(static_cast(AMOTION_EVENT_AXIS_TOUCH_MAJOR) == + common::Axis::TOUCH_MAJOR); +static_assert(static_cast(AMOTION_EVENT_AXIS_TOUCH_MINOR) == + common::Axis::TOUCH_MINOR); +static_assert(static_cast(AMOTION_EVENT_AXIS_TOOL_MAJOR) == common::Axis::TOOL_MAJOR); +static_assert(static_cast(AMOTION_EVENT_AXIS_TOOL_MINOR) == common::Axis::TOOL_MINOR); +static_assert(static_cast(AMOTION_EVENT_AXIS_ORIENTATION) == + common::Axis::ORIENTATION); +static_assert(static_cast(AMOTION_EVENT_AXIS_VSCROLL) == common::Axis::VSCROLL); +static_assert(static_cast(AMOTION_EVENT_AXIS_HSCROLL) == common::Axis::HSCROLL); +static_assert(static_cast(AMOTION_EVENT_AXIS_Z) == common::Axis::Z); +static_assert(static_cast(AMOTION_EVENT_AXIS_RX) == common::Axis::RX); +static_assert(static_cast(AMOTION_EVENT_AXIS_RY) == common::Axis::RY); +static_assert(static_cast(AMOTION_EVENT_AXIS_RZ) == common::Axis::RZ); +static_assert(static_cast(AMOTION_EVENT_AXIS_HAT_X) == common::Axis::HAT_X); +static_assert(static_cast(AMOTION_EVENT_AXIS_HAT_Y) == common::Axis::HAT_Y); +static_assert(static_cast(AMOTION_EVENT_AXIS_LTRIGGER) == common::Axis::LTRIGGER); +static_assert(static_cast(AMOTION_EVENT_AXIS_RTRIGGER) == common::Axis::RTRIGGER); +static_assert(static_cast(AMOTION_EVENT_AXIS_THROTTLE) == common::Axis::THROTTLE); +static_assert(static_cast(AMOTION_EVENT_AXIS_RUDDER) == common::Axis::RUDDER); +static_assert(static_cast(AMOTION_EVENT_AXIS_WHEEL) == common::Axis::WHEEL); +static_assert(static_cast(AMOTION_EVENT_AXIS_GAS) == common::Axis::GAS); +static_assert(static_cast(AMOTION_EVENT_AXIS_BRAKE) == common::Axis::BRAKE); +static_assert(static_cast(AMOTION_EVENT_AXIS_DISTANCE) == common::Axis::DISTANCE); +static_assert(static_cast(AMOTION_EVENT_AXIS_TILT) == common::Axis::TILT); +static_assert(static_cast(AMOTION_EVENT_AXIS_SCROLL) == common::Axis::SCROLL); +static_assert(static_cast(AMOTION_EVENT_AXIS_RELATIVE_X) == common::Axis::RELATIVE_X); +static_assert(static_cast(AMOTION_EVENT_AXIS_RELATIVE_Y) == common::Axis::RELATIVE_Y); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_1) == common::Axis::GENERIC_1); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_2) == common::Axis::GENERIC_2); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_3) == common::Axis::GENERIC_3); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_4) == common::Axis::GENERIC_4); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_5) == common::Axis::GENERIC_5); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_6) == common::Axis::GENERIC_6); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_7) == common::Axis::GENERIC_7); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_8) == common::Axis::GENERIC_8); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_9) == common::Axis::GENERIC_9); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_10) == common::Axis::GENERIC_10); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_11) == common::Axis::GENERIC_11); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_12) == common::Axis::GENERIC_12); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_13) == common::Axis::GENERIC_13); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15); +static_assert(static_cast(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16); + +static common::VideoFrame getHalVideoFrame(const TouchVideoFrame& frame) { + common::VideoFrame out; + out.width = frame.getWidth(); + out.height = frame.getHeight(); + std::vector unsignedData(frame.getData().begin(), frame.getData().end()); + out.data = unsignedData; + struct timeval timestamp = frame.getTimestamp(); + out.timestamp = seconds_to_nanoseconds(timestamp.tv_sec) + + microseconds_to_nanoseconds(timestamp.tv_usec); + return out; +} + +static std::vector convertVideoFrames( + const std::vector& frames) { + std::vector out; + for (const TouchVideoFrame& frame : frames) { + out.push_back(getHalVideoFrame(frame)); + } + return out; +} + +static void getHalPropertiesAndCoords(const NotifyMotionArgs& args, + std::vector& outPointerProperties, + std::vector& outPointerCoords) { + outPointerProperties.reserve(args.pointerCount); + outPointerCoords.reserve(args.pointerCount); + for (size_t i = 0; i < args.pointerCount; i++) { + common::PointerProperties properties; + properties.id = args.pointerProperties[i].id; + properties.toolType = getToolType(args.pointerProperties[i].toolType); + outPointerProperties.push_back(properties); + + common::PointerCoords coords; + // OK to copy bits because we have static_assert for pointerCoords axes + coords.bits = args.pointerCoords[i].bits; + coords.values = std::vector(args.pointerCoords[i].values, + args.pointerCoords[i].values + + BitSet64::count(args.pointerCoords[i].bits)); + outPointerCoords.push_back(coords); + } +} + +common::MotionEvent notifyMotionArgsToHalMotionEvent(const NotifyMotionArgs& args) { + common::MotionEvent event; + event.deviceId = args.deviceId; + event.source = getSource(args.source); + event.displayId = args.displayId; + event.downTime = args.downTime; + event.eventTime = args.eventTime; + event.deviceTimestamp = 0; + event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK); + event.actionIndex = MotionEvent::getActionIndex(args.action); + event.actionButton = getActionButton(args.actionButton); + event.flags = getFlags(args.flags); + event.policyFlags = getPolicyFlags(args.policyFlags); + event.edgeFlags = getEdgeFlags(args.edgeFlags); + event.metaState = getMetastate(args.metaState); + event.buttonState = getButtonState(args.buttonState); + event.xPrecision = args.xPrecision; + event.yPrecision = args.yPrecision; + + std::vector pointerProperties; + std::vector pointerCoords; + getHalPropertiesAndCoords(args, /*out*/ pointerProperties, /*out*/ pointerCoords); + event.pointerProperties = pointerProperties; + event.pointerCoords = pointerCoords; + + event.frames = convertVideoFrames(args.videoFrames); + + return event; +} + +} // namespace android diff --git a/services/inputflinger/InputCommonConverter.h b/services/inputflinger/InputCommonConverter.h new file mode 100644 index 0000000000..4d3b76885f --- /dev/null +++ b/services/inputflinger/InputCommonConverter.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include "InputListener.h" + +namespace android { + +/** + * Convert from framework's NotifyMotionArgs to hidl's common::MotionEvent + */ +::aidl::android::hardware::input::common::MotionEvent notifyMotionArgsToHalMotionEvent( + const NotifyMotionArgs& args); + +} // namespace android diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp index f626d56b8c..81ef9b95f0 100644 --- a/services/inputflinger/tests/InputClassifierConverter_test.cpp +++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ -#include "../InputClassifierConverter.h" +#include "../InputCommonConverter.h" #include #include #include -using namespace android::hardware::input; +using namespace aidl::android::hardware::input; namespace android { @@ -50,8 +50,7 @@ static NotifyMotionArgs generateBasicMotionArgs() { return motionArgs; } -static float getMotionEventAxis(common::V1_0::PointerCoords coords, - common::V1_0::Axis axis) { +static float getMotionEventAxis(common::PointerCoords coords, common::Axis axis) { uint32_t index = BitSet64::getIndexOfBit(static_cast(coords.bits), static_cast(axis)); return coords.values[index]; @@ -68,14 +67,14 @@ TEST(InputClassifierConverterTest, PointerCoordsAxes) { ASSERT_EQ(0.5, motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE)); ASSERT_EQ(3U, BitSet64::count(motionArgs.pointerCoords[0].bits)); - common::V1_0::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs); + common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(motionArgs); - ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::X), - motionArgs.pointerCoords[0].getX()); - ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::Y), - motionArgs.pointerCoords[0].getY()); - ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::V1_0::Axis::SIZE), - motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE)); + ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::X), + motionArgs.pointerCoords[0].getX()); + ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::Y), + motionArgs.pointerCoords[0].getY()); + ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::SIZE), + motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE)); ASSERT_EQ(BitSet64::count(motionArgs.pointerCoords[0].bits), BitSet64::count(motionEvent.pointerCoords[0].bits)); } diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index f13187ddb7..3a7712727a 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -20,12 +20,14 @@ #include "TestInputListener.h" -#include +#include +#include +#include +#include -using namespace android::hardware::input; -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::input::common::V1_0::Classification; +using namespace aidl::android::hardware::input; +using aidl::android::hardware::input::common::Classification; +using aidl::android::hardware::input::processor::IInputProcessor; namespace android { @@ -154,22 +156,17 @@ TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) { /** * A minimal implementation of IInputClassifier. */ -struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier { - Return classify( - const android::hardware::input::common::V1_0::MotionEvent& event) override { - return Classification::NONE; - }; - Return reset() override { return Void(); }; - Return resetDevice(int32_t deviceId) override { return Void(); }; -}; - -/** - * An entity that will be subscribed to the HAL death. - */ -class TestDeathRecipient : public android::hardware::hidl_death_recipient { -public: - virtual void serviceDied(uint64_t cookie, - const wp& who) override{}; +class TestHal : public aidl::android::hardware::input::processor::BnInputProcessor { + ::ndk::ScopedAStatus classify( + const ::aidl::android::hardware::input::common::MotionEvent& in_event, + ::aidl::android::hardware::input::common::Classification* _aidl_return) override { + *_aidl_return = Classification::NONE; + return ndk::ScopedAStatus::ok(); + } + ::ndk::ScopedAStatus reset() override { return ndk::ScopedAStatus::ok(); } + ::ndk::ScopedAStatus resetDevice(int32_t in_deviceId) override { + return ndk::ScopedAStatus::ok(); + } }; // --- MotionClassifierTest --- @@ -178,15 +175,9 @@ class MotionClassifierTest : public testing::Test { protected: std::unique_ptr mMotionClassifier; - virtual void SetUp() override { - mMotionClassifier = MotionClassifier::create(new TestDeathRecipient()); - if (mMotionClassifier == nullptr) { - // If the device running this test does not have IInputClassifier service, - // use the test HAL instead. - // Using 'new' to access non-public constructor - mMotionClassifier = - std::unique_ptr(new MotionClassifier(new TestHal())); - } + void SetUp() override { + std::shared_ptr service = ndk::SharedRefBase::make(); + mMotionClassifier = MotionClassifier::create(std::move(service)); } }; -- cgit v1.2.3-59-g8ed1b From a91d8576d9fbb5c2fecbcad8a4f3eef0d2fcc30f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 17 May 2022 05:03:42 -0700 Subject: Add lock to protect UnwantedInteractionBlocker The call to 'dump' may come from any thread, and therefore could cause a crash. Add a lock to protect this input stage. To run the test: adb shell -t "/data/nativetest64/inputflinger_tests/inputflinger_tests --gtest_filter='*Dump*' --gtest_repeat=100000 --gtest_break_on_failure" Before this patch, the test failed after ~5K - ~13K iterations (took 10-20 seconds to crash). Bug: 232645962 Test: m inputflinger_tests && adb sync data && Change-Id: I2a199690450bc5bb4a8576aa59075e99d37a531b (cherry picked from commit 9f330c542b48dc6edba9aeaff3b3f4bf305713f3) --- include/input/PrintTools.h | 9 ++ libs/input/PrintTools.cpp | 17 +++ services/inputflinger/InputClassifier.cpp | 62 ++++++---- services/inputflinger/InputClassifier.h | 6 +- services/inputflinger/InputManager.cpp | 13 +- services/inputflinger/InputManager.h | 6 +- .../inputflinger/UnwantedInteractionBlocker.cpp | 133 +++++++++------------ services/inputflinger/UnwantedInteractionBlocker.h | 11 +- .../include/UnwantedInteractionBlockerInterface.h | 4 +- .../tests/UnwantedInteractionBlocker_test.cpp | 22 ++++ 10 files changed, 171 insertions(+), 112 deletions(-) (limited to 'services/inputflinger/InputClassifier.cpp') diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h index 7c3b29b55f..0a75278494 100644 --- a/include/input/PrintTools.h +++ b/include/input/PrintTools.h @@ -58,4 +58,13 @@ std::string dumpMap(const std::map& map, std::string (*keyToString)(const const char* toString(bool value); +/** + * Add "prefix" to the beginning of each line in the provided string + * "str". + * The string 'str' is typically multi-line. + * The most common use case for this function is to add some padding + * when dumping state. + */ +std::string addLinePrefix(std::string str, const std::string& prefix); + } // namespace android \ No newline at end of file diff --git a/libs/input/PrintTools.cpp b/libs/input/PrintTools.cpp index 5d6ae4ed91..01f6bf514b 100644 --- a/libs/input/PrintTools.cpp +++ b/libs/input/PrintTools.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "PrintTools" #include +#include namespace android { @@ -24,4 +25,20 @@ const char* toString(bool value) { return value ? "true" : "false"; } +std::string addLinePrefix(std::string str, const std::string& prefix) { + std::stringstream ss; + bool newLineStarted = true; + for (const auto& ch : str) { + if (newLineStarted) { + ss << prefix; + newLineStarted = false; + } + if (ch == '\n') { + newLineStarted = true; + } + ss << ch; + } + return ss.str(); +} + } // namespace android diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 3ea0986d41..8ce2f35d7b 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -367,7 +367,7 @@ void MotionClassifier::dump(std::string& dump) { // --- InputClassifier --- -InputClassifier::InputClassifier(InputListenerInterface& listener) : mListener(listener) {} +InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {} void InputClassifier::onBinderDied(void* cookie) { InputClassifier* classifier = static_cast(cookie); @@ -417,55 +417,67 @@ void InputClassifier::setMotionClassifierEnabled(bool enabled) { void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { // pass through - mListener.notifyConfigurationChanged(args); + mQueuedListener.notifyConfigurationChanged(args); + mQueuedListener.flush(); } void InputClassifier::notifyKey(const NotifyKeyArgs* args) { // pass through - mListener.notifyKey(args); + mQueuedListener.notifyKey(args); + mQueuedListener.flush(); } void InputClassifier::notifyMotion(const NotifyMotionArgs* args) { - std::scoped_lock lock(mLock); - // MotionClassifier is only used for touch events, for now - const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args); - if (!sendToMotionClassifier) { - mListener.notifyMotion(args); - return; - } - - NotifyMotionArgs newArgs(*args); - newArgs.classification = mMotionClassifier->classify(newArgs); - mListener.notifyMotion(&newArgs); + { // acquire lock + std::scoped_lock lock(mLock); + // MotionClassifier is only used for touch events, for now + const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args); + if (!sendToMotionClassifier) { + mQueuedListener.notifyMotion(args); + } else { + NotifyMotionArgs newArgs(*args); + newArgs.classification = mMotionClassifier->classify(newArgs); + mQueuedListener.notifyMotion(&newArgs); + } + } // release lock + mQueuedListener.flush(); } void InputClassifier::notifySensor(const NotifySensorArgs* args) { // pass through - mListener.notifySensor(args); + mQueuedListener.notifySensor(args); + mQueuedListener.flush(); } void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) { // pass through - mListener.notifyVibratorState(args); + mQueuedListener.notifyVibratorState(args); + mQueuedListener.flush(); } void InputClassifier::notifySwitch(const NotifySwitchArgs* args) { // pass through - mListener.notifySwitch(args); + mQueuedListener.notifySwitch(args); + mQueuedListener.flush(); } void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { - std::scoped_lock lock(mLock); - if (mMotionClassifier) { - mMotionClassifier->reset(*args); - } + { // acquire lock + std::scoped_lock lock(mLock); + if (mMotionClassifier) { + mMotionClassifier->reset(*args); + } + } // release lock + // continue to next stage - mListener.notifyDeviceReset(args); + mQueuedListener.notifyDeviceReset(args); + mQueuedListener.flush(); } void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { // pass through - mListener.notifyPointerCaptureChanged(args); + mQueuedListener.notifyPointerCaptureChanged(args); + mQueuedListener.flush(); } void InputClassifier::setMotionClassifierLocked( @@ -490,6 +502,10 @@ void InputClassifier::dump(std::string& dump) { dump += "\n"; } +void InputClassifier::monitor() { + std::scoped_lock lock(mLock); +} + InputClassifier::~InputClassifier() { } diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index e2a0bc26f6..56cf760256 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -96,6 +96,9 @@ public: */ virtual void dump(std::string& dump) = 0; + /* Called by the heatbeat to ensures that the classifier has not deadlocked. */ + virtual void monitor() = 0; + InputClassifierInterface() { } virtual ~InputClassifierInterface() { } }; @@ -247,6 +250,7 @@ public: void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; void dump(std::string& dump) override; + void monitor() override; ~InputClassifier(); @@ -257,7 +261,7 @@ private: // Protect access to mMotionClassifier, since it may become null via a hidl callback std::mutex mLock; // The next stage to pass input events to - InputListenerInterface& mListener; + QueuedInputListener mQueuedListener; std::unique_ptr mMotionClassifier GUARDED_BY(mLock); std::future mInitializeMotionClassifier GUARDED_BY(mLock); diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 7b03631e1f..9767cd9b71 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -62,8 +62,8 @@ InputManager::InputManager( const sp& dispatcherPolicy) { mDispatcher = createInputDispatcher(dispatcherPolicy); mClassifier = std::make_unique(*mDispatcher); - mUnwantedInteractionBlocker = std::make_unique(*mClassifier); - mReader = createInputReader(readerPolicy, *mUnwantedInteractionBlocker); + mBlocker = std::make_unique(*mClassifier); + mReader = createInputReader(readerPolicy, *mBlocker); } InputManager::~InputManager() { @@ -111,7 +111,7 @@ InputReaderInterface& InputManager::getReader() { } UnwantedInteractionBlockerInterface& InputManager::getUnwantedInteractionBlocker() { - return *mUnwantedInteractionBlocker; + return *mBlocker; } InputClassifierInterface& InputManager::getClassifier() { @@ -122,6 +122,13 @@ InputDispatcherInterface& InputManager::getDispatcher() { return *mDispatcher; } +void InputManager::monitor() { + mReader->monitor(); + mBlocker->monitor(); + mClassifier->monitor(); + mDispatcher->monitor(); +} + // Used by tests only. binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 35d2b0fa19..8aad35bf1e 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -90,6 +90,9 @@ public: /* Gets the input dispatcher. */ virtual InputDispatcherInterface& getDispatcher() = 0; + + /* Check that the input stages have not deadlocked. */ + virtual void monitor() = 0; }; class InputManager : public InputManagerInterface, public BnInputFlinger { @@ -108,6 +111,7 @@ public: UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() override; InputClassifierInterface& getClassifier() override; InputDispatcherInterface& getDispatcher() override; + void monitor() override; status_t dump(int fd, const Vector& args) override; binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override; @@ -117,7 +121,7 @@ public: private: std::unique_ptr mReader; - std::unique_ptr mUnwantedInteractionBlocker; + std::unique_ptr mBlocker; std::unique_ptr mClassifier; diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp index b69e16ac85..f57ff33d50 100644 --- a/services/inputflinger/UnwantedInteractionBlocker.cpp +++ b/services/inputflinger/UnwantedInteractionBlocker.cpp @@ -18,6 +18,7 @@ #include "UnwantedInteractionBlocker.h" #include +#include #include #include #include @@ -80,47 +81,6 @@ static int getLinuxToolType(int32_t toolType) { return MT_TOOL_FINGER; } -static std::string addPrefix(std::string str, const std::string& prefix) { - std::stringstream ss; - bool newLineStarted = true; - for (const auto& ch : str) { - if (newLineStarted) { - ss << prefix; - newLineStarted = false; - } - if (ch == '\n') { - newLineStarted = true; - } - ss << ch; - } - return ss.str(); -} - -template -static std::string dumpSet(const std::set& v) { - static_assert(std::is_integral::value, "Only integral types can be printed."); - std::string out; - for (const T& entry : v) { - out += out.empty() ? "{" : ", "; - out += android::base::StringPrintf("%i", entry); - } - return out.empty() ? "{}" : (out + "}"); -} - -template -static std::string dumpMap(const std::map& map) { - static_assert(std::is_integral::value, "Keys should have integral type to be printed."); - static_assert(std::is_integral::value, "Values should have integral type to be printed."); - std::string out; - for (const auto& [k, v] : map) { - if (!out.empty()) { - out += "\n"; - } - out += android::base::StringPrintf("%i : %i", static_cast(k), static_cast(v)); - } - return out; -} - static std::string dumpDeviceInfo(const AndroidPalmFilterDeviceInfo& info) { std::string out; out += StringPrintf("max_x = %.2f\n", info.max_x); @@ -168,10 +128,6 @@ static int32_t resolveActionForPointer(uint8_t pointerIndex, int32_t action) { return AMOTION_EVENT_ACTION_MOVE; } -static const char* toString(bool value) { - return value ? "true" : "false"; -} - std::string toString(const ::ui::InProgressTouchEvdev& touch) { return StringPrintf("x=%.1f, y=%.1f, tracking_id=%i, slot=%zu," " pressure=%.1f, major=%i, minor=%i, " @@ -356,69 +312,87 @@ UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& l UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& listener, bool enablePalmRejection) - : mListener(listener), mEnablePalmRejection(enablePalmRejection) {} + : mQueuedListener(listener), mEnablePalmRejection(enablePalmRejection) {} void UnwantedInteractionBlocker::notifyConfigurationChanged( const NotifyConfigurationChangedArgs* args) { - mListener.notifyConfigurationChanged(args); + mQueuedListener.notifyConfigurationChanged(args); + mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) { - mListener.notifyKey(args); + mQueuedListener.notifyKey(args); + mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) { - const std::vector processedArgs = - mPreferStylusOverTouchBlocker.processMotion(*args); - for (const NotifyMotionArgs& loopArgs : processedArgs) { - notifyMotionInner(&loopArgs); - } + { // acquire lock + std::scoped_lock lock(mLock); + const std::vector processedArgs = + mPreferStylusOverTouchBlocker.processMotion(*args); + for (const NotifyMotionArgs& loopArgs : processedArgs) { + notifyMotionLocked(&loopArgs); + } + } // release lock + + // Call out to the next stage without holding the lock + mQueuedListener.flush(); } -void UnwantedInteractionBlocker::notifyMotionInner(const NotifyMotionArgs* args) { +void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs* args) { auto it = mPalmRejectors.find(args->deviceId); const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source); if (!sendToPalmRejector) { - mListener.notifyMotion(args); + mQueuedListener.notifyMotion(args); return; } - const std::vector newMotions = it->second.processMotion(*args); - for (const NotifyMotionArgs& newArgs : newMotions) { - mListener.notifyMotion(&newArgs); + std::vector processedArgs = it->second.processMotion(*args); + for (const NotifyMotionArgs& loopArgs : processedArgs) { + mQueuedListener.notifyMotion(&loopArgs); } } void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs* args) { - mListener.notifySwitch(args); + mQueuedListener.notifySwitch(args); + mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs* args) { - mListener.notifySensor(args); + mQueuedListener.notifySensor(args); + mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs* args) { - mListener.notifyVibratorState(args); + mQueuedListener.notifyVibratorState(args); + mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs* args) { - auto it = mPalmRejectors.find(args->deviceId); - if (it != mPalmRejectors.end()) { - AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo(); - // Re-create the object instead of resetting it - mPalmRejectors.erase(it); - mPalmRejectors.emplace(args->deviceId, info); - } - mListener.notifyDeviceReset(args); - mPreferStylusOverTouchBlocker.notifyDeviceReset(*args); + { // acquire lock + std::scoped_lock lock(mLock); + auto it = mPalmRejectors.find(args->deviceId); + if (it != mPalmRejectors.end()) { + AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo(); + // Re-create the object instead of resetting it + mPalmRejectors.erase(it); + mPalmRejectors.emplace(args->deviceId, info); + } + mQueuedListener.notifyDeviceReset(args); + mPreferStylusOverTouchBlocker.notifyDeviceReset(*args); + } // release lock + // Send events to the next stage without holding the lock + mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifyPointerCaptureChanged( const NotifyPointerCaptureChangedArgs* args) { - mListener.notifyPointerCaptureChanged(args); + mQueuedListener.notifyPointerCaptureChanged(args); + mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifyInputDevicesChanged( const std::vector& inputDevices) { + std::scoped_lock lock(mLock); if (!mEnablePalmRejection) { // Palm rejection is disabled. Don't create any palm rejector objects. return; @@ -450,20 +424,23 @@ void UnwantedInteractionBlocker::notifyInputDevicesChanged( } void UnwantedInteractionBlocker::dump(std::string& dump) { + std::scoped_lock lock(mLock); dump += "UnwantedInteractionBlocker:\n"; dump += " mPreferStylusOverTouchBlocker:\n"; - dump += addPrefix(mPreferStylusOverTouchBlocker.dump(), " "); + dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), " "); dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection)); dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n", toString(isPalmRejectionEnabled())); dump += mPalmRejectors.empty() ? " mPalmRejectors: None\n" : " mPalmRejectors:\n"; for (const auto& [deviceId, palmRejector] : mPalmRejectors) { dump += StringPrintf(" deviceId = %" PRId32 ":\n", deviceId); - dump += addPrefix(palmRejector.dump(), " "); + dump += addLinePrefix(palmRejector.dump(), " "); } } -void UnwantedInteractionBlocker::monitor() {} +void UnwantedInteractionBlocker::monitor() { + std::scoped_lock lock(mLock); +} UnwantedInteractionBlocker::~UnwantedInteractionBlocker() {} @@ -529,9 +506,9 @@ std::optional SlotState::getSlotForPointerId(int32_t pointerId) const { std::string SlotState::dump() const { std::string out = "mSlotsByPointerId:\n"; - out += addPrefix(dumpMap(mSlotsByPointerId), " ") + "\n"; + out += addLinePrefix(dumpMap(mSlotsByPointerId), " ") + "\n"; out += "mPointerIdsBySlot:\n"; - out += addPrefix(dumpMap(mPointerIdsBySlot), " ") + "\n"; + out += addLinePrefix(dumpMap(mPointerIdsBySlot), " ") + "\n"; return out; } @@ -689,9 +666,9 @@ const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() { std::string PalmRejector::dump() const { std::string out; out += "mDeviceInfo:\n"; - out += addPrefix(dumpDeviceInfo(mDeviceInfo), " "); + out += addLinePrefix(dumpDeviceInfo(mDeviceInfo), " "); out += "mSlotState:\n"; - out += addPrefix(mSlotState.dump(), " "); + out += addLinePrefix(mSlotState.dump(), " "); out += "mSuppressedPointerIds: "; out += dumpSet(mSuppressedPointerIds) + "\n"; return out; diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h index 8a1cd7265e..a43376419f 100644 --- a/services/inputflinger/UnwantedInteractionBlocker.h +++ b/services/inputflinger/UnwantedInteractionBlocker.h @@ -19,6 +19,7 @@ #include #include +#include #include "include/UnwantedInteractionBlockerInterface.h" #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter_util.h" #include "ui/events/ozone/evdev/touch_filter/palm_detection_filter.h" @@ -86,18 +87,20 @@ public: ~UnwantedInteractionBlocker(); private: + std::mutex mLock; // The next stage to pass input events to - InputListenerInterface& mListener; + + QueuedInputListener mQueuedListener; const bool mEnablePalmRejection; // When stylus is down, ignore touch - PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker; + PreferStylusOverTouchBlocker mPreferStylusOverTouchBlocker GUARDED_BY(mLock); // Detect and reject unwanted palms on screen // Use a separate palm rejector for every touch device. - std::map mPalmRejectors; + std::map mPalmRejectors GUARDED_BY(mLock); // TODO(b/210159205): delete this when simultaneous stylus and touch is supported - void notifyMotionInner(const NotifyMotionArgs* args); + void notifyMotionLocked(const NotifyMotionArgs* args) REQUIRES(mLock); }; class SlotState { diff --git a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h index 2327266563..1a6f8472a5 100644 --- a/services/inputflinger/include/UnwantedInteractionBlockerInterface.h +++ b/services/inputflinger/include/UnwantedInteractionBlockerInterface.h @@ -39,11 +39,11 @@ public: /** * Dump the state of the interaction blocker. - * This method may be called on any thread (usually by the input manager). + * This method may be called on any thread (usually by the input manager on a binder thread). */ virtual void dump(std::string& dump) = 0; - /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ + /* Called by the heatbeat to ensures that the blocker has not deadlocked. */ virtual void monitor() = 0; UnwantedInteractionBlockerInterface() {} diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp index e378096df5..0062f426d7 100644 --- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp +++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "TestInputListener.h" @@ -547,6 +548,27 @@ TEST_F(UnwantedInteractionBlockerTest, StylusAfterTouchWorks) { mBlocker->notifyMotion(&args); } +/** + * Call dump, and on another thread, try to send some motions. The blocker should + * not crash. On 2022 hardware, this test requires ~ 13K executions (about 20 seconds) to reproduce + * the original bug. This is meant to be run with "--gtest_repeat=100000 --gtest_break_on_failure" + * options + */ +TEST_F(UnwantedInteractionBlockerTest, DumpCanBeAccessedOnAnotherThread) { + mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()}); + NotifyMotionArgs args1 = generateMotionArgs(0 /*downTime*/, 0 /*eventTime*/, DOWN, {{1, 2, 3}}); + mBlocker->notifyMotion(&args1); + std::thread dumpThread([this]() { + std::string dump; + mBlocker->dump(dump); + }); + NotifyMotionArgs args2 = generateMotionArgs(0 /*downTime*/, 1 /*eventTime*/, MOVE, {{4, 5, 6}}); + mBlocker->notifyMotion(&args2); + NotifyMotionArgs args3 = generateMotionArgs(0 /*downTime*/, 2 /*eventTime*/, UP, {{4, 5, 6}}); + mBlocker->notifyMotion(&args3); + dumpThread.join(); +} + using UnwantedInteractionBlockerTestDeathTest = UnwantedInteractionBlockerTest; /** -- cgit v1.2.3-59-g8ed1b