diff options
Diffstat (limited to 'services/inputflinger/InputClassifier.cpp')
-rw-r--r-- | services/inputflinger/InputClassifier.cpp | 249 |
1 files changed, 157 insertions, 92 deletions
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index a9cbd5ad02..8ce2f35d7b 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -17,20 +17,20 @@ #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 #include <unordered_set> -#include <android/hardware/input/classifier/1.0/IInputClassifier.h> - #define INDENT1 " " #define INDENT2 " " #define INDENT3 " " @@ -38,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 { @@ -57,18 +56,69 @@ 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); } 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); +} + +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 --- @@ -119,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 @@ -136,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() { @@ -177,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; } @@ -301,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"; @@ -330,99 +365,128 @@ void MotionClassifier::dump(std::string& dump) { } } -// --- HalDeathRecipient +// --- InputClassifier --- -InputClassifier::HalDeathRecipient::HalDeathRecipient(InputClassifier& parent) : mParent(parent) {} +InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(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(const sp<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); } } 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::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); } @@ -438,10 +502,11 @@ void InputClassifier::dump(std::string& dump) { dump += "\n"; } +void InputClassifier::monitor() { + std::scoped_lock lock(mLock); +} + InputClassifier::~InputClassifier() { - if (mInitializeMotionClassifierThread.joinable()) { - mInitializeMotionClassifierThread.join(); - } } } // namespace android |