Loading services/inputflinger/Android.bp +3 −2 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ filegroup { name: "libinputflinger_sources", srcs: [ "InputClassifier.cpp", "InputClassifierConverter.cpp", "InputCommonConverter.cpp", "UnwantedInteractionBlocker.cpp", "InputManager.cpp", ], Loading @@ -67,9 +67,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", Loading services/inputflinger/InputClassifier.cpp +117 −67 Original line number Diff line number Diff line Loading @@ -17,13 +17,15 @@ #define LOG_TAG "InputClassifier" #include "InputClassifier.h" #include "InputClassifierConverter.h" #include "InputCommonConverter.h" #include <algorithm> #include <android-base/stringprintf.h> #include <cmath> #include <android/binder_manager.h> #include <android/binder_process.h> #include <inttypes.h> #include <log/log.h> #include <algorithm> #include <cmath> #if defined(__linux__) #include <pthread.h> #endif Loading @@ -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 { Loading @@ -55,13 +56,13 @@ static V getValueForKey(const std::unordered_map<K, V>& 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<MotionClassification>(common::V1_0::Classification::NONE)); static_cast<MotionClassification>(common::Classification::NONE)); static_assert(MotionClassification::AMBIGUOUS_GESTURE == static_cast<MotionClassification>(common::V1_0::Classification::AMBIGUOUS_GESTURE)); static_cast<MotionClassification>(common::Classification::AMBIGUOUS_GESTURE)); static_assert(MotionClassification::DEEP_PRESS == static_cast<MotionClassification>(common::V1_0::Classification::DEEP_PRESS)); static_cast<MotionClassification>(common::Classification::DEEP_PRESS)); return static_cast<MotionClassification>(classification); } Loading @@ -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<IInputProcessor> 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<NotifyMotionArgs> args) : Loading Loading @@ -118,9 +169,8 @@ std::optional<int32_t> ClassifierEvent::getDeviceId() const { // --- MotionClassifier --- MotionClassifier::MotionClassifier( sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) : mEvents(MAX_EVENTS), mService(service) { MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> 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 Loading @@ -135,23 +185,10 @@ MotionClassifier::MotionClassifier( } 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 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<IInputProcessor> service) { LOG_ALWAYS_FATAL_IF(service == nullptr); // Using 'new' to access a non-public constructor return std::unique_ptr<MotionClassifier>(new MotionClassifier(service)); return std::unique_ptr<MotionClassifier>(new MotionClassifier(std::move(service))); } MotionClassifier::~MotionClassifier() { Loading @@ -176,14 +213,12 @@ void MotionClassifier::processEvents() { switch (event.type) { case ClassifierEventType::MOTION: { NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get()); common::V1_0::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs); Return<common::V1_0::Classification> 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; } Loading Loading @@ -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"; Loading Loading @@ -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<android::hidl::base::V1_0::IBase>& who) { sp<android::hidl::base::V1_0::IBase> service = who.promote(); if (service) { service->unlinkToDeath(this); void InputClassifier::onBinderDied(void* cookie) { InputClassifier* classifier = static_cast<InputClassifier*>(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<IInputProcessor> 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<ScopedDeathRecipient>(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); } } Loading Loading @@ -419,9 +468,13 @@ void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChan mListener.notifyPointerCaptureChanged(args); } void InputClassifier::setMotionClassifier( std::unique_ptr<MotionClassifierInterface> motionClassifier) { std::scoped_lock lock(mLock); void InputClassifier::setMotionClassifierLocked( std::unique_ptr<MotionClassifierInterface> 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); } Loading @@ -438,9 +491,6 @@ void InputClassifier::dump(std::string& dump) { } InputClassifier::~InputClassifier() { if (mInitializeMotionClassifierThread.joinable()) { mInitializeMotionClassifierThread.join(); } } } // namespace android services/inputflinger/InputClassifier.h +35 −34 Original line number Diff line number Diff line Loading @@ -18,13 +18,13 @@ #define _UI_INPUT_CLASSIFIER_H #include <android-base/thread_annotations.h> #include <future> #include <thread> #include <unordered_map> #include <aidl/android/hardware/input/processor/IInputProcessor.h> #include "BlockingQueue.h" #include "InputListener.h" #include <android/hardware/input/classifier/1.0/IInputClassifier.h> namespace android { enum class ClassifierEventType : uint8_t { Loading Loading @@ -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. Loading @@ -121,7 +134,7 @@ public: * This function should be called asynchronously, because getService takes a long time. */ static std::unique_ptr<MotionClassifierInterface> create( sp<android::hardware::hidl_death_recipient> deathRecipient); std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service); ~MotionClassifier(); Loading @@ -143,7 +156,7 @@ public: private: friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation explicit MotionClassifier( sp<android::hardware::input::classifier::V1_0::IInputClassifier> service); std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service); // The events that need to be sent to the HAL. BlockingQueue<ClassifierEvent> mEvents; Loading @@ -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<android::hardware::input::classifier::V1_0::IInputClassifier> mService; std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> mService; std::mutex mLock; /** * Per-device input classifications. Should only be accessed using the Loading Loading @@ -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 Loading @@ -247,7 +260,8 @@ private: InputListenerInterface& mListener; std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); std::thread mInitializeMotionClassifierThread; std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock); /** * Set the value of mMotionClassifier. * This is called from 2 different threads: Loading @@ -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<MotionClassifierInterface> motionClassifier); void setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> 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<android::hidl::base::V1_0::IBase>& who) override; static void onBinderDied(void* cookie); 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; std::unique_ptr<ScopedDeathRecipient> mHalDeathRecipient GUARDED_BY(mLock); }; } // namespace android Loading Loading
services/inputflinger/Android.bp +3 −2 Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ filegroup { name: "libinputflinger_sources", srcs: [ "InputClassifier.cpp", "InputClassifierConverter.cpp", "InputCommonConverter.cpp", "UnwantedInteractionBlocker.cpp", "InputManager.cpp", ], Loading @@ -67,9 +67,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", Loading
services/inputflinger/InputClassifier.cpp +117 −67 Original line number Diff line number Diff line Loading @@ -17,13 +17,15 @@ #define LOG_TAG "InputClassifier" #include "InputClassifier.h" #include "InputClassifierConverter.h" #include "InputCommonConverter.h" #include <algorithm> #include <android-base/stringprintf.h> #include <cmath> #include <android/binder_manager.h> #include <android/binder_process.h> #include <inttypes.h> #include <log/log.h> #include <algorithm> #include <cmath> #if defined(__linux__) #include <pthread.h> #endif Loading @@ -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 { Loading @@ -55,13 +56,13 @@ static V getValueForKey(const std::unordered_map<K, V>& 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<MotionClassification>(common::V1_0::Classification::NONE)); static_cast<MotionClassification>(common::Classification::NONE)); static_assert(MotionClassification::AMBIGUOUS_GESTURE == static_cast<MotionClassification>(common::V1_0::Classification::AMBIGUOUS_GESTURE)); static_cast<MotionClassification>(common::Classification::AMBIGUOUS_GESTURE)); static_assert(MotionClassification::DEEP_PRESS == static_cast<MotionClassification>(common::V1_0::Classification::DEEP_PRESS)); static_cast<MotionClassification>(common::Classification::DEEP_PRESS)); return static_cast<MotionClassification>(classification); } Loading @@ -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<IInputProcessor> 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<NotifyMotionArgs> args) : Loading Loading @@ -118,9 +169,8 @@ std::optional<int32_t> ClassifierEvent::getDeviceId() const { // --- MotionClassifier --- MotionClassifier::MotionClassifier( sp<android::hardware::input::classifier::V1_0::IInputClassifier> service) : mEvents(MAX_EVENTS), mService(service) { MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> 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 Loading @@ -135,23 +185,10 @@ MotionClassifier::MotionClassifier( } 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 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<IInputProcessor> service) { LOG_ALWAYS_FATAL_IF(service == nullptr); // Using 'new' to access a non-public constructor return std::unique_ptr<MotionClassifier>(new MotionClassifier(service)); return std::unique_ptr<MotionClassifier>(new MotionClassifier(std::move(service))); } MotionClassifier::~MotionClassifier() { Loading @@ -176,14 +213,12 @@ void MotionClassifier::processEvents() { switch (event.type) { case ClassifierEventType::MOTION: { NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get()); common::V1_0::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs); Return<common::V1_0::Classification> 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; } Loading Loading @@ -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"; Loading Loading @@ -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<android::hidl::base::V1_0::IBase>& who) { sp<android::hidl::base::V1_0::IBase> service = who.promote(); if (service) { service->unlinkToDeath(this); void InputClassifier::onBinderDied(void* cookie) { InputClassifier* classifier = static_cast<InputClassifier*>(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<IInputProcessor> 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<ScopedDeathRecipient>(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); } } Loading Loading @@ -419,9 +468,13 @@ void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChan mListener.notifyPointerCaptureChanged(args); } void InputClassifier::setMotionClassifier( std::unique_ptr<MotionClassifierInterface> motionClassifier) { std::scoped_lock lock(mLock); void InputClassifier::setMotionClassifierLocked( std::unique_ptr<MotionClassifierInterface> 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); } Loading @@ -438,9 +491,6 @@ void InputClassifier::dump(std::string& dump) { } InputClassifier::~InputClassifier() { if (mInitializeMotionClassifierThread.joinable()) { mInitializeMotionClassifierThread.join(); } } } // namespace android
services/inputflinger/InputClassifier.h +35 −34 Original line number Diff line number Diff line Loading @@ -18,13 +18,13 @@ #define _UI_INPUT_CLASSIFIER_H #include <android-base/thread_annotations.h> #include <future> #include <thread> #include <unordered_map> #include <aidl/android/hardware/input/processor/IInputProcessor.h> #include "BlockingQueue.h" #include "InputListener.h" #include <android/hardware/input/classifier/1.0/IInputClassifier.h> namespace android { enum class ClassifierEventType : uint8_t { Loading Loading @@ -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. Loading @@ -121,7 +134,7 @@ public: * This function should be called asynchronously, because getService takes a long time. */ static std::unique_ptr<MotionClassifierInterface> create( sp<android::hardware::hidl_death_recipient> deathRecipient); std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service); ~MotionClassifier(); Loading @@ -143,7 +156,7 @@ public: private: friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation explicit MotionClassifier( sp<android::hardware::input::classifier::V1_0::IInputClassifier> service); std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service); // The events that need to be sent to the HAL. BlockingQueue<ClassifierEvent> mEvents; Loading @@ -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<android::hardware::input::classifier::V1_0::IInputClassifier> mService; std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> mService; std::mutex mLock; /** * Per-device input classifications. Should only be accessed using the Loading Loading @@ -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 Loading @@ -247,7 +260,8 @@ private: InputListenerInterface& mListener; std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock); std::thread mInitializeMotionClassifierThread; std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock); /** * Set the value of mMotionClassifier. * This is called from 2 different threads: Loading @@ -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<MotionClassifierInterface> motionClassifier); void setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> 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<android::hidl::base::V1_0::IBase>& who) override; static void onBinderDied(void* cookie); 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; std::unique_ptr<ScopedDeathRecipient> mHalDeathRecipient GUARDED_BY(mLock); }; } // namespace android Loading