diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-03-21 23:11:40 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-03-21 23:11:40 +0000 |
commit | 0ff40ae4c65e89f4a769497ddafc4b77f324c5bf (patch) | |
tree | 5055af986a869aa01628dd71161747df32308d50 | |
parent | a1b55870d7e9477405348e2f256772befe770c63 (diff) | |
parent | 1a683cebe3c32f6ee006015e2b811536ea15305e (diff) | |
download | android_frameworks_native-0ff40ae4c65e89f4a769497ddafc4b77f324c5bf.tar.gz android_frameworks_native-0ff40ae4c65e89f4a769497ddafc4b77f324c5bf.tar.bz2 android_frameworks_native-0ff40ae4c65e89f4a769497ddafc4b77f324c5bf.zip |
Snap for 6320329 from 1a683cebe3c32f6ee006015e2b811536ea15305e to qt-qpr3-release
Change-Id: If10a78c294d6b490245ba4283b1dfa9f7c266fb1
-rw-r--r-- | services/inputflinger/Android.bp | 1 | ||||
-rw-r--r-- | services/inputflinger/InputClassifier.cpp | 159 | ||||
-rw-r--r-- | services/inputflinger/InputClassifier.h | 92 | ||||
-rw-r--r-- | services/inputflinger/InputManager.cpp | 4 | ||||
-rw-r--r-- | services/inputflinger/InputManager.h | 2 | ||||
-rw-r--r-- | services/inputflinger/tests/InputClassifier_test.cpp | 55 |
6 files changed, 173 insertions, 140 deletions
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 8dd4d1df6..576c8d8bb 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -47,7 +47,6 @@ cc_library_shared { "liblog", "libutils", "libui", - "server_configurable_flags", ], cflags: [ diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index ef1a2247e..cda0e0cdc 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -27,7 +27,6 @@ #if defined(__linux__) #include <pthread.h> #endif -#include <server_configurable_flags/get_flags.h> #include <unordered_set> #include <android/hardware/input/classifier/1.0/IInputClassifier.h> @@ -46,13 +45,6 @@ using namespace android::hardware::input; namespace android { -static constexpr bool DEBUG = false; - -// Category (=namespace) name for the input settings that are applied at boot time -static const char* INPUT_NATIVE_BOOT = "input_native_boot"; -// Feature flag name for the deep press feature -static const char* DEEP_PRESS_ENABLED = "deep_press_enabled"; - //Max number of elements to store in mEvents. static constexpr size_t MAX_EVENTS = 5; @@ -79,20 +71,6 @@ static bool isTouchEvent(const NotifyMotionArgs& args) { return args.source == AINPUT_SOURCE_TOUCHPAD || args.source == AINPUT_SOURCE_TOUCHSCREEN; } -// Check if the "deep touch" feature is on. -static bool deepPressEnabled() { - std::string flag_value = server_configurable_flags::GetServerConfigurableFlag( - INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true"); - std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower); - if (flag_value == "1" || flag_value == "true") { - ALOGI("Deep press feature enabled."); - return true; - } - ALOGI("Deep press feature is not enabled."); - return false; -} - - // --- ClassifierEvent --- ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) : @@ -141,53 +119,40 @@ std::optional<int32_t> ClassifierEvent::getDeviceId() const { // --- MotionClassifier --- -MotionClassifier::MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient) : - mDeathRecipient(deathRecipient), mEvents(MAX_EVENTS) { - mHalThread = std::thread(&MotionClassifier::callInputClassifierHal, this); +MotionClassifier::MotionClassifier( + sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) + : mEvents(MAX_EVENTS), mService(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 + // once it receives events from the newly created MotionClassifier. + mEvents.push(ClassifierEvent::createHalResetEvent()); + + mHalThread = std::thread(&MotionClassifier::processEvents, this); #if defined(__linux__) // Set the thread name for debugging pthread_setname_np(mHalThread.native_handle(), "InputClassifier"); #endif } -/** - * This function may block for some time to initialize the HAL, so it should only be called - * from the "InputClassifier HAL" thread. - */ -bool MotionClassifier::init() { - ensureHalThread(__func__); +std::unique_ptr<MotionClassifierInterface> MotionClassifier::create( + sp<android::hardware::hidl_death_recipient> deathRecipient) { sp<android::hardware::input::classifier::V1_0::IInputClassifier> 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 false; + return nullptr; } - sp<android::hardware::hidl_death_recipient> recipient = mDeathRecipient.promote(); - if (recipient != nullptr) { - const bool linked = service->linkToDeath(recipient, 0 /* cookie */).withDefault(false); - if (!linked) { - ALOGE("Could not link MotionClassifier to the HAL death"); - return false; - } + const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false); + if (!linked) { + ALOGE("Could not link death recipient to the HAL death"); + return nullptr; } - - // 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 - // once it receives events from the newly created MotionClassifier. - mEvents.push(ClassifierEvent::createHalResetEvent()); - - { - std::scoped_lock lock(mLock); - if (mService) { - ALOGE("MotionClassifier::%s should only be called once", __func__); - } - mService = service; - } - return true; + // Using 'new' to access a non-public constructor + return std::unique_ptr<MotionClassifier>(new MotionClassifier(service)); } MotionClassifier::~MotionClassifier() { @@ -195,14 +160,6 @@ MotionClassifier::~MotionClassifier() { mHalThread.join(); } -void MotionClassifier::ensureHalThread(const char* function) { - if (DEBUG) { - if (std::this_thread::get_id() != mHalThread.get_id()) { - LOG_FATAL("Function %s should only be called from InputClassifier thread", function); - } - } -} - /** * Obtain the classification from the HAL for a given MotionEvent. * Should only be called from the InputClassifier thread (mHalThread). @@ -213,23 +170,7 @@ void MotionClassifier::ensureHalThread(const char* function) { * To remove any possibility of negatively affecting the touch latency, the HAL * is called from a dedicated thread. */ -void MotionClassifier::callInputClassifierHal() { - ensureHalThread(__func__); - const bool initialized = init(); - if (!initialized) { - // MotionClassifier no longer useful. - // Deliver death notification from a separate thread - // because ~MotionClassifier may be invoked, which calls mHalThread.join() - std::thread([deathRecipient = mDeathRecipient](){ - sp<android::hardware::hidl_death_recipient> recipient = deathRecipient.promote(); - if (recipient != nullptr) { - recipient->serviceDied(0 /*cookie*/, nullptr); - } - }).detach(); - return; - } - // From this point on, mService is guaranteed to be non-null. - +void MotionClassifier::processEvents() { while (true) { ClassifierEvent event = mEvents.pop(); bool halResponseOk = true; @@ -383,24 +324,41 @@ void MotionClassifier::dump(std::string& dump) { } } +// --- HalDeathRecipient -// --- InputClassifier --- +InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {} -InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) : - mListener(listener) { - // The rest of the initialization is done in onFirstRef, because we need to obtain - // an sp to 'this' in order to register for HAL death notifications +void InputClassifier::HalDeathRecipient::serviceDied( + uint64_t cookie, const wp<android::hidl::base::V1_0::IBase>& who) { + sp<android::hidl::base::V1_0::IBase> service = who.promote(); + if (service) { + service->unlinkToDeath(this); + } + mParent.setMotionClassifier(nullptr); } -void InputClassifier::onFirstRef() { - if (!deepPressEnabled()) { - // If feature is not enabled, MotionClassifier should stay null to avoid unnecessary work. - // When MotionClassifier is null, InputClassifier will forward all events - // to the next InputListener, unmodified. - return; +// --- InputClassifier --- + +InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener) + : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {} + +void InputClassifier::setMotionClassifierEnabled(bool enabled) { + if (enabled) { + ALOGI("Enabling motion classifier"); + if (mInitializeMotionClassifierThread.joinable()) { + mInitializeMotionClassifierThread.join(); + } + 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 + } else { + ALOGI("Disabling motion classifier"); + setMotionClassifier(nullptr); } - std::scoped_lock lock(mLock); - mMotionClassifier = std::make_unique<MotionClassifier>(this); } void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { @@ -441,15 +399,10 @@ void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mListener->notifyDeviceReset(args); } -void InputClassifier::serviceDied(uint64_t /*cookie*/, - const wp<android::hidl::base::V1_0::IBase>& who) { +void InputClassifier::setMotionClassifier( + std::unique_ptr<MotionClassifierInterface> motionClassifier) { std::scoped_lock lock(mLock); - ALOGE("InputClassifier HAL has died. Setting mMotionClassifier to null"); - mMotionClassifier = nullptr; - sp<android::hidl::base::V1_0::IBase> service = who.promote(); - if (service) { - service->unlinkToDeath(this); - } + mMotionClassifier = std::move(motionClassifier); } void InputClassifier::dump(std::string& dump) { @@ -465,4 +418,10 @@ void InputClassifier::dump(std::string& dump) { dump += "\n"; } +InputClassifier::~InputClassifier() { + if (mInitializeMotionClassifierThread.joinable()) { + mInitializeMotionClassifierThread.join(); + } +} + } // namespace android diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index 47e20dbf7..9ac8e2db2 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -19,8 +19,8 @@ #include <android-base/thread_annotations.h> #include <utils/RefBase.h> -#include <unordered_map> #include <thread> +#include <unordered_map> #include "BlockingQueue.h" #include "InputListener.h" @@ -90,6 +90,7 @@ public: */ class InputClassifierInterface : public virtual RefBase, public InputListenerInterface { public: + virtual void setMotionClassifierEnabled(bool enabled) = 0; /** * Dump the state of the input classifier. * This method may be called on any thread (usually by the input manager). @@ -113,23 +114,23 @@ protected: */ class MotionClassifier final : public MotionClassifierInterface { public: - /** - * The deathRecipient will be subscribed to the HAL death. If the death recipient - * owns MotionClassifier and receives HAL death, it should delete its copy of it. - * The callback serviceDied will also be sent if the MotionClassifier itself fails - * to initialize. If the MotionClassifier fails to initialize, it is not useful, and - * should be deleted. - * If no death recipient is supplied, then the registration step will be skipped, so there will - * be no listeners registered for the HAL death. This is useful for testing - * MotionClassifier in isolation. + /* + * Create an instance of MotionClassifier. + * The death recipient, if provided, will be subscribed to the HAL death. + * The death recipient could be used to destroy MotionClassifier. + * + * This function should be called asynchronously, because getService takes a long time. */ - explicit MotionClassifier(sp<android::hardware::hidl_death_recipient> deathRecipient = nullptr); + static std::unique_ptr<MotionClassifierInterface> create( + sp<android::hardware::hidl_death_recipient> deathRecipient); + ~MotionClassifier(); /** * Classifies events asynchronously; that is, it doesn't block events on a classification, - * but instead sends them over to the classifier HAL and after a classification is - * determined, it then marks the next event it sees in the stream with it. + * but instead sends them over to the classifier HAL. After a classification of a specific + * event is determined, MotionClassifier then marks the next event in the stream with this + * classification. * * Therefore, it is acceptable to have the classifications be delayed by 1-2 events * in a particular gesture. @@ -141,15 +142,9 @@ public: virtual void dump(std::string& dump) override; private: - /** - * Initialize MotionClassifier. - * Return true if initializaion is successful. - */ - bool init(); - /** - * Entity that will be notified of the HAL death (most likely InputClassifier). - */ - wp<android::hardware::hidl_death_recipient> mDeathRecipient; + friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation + explicit MotionClassifier( + sp<android::hardware::input::classifier::V1_0::IInputClassifier> service); // The events that need to be sent to the HAL. BlockingQueue<ClassifierEvent> mEvents; @@ -164,14 +159,9 @@ private: */ std::thread mHalThread; /** - * Print an error message if the caller is not on the InputClassifier thread. - * Caller must supply the name of the calling function as __func__ + * Process events and call the InputClassifier HAL */ - void ensureHalThread(const char* function); - /** - * Call the InputClassifier HAL - */ - void callInputClassifierHal(); + void processEvents(); /** * Access to the InputClassifier HAL. May be null if init() hasn't completed yet. * When init() successfully completes, mService is guaranteed to remain non-null and to not @@ -223,19 +213,15 @@ private: const char* getServiceStatus() REQUIRES(mLock); }; - /** * Implementation of the InputClassifierInterface. * Represents a separate stage of input processing. All of the input events go through this stage. * Acts as a passthrough for all input events except for motion events. * The events of motion type are sent to MotionClassifier. */ -class InputClassifier : public InputClassifierInterface, - public android::hardware::hidl_death_recipient { +class InputClassifier : public InputClassifierInterface { public: explicit InputClassifier(const sp<InputListenerInterface>& listener); - // Some of the constructor logic is finished in onFirstRef - virtual void onFirstRef() override; virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; virtual void notifyKey(const NotifyKeyArgs* args) override; @@ -243,17 +229,47 @@ public: virtual void notifySwitch(const NotifySwitchArgs* args) override; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - virtual void serviceDied(uint64_t cookie, - const wp<android::hidl::base::V1_0::IBase>& who) override; - virtual void dump(std::string& dump) override; + ~InputClassifier(); + + // Called from InputManager + virtual void setMotionClassifierEnabled(bool enabled) override; + private: // Protect access to mMotionClassifier, since it may become null via a hidl callback std::mutex mLock; - std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); // The next stage to pass input events to sp<InputListenerInterface> mListener; + + std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); + std::thread mInitializeMotionClassifierThread; + /** + * Set the value of mMotionClassifier. + * This is called from 2 different threads: + * 1) mInitializeMotionClassifierThread, when we have constructed a MotionClassifier + * 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<MotionClassifierInterface> motionClassifier); + + /** + * 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<android::hidl::base::V1_0::IBase>& 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<HalDeathRecipient> mHalDeathRecipient; }; } // namespace android diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index acb53be69..52e908066 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -133,4 +133,8 @@ void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) { mDispatcher->unregisterInputChannel(channel); } +void InputManager::setMotionClassifierEnabled(bool enabled) { + mClassifier->setMotionClassifierEnabled(enabled); +} + } // namespace android diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 32f7ae005..c75611f08 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -100,6 +100,8 @@ public: virtual void registerInputChannel(const sp<InputChannel>& channel); virtual void unregisterInputChannel(const sp<InputChannel>& channel); + void setMotionClassifierEnabled(bool enabled); + private: sp<InputReaderInterface> mReader; sp<InputReaderThread> mReaderThread; diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp index 7cc17a221..4cddec50d 100644 --- a/services/inputflinger/tests/InputClassifier_test.cpp +++ b/services/inputflinger/tests/InputClassifier_test.cpp @@ -22,6 +22,9 @@ #include <android/hardware/input/classifier/1.0/IInputClassifier.h> using namespace android::hardware::input; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::input::common::V1_0::Classification; namespace android { @@ -129,6 +132,49 @@ TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) { ASSERT_EQ(args, outArgs); } +TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) { + mClassifier->setMotionClassifierEnabled(true); +} + +TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) { + mClassifier->setMotionClassifierEnabled(false); +} + +/** + * Try to break it by calling setMotionClassifierEnabled multiple times. + */ +TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) { + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(false); + mClassifier->setMotionClassifierEnabled(false); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); + mClassifier->setMotionClassifierEnabled(true); +} + +/** + * A minimal implementation of IInputClassifier. + */ +struct TestHal : public android::hardware::input::classifier::V1_0::IInputClassifier { + Return<Classification> classify( + const android::hardware::input::common::V1_0::MotionEvent& event) override { + return Classification::NONE; + }; + Return<void> reset() override { return Void(); }; + Return<void> 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<android::hidl::base::V1_0::IBase>& who) override{}; +}; + // --- MotionClassifierTest --- class MotionClassifierTest : public testing::Test { @@ -136,7 +182,14 @@ protected: std::unique_ptr<MotionClassifierInterface> mMotionClassifier; virtual void SetUp() override { - mMotionClassifier = std::make_unique<MotionClassifier>(); + 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<MotionClassifier>(new MotionClassifier(new TestHal())); + } } }; |