Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df4b0674 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou Committed by Android (Google) Code Review
Browse files

Merge "Use InputProcessor instead of InputClassifier"

parents 9df93aa6 34d6fef6
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ filegroup {
    name: "libinputflinger_sources",
    srcs: [
        "InputClassifier.cpp",
        "InputClassifierConverter.cpp",
        "InputCommonConverter.cpp",
        "UnwantedInteractionBlocker.cpp",
        "InputManager.cpp",
    ],
@@ -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",
+117 −67
Original line number Diff line number Diff line
@@ -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
@@ -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<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);
}

@@ -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) :
@@ -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
@@ -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() {
@@ -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;
            }
@@ -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<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);
    }
}

@@ -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);
}

@@ -438,9 +491,6 @@ void InputClassifier::dump(std::string& dump) {
}

InputClassifier::~InputClassifier() {
    if (mInitializeMotionClassifierThread.joinable()) {
        mInitializeMotionClassifierThread.join();
    }
}

} // namespace android
+35 −34
Original line number Diff line number Diff line
@@ -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 {
@@ -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<MotionClassifierInterface> create(
            sp<android::hardware::hidl_death_recipient> deathRecipient);
            std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);

    ~MotionClassifier();

@@ -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;
@@ -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
@@ -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<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:
@@ -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
+0 −379

File deleted.

Preview size limit exceeded, changes collapsed.

+339 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading