From 5c02a719954b4e2c3221aefe75a7b151bbf91c01 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 15 May 2023 15:45:02 -0700 Subject: Convert InputVerifier to rust To establish some basic rust infrastructure for input code, convert the InputVerifier into rust. Currently, we use bindgen for interfacing between cpp and rust. In a future CL, this may be changed to an aidl interface instead. The logs and verifications can be enabled via: adb shell setprop log.tag.InputTransportVerifyEvents DEBUG adb shell setprop log.tag.InputVerifierLogEvents DEBUG adb shell setprop log.tag.InputDispatcherVerifyEvents DEBUG Bug: 271455682 Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests Change-Id: I607fed9f6fc9c38e2c8392f59e9c4facdaf6c68a --- libs/input/InputVerifier.cpp | 118 ++++++++----------------------------------- 1 file changed, 21 insertions(+), 97 deletions(-) (limited to 'libs/input/InputVerifier.cpp') diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index eb758045cc..32b4ca0fc1 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -18,111 +18,35 @@ #include #include +#include "input_verifier.rs.h" -namespace android { +using android::base::Error; +using android::base::Result; +using android::input::RustPointerProperties; -/** - * Log all of the movements that are sent to this verifier. Helps to identify the streams that lead - * to inconsistent events. - * Enable this via "adb shell setprop log.tag.InputVerifierLogEvents DEBUG" - */ -static bool logEvents() { - return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "LogEvents", ANDROID_LOG_INFO); -} +namespace android { // --- InputVerifier --- -InputVerifier::InputVerifier(const std::string& name) : mName(name){}; +InputVerifier::InputVerifier(const std::string& name) + : mVerifier(android::input::verifier::create(name)){}; -void InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords, int32_t flags) { - if (logEvents()) { - LOG(ERROR) << "Processing " << MotionEvent::actionToString(action) << " for device " - << deviceId << " (" << pointerCount << " pointer" - << (pointerCount == 1 ? "" : "s") << ") on " << mName; +Result InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, int32_t flags) { + std::vector rpp; + for (size_t i = 0; i < pointerCount; i++) { + rpp.emplace_back(RustPointerProperties{.id = pointerProperties[i].id}); } - - switch (MotionEvent::getActionMasked(action)) { - case AMOTION_EVENT_ACTION_DOWN: { - auto [it, inserted] = mTouchingPointerIdsByDevice.insert({deviceId, {}}); - if (!inserted) { - LOG(FATAL) << "Got ACTION_DOWN, but already have touching pointers " << it->second - << " for device " << deviceId << " on " << mName; - } - it->second.set(pointerProperties[0].id); - break; - } - case AMOTION_EVENT_ACTION_POINTER_DOWN: { - auto it = mTouchingPointerIdsByDevice.find(deviceId); - if (it == mTouchingPointerIdsByDevice.end()) { - LOG(FATAL) << "Got POINTER_DOWN, but no touching pointers for device " << deviceId - << " on " << mName; - } - it->second.set(pointerProperties[MotionEvent::getActionIndex(action)].id); - break; - } - case AMOTION_EVENT_ACTION_MOVE: { - ensureTouchingPointersMatch(deviceId, pointerCount, pointerProperties, "MOVE"); - break; - } - case AMOTION_EVENT_ACTION_POINTER_UP: { - auto it = mTouchingPointerIdsByDevice.find(deviceId); - if (it == mTouchingPointerIdsByDevice.end()) { - LOG(FATAL) << "Got POINTER_UP, but no touching pointers for device " << deviceId - << " on " << mName; - } - it->second.reset(pointerProperties[MotionEvent::getActionIndex(action)].id); - break; - } - case AMOTION_EVENT_ACTION_UP: { - auto it = mTouchingPointerIdsByDevice.find(deviceId); - if (it == mTouchingPointerIdsByDevice.end()) { - LOG(FATAL) << "Got ACTION_UP, but no record for deviceId " << deviceId << " on " - << mName; - } - const auto& [_, touchingPointerIds] = *it; - if (touchingPointerIds.count() != 1) { - LOG(FATAL) << "Got ACTION_UP, but we have pointers: " << touchingPointerIds - << " for deviceId " << deviceId << " on " << mName; - } - const int32_t pointerId = pointerProperties[0].id; - if (!touchingPointerIds.test(pointerId)) { - LOG(FATAL) << "Got ACTION_UP, but pointerId " << pointerId - << " is not touching. Touching pointers: " << touchingPointerIds - << " for deviceId " << deviceId << " on " << mName; - } - mTouchingPointerIdsByDevice.erase(it); - break; - } - case AMOTION_EVENT_ACTION_CANCEL: { - if ((flags & AMOTION_EVENT_FLAG_CANCELED) != AMOTION_EVENT_FLAG_CANCELED) { - LOG(FATAL) << "For ACTION_CANCEL, must set FLAG_CANCELED"; - } - ensureTouchingPointersMatch(deviceId, pointerCount, pointerProperties, "CANCEL"); - mTouchingPointerIdsByDevice.erase(deviceId); - break; - } + rust::Slice properties{rpp.data(), rpp.size()}; + rust::String errorMessage = + android::input::verifier::process_movement(*mVerifier, deviceId, action, properties, + flags); + if (errorMessage.empty()) { + return {}; + } else { + return Error() << errorMessage; } } -void InputVerifier::ensureTouchingPointersMatch(int32_t deviceId, uint32_t pointerCount, - const PointerProperties* pointerProperties, - const char* action) const { - auto it = mTouchingPointerIdsByDevice.find(deviceId); - if (it == mTouchingPointerIdsByDevice.end()) { - LOG(FATAL) << "Got " << action << ", but no touching pointers for device " << deviceId - << " on " << mName; - } - const auto& [_, touchingPointerIds] = *it; - for (size_t i = 0; i < pointerCount; i++) { - const int32_t pointerId = pointerProperties[i].id; - if (!touchingPointerIds.test(pointerId)) { - LOG(FATAL) << "Got " << action << " for pointerId " << pointerId - << " but the touching pointers are " << touchingPointerIds << " on " - << mName; - } - } -}; - } // namespace android -- cgit v1.2.3-59-g8ed1b From 3117a44a2bb277a99cf90ffb57086a3f2a5aae8f Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 11 Aug 2023 17:48:43 +0000 Subject: InputVerifier: Accept invalid utf-8 strings silently Rust's String seems to have more strict requirements than cpp's std::string, since its creation will fail if the string is not valid in its encoding format. rust::String from cxxbridge escalates the error and causes a panic. Since we do not perform a validity check on the std::string that comes from apps, we must use rust::String::lossy() to create the rust::String for cxxbridge, since it is tolorant of invalid encodings. Bug: 295014987 Test: atest libinput_tests Change-Id: I45ecc6117a43cf25ac6ac15fd57ae25e7174d88f --- libs/input/InputVerifier.cpp | 2 +- libs/input/tests/Android.bp | 1 + libs/input/tests/InputVerifier_test.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 libs/input/tests/InputVerifier_test.cpp (limited to 'libs/input/InputVerifier.cpp') diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index 32b4ca0fc1..9745e89234 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -29,7 +29,7 @@ namespace android { // --- InputVerifier --- InputVerifier::InputVerifier(const std::string& name) - : mVerifier(android::input::verifier::create(name)){}; + : mVerifier(android::input::verifier::create(rust::String::lossy(name))){}; Result InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, const PointerProperties* pointerProperties, diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index cadac88030..86b996b3b6 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -18,6 +18,7 @@ cc_test { "InputDevice_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", + "InputVerifier_test.cpp", "MotionPredictor_test.cpp", "RingBuffer_test.cpp", "TfLiteMotionPredictor_test.cpp", diff --git a/libs/input/tests/InputVerifier_test.cpp b/libs/input/tests/InputVerifier_test.cpp new file mode 100644 index 0000000000..e24fa6ed0b --- /dev/null +++ b/libs/input/tests/InputVerifier_test.cpp @@ -0,0 +1,29 @@ +/* + * Copyright 2023 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 +#include +#include + +namespace android { + +TEST(InputVerifierTest, CreationWithInvalidUtfStringDoesNotCrash) { + constexpr char bytes[] = {static_cast(0xC0), static_cast(0x80)}; + const std::string name(bytes, sizeof(bytes)); + InputVerifier verifier(name); +} + +} // namespace android -- cgit v1.2.3-59-g8ed1b