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 Original line Diff line number Diff line
@@ -57,7 +57,7 @@ filegroup {
    name: "libinputflinger_sources",
    name: "libinputflinger_sources",
    srcs: [
    srcs: [
        "InputClassifier.cpp",
        "InputClassifier.cpp",
        "InputClassifierConverter.cpp",
        "InputCommonConverter.cpp",
        "UnwantedInteractionBlocker.cpp",
        "UnwantedInteractionBlocker.cpp",
        "InputManager.cpp",
        "InputManager.cpp",
    ],
    ],
@@ -67,9 +67,10 @@ cc_defaults {
    name: "libinputflinger_defaults",
    name: "libinputflinger_defaults",
    srcs: [":libinputflinger_sources"],
    srcs: [":libinputflinger_sources"],
    shared_libs: [
    shared_libs: [
        "android.hardware.input.classifier@1.0",
        "android.hardware.input.processor-V1-ndk",
        "libbase",
        "libbase",
        "libbinder",
        "libbinder",
        "libbinder_ndk",
        "libchrome",
        "libchrome",
        "libcrypto",
        "libcrypto",
        "libcutils",
        "libcutils",
+117 −67
Original line number Original line Diff line number Diff line
@@ -17,13 +17,15 @@
#define LOG_TAG "InputClassifier"
#define LOG_TAG "InputClassifier"


#include "InputClassifier.h"
#include "InputClassifier.h"
#include "InputClassifierConverter.h"
#include "InputCommonConverter.h"


#include <algorithm>
#include <android-base/stringprintf.h>
#include <android-base/stringprintf.h>
#include <cmath>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <inttypes.h>
#include <inttypes.h>
#include <log/log.h>
#include <log/log.h>
#include <algorithm>
#include <cmath>
#if defined(__linux__)
#if defined(__linux__)
    #include <pthread.h>
    #include <pthread.h>
#endif
#endif
@@ -36,10 +38,9 @@
#define INDENT5 "          "
#define INDENT5 "          "


using android::base::StringPrintf;
using android::base::StringPrintf;
using android::hardware::hidl_bitfield;
using namespace std::chrono_literals;
using android::hardware::hidl_vec;
using namespace ::aidl::android::hardware::input;
using android::hardware::Return;
using aidl::android::hardware::input::processor::IInputProcessor;
using namespace android::hardware::input;


namespace android {
namespace android {


@@ -55,13 +56,13 @@ static V getValueForKey(const std::unordered_map<K, V>& map, K key, V defaultVal
    return it->second;
    return it->second;
}
}


static MotionClassification getMotionClassification(common::V1_0::Classification classification) {
static MotionClassification getMotionClassification(common::Classification classification) {
    static_assert(MotionClassification::NONE ==
    static_assert(MotionClassification::NONE ==
            static_cast<MotionClassification>(common::V1_0::Classification::NONE));
                  static_cast<MotionClassification>(common::Classification::NONE));
    static_assert(MotionClassification::AMBIGUOUS_GESTURE ==
    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_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);
    return static_cast<MotionClassification>(classification);
}
}


@@ -70,6 +71,56 @@ static bool isTouchEvent(const NotifyMotionArgs& args) {
            isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN);
            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::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
@@ -118,9 +169,8 @@ std::optional<int32_t> ClassifierEvent::getDeviceId() const {


// --- MotionClassifier ---
// --- MotionClassifier ---


MotionClassifier::MotionClassifier(
MotionClassifier::MotionClassifier(std::shared_ptr<IInputProcessor> service)
        sp<android::hardware::input::classifier::V1_0::IInputClassifier> service)
      : mEvents(MAX_EVENTS), mService(std::move(service)) {
      : mEvents(MAX_EVENTS), mService(service) {
    // Under normal operation, we do not need to reset the HAL here. But in the case where system
    // 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
    // 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
    // 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(
std::unique_ptr<MotionClassifierInterface> MotionClassifier::create(
        sp<android::hardware::hidl_death_recipient> deathRecipient) {
        std::shared_ptr<IInputProcessor> service) {
    sp<android::hardware::input::classifier::V1_0::IInputClassifier> service =
    LOG_ALWAYS_FATAL_IF(service == nullptr);
            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;
    }
    // Using 'new' to access a non-public constructor
    // 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() {
MotionClassifier::~MotionClassifier() {
@@ -176,14 +213,12 @@ void MotionClassifier::processEvents() {
        switch (event.type) {
        switch (event.type) {
            case ClassifierEventType::MOTION: {
            case ClassifierEventType::MOTION: {
                NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get());
                NotifyMotionArgs* motionArgs = static_cast<NotifyMotionArgs*>(event.args.get());
                common::V1_0::MotionEvent motionEvent =
                common::MotionEvent motionEvent = notifyMotionArgsToHalMotionEvent(*motionArgs);
                        notifyMotionArgsToHalMotionEvent(*motionArgs);
                common::Classification classification;
                Return<common::V1_0::Classification> response = mService->classify(motionEvent);
                ndk::ScopedAStatus response = mService->classify(motionEvent, &classification);
                halResponseOk = response.isOk();
                if (response.isOk()) {
                if (halResponseOk) {
                    common::V1_0::Classification halClassification = response;
                    updateClassification(motionArgs->deviceId, motionArgs->eventTime,
                    updateClassification(motionArgs->deviceId, motionArgs->eventTime,
                            getMotionClassification(halClassification));
                                         getMotionClassification(classification));
                }
                }
                break;
                break;
            }
            }
@@ -300,7 +335,8 @@ const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) {
    if (!mService) {
    if (!mService) {
        return "null";
        return "null";
    }
    }
    if (mService->ping().isOk()) {

    if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) {
        return "running";
        return "running";
    }
    }
    return "not responding";
    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(
void InputClassifier::onBinderDied(void* cookie) {
        uint64_t cookie, const wp<android::hidl::base::V1_0::IBase>& who) {
    InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
    sp<android::hidl::base::V1_0::IBase> service = who.promote();
    if (classifier == nullptr) {
    if (service) {
        LOG_ALWAYS_FATAL("Cookie is not valid");
        service->unlinkToDeath(this);
        return;
    }
    }
    mParent.setMotionClassifier(nullptr);
    classifier->setMotionClassifierEnabled(false);
}
}


// --- InputClassifier ---

InputClassifier::InputClassifier(InputListenerInterface& listener)
      : mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}

void InputClassifier::setMotionClassifierEnabled(bool enabled) {
void InputClassifier::setMotionClassifierEnabled(bool enabled) {
    std::scoped_lock lock(mLock);
    if (enabled) {
    if (enabled) {
        ALOGI("Enabling motion classifier");
        ALOGI("Enabling motion classifier");
        if (mInitializeMotionClassifierThread.joinable()) {
        if (mInitializeMotionClassifier.valid()) {
            mInitializeMotionClassifierThread.join();
            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)); });
        mInitializeMotionClassifier = std::async(std::launch::async, [this] {
#if defined(__linux__)
            setCurrentThreadName("Create MotionClassifier");
        // Set the thread name for debugging
            std::shared_ptr<IInputProcessor> service = getService();
        pthread_setname_np(mInitializeMotionClassifierThread.native_handle(),
            if (service == nullptr) {
                           "Create MotionClassifier");
                // Keep the MotionClassifier null, no service was found
#endif
                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 {
    } else {
        ALOGI("Disabling motion classifier");
        ALOGI("Disabling motion classifier");
        setMotionClassifier(nullptr);
        setMotionClassifierLocked(nullptr);
    }
    }
}
}


@@ -419,9 +468,13 @@ void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChan
    mListener.notifyPointerCaptureChanged(args);
    mListener.notifyPointerCaptureChanged(args);
}
}


void InputClassifier::setMotionClassifier(
void InputClassifier::setMotionClassifierLocked(
        std::unique_ptr<MotionClassifierInterface> motionClassifier) {
        std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
    std::scoped_lock lock(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);
    mMotionClassifier = std::move(motionClassifier);
}
}


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


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


} // namespace android
} // namespace android
+35 −34
Original line number Original line Diff line number Diff line
@@ -18,13 +18,13 @@
#define _UI_INPUT_CLASSIFIER_H
#define _UI_INPUT_CLASSIFIER_H


#include <android-base/thread_annotations.h>
#include <android-base/thread_annotations.h>
#include <future>
#include <thread>
#include <thread>
#include <unordered_map>
#include <unordered_map>


#include <aidl/android/hardware/input/processor/IInputProcessor.h>
#include "BlockingQueue.h"
#include "BlockingQueue.h"
#include "InputListener.h"
#include "InputListener.h"
#include <android/hardware/input/classifier/1.0/IInputClassifier.h>

namespace android {
namespace android {


enum class ClassifierEventType : uint8_t {
enum class ClassifierEventType : uint8_t {
@@ -102,6 +102,19 @@ public:


// --- Implementations ---
// --- 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
 * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
 * in order to determine the classification for the current gesture.
 * 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.
     * This function should be called asynchronously, because getService takes a long time.
     */
     */
    static std::unique_ptr<MotionClassifierInterface> create(
    static std::unique_ptr<MotionClassifierInterface> create(
            sp<android::hardware::hidl_death_recipient> deathRecipient);
            std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service);


    ~MotionClassifier();
    ~MotionClassifier();


@@ -143,7 +156,7 @@ public:
private:
private:
    friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
    friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation
    explicit MotionClassifier(
    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.
    // The events that need to be sent to the HAL.
    BlockingQueue<ClassifierEvent> mEvents;
    BlockingQueue<ClassifierEvent> mEvents;
@@ -162,14 +175,14 @@ private:
     */
     */
    void processEvents();
    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
     * When init() successfully completes, mService is guaranteed to remain non-null and to not
     * change its value until MotionClassifier is destroyed.
     * change its value until MotionClassifier is destroyed.
     * This variable is *not* guarded by mLock in the InputClassifier thread, because
     * This variable is *not* guarded by mLock in the InputClassifier thread, because
     * that thread knows exactly when this variable is initialized.
     * that thread knows exactly when this variable is initialized.
     * When accessed in any other thread, mService is checked for nullness with a lock.
     * 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;
    std::mutex mLock;
    /**
    /**
     * Per-device input classifications. Should only be accessed using the
     * Per-device input classifications. Should only be accessed using the
@@ -224,21 +237,21 @@ class InputClassifier : public InputClassifierInterface {
public:
public:
    explicit InputClassifier(InputListenerInterface& listener);
    explicit InputClassifier(InputListenerInterface& listener);


    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
    void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
    virtual void notifyKey(const NotifyKeyArgs* args) override;
    void notifyKey(const NotifyKeyArgs* args) override;
    virtual void notifyMotion(const NotifyMotionArgs* args) override;
    void notifyMotion(const NotifyMotionArgs* args) override;
    virtual void notifySwitch(const NotifySwitchArgs* args) override;
    void notifySwitch(const NotifySwitchArgs* args) override;
    virtual void notifySensor(const NotifySensorArgs* args) override;
    void notifySensor(const NotifySensorArgs* args) override;
    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
    void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
    void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;


    virtual void dump(std::string& dump) override;
    void dump(std::string& dump) override;


    ~InputClassifier();
    ~InputClassifier();


    // Called from InputManager
    // Called from InputManager
    virtual void setMotionClassifierEnabled(bool enabled) override;
    void setMotionClassifierEnabled(bool enabled) override;


private:
private:
    // Protect access to mMotionClassifier, since it may become null via a hidl callback
    // Protect access to mMotionClassifier, since it may become null via a hidl callback
@@ -247,7 +260,8 @@ private:
    InputListenerInterface& mListener;
    InputListenerInterface& mListener;


    std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
    std::unique_ptr<MotionClassifierInterface> mMotionClassifier GUARDED_BY(mLock);
    std::thread mInitializeMotionClassifierThread;
    std::future<void> mInitializeMotionClassifier GUARDED_BY(mLock);

    /**
    /**
     * Set the value of mMotionClassifier.
     * Set the value of mMotionClassifier.
     * This is called from 2 different threads:
     * 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
     * 2) A binder thread of the HalDeathRecipient, which is created when HAL dies. This would cause
     *    mMotionClassifier to become nullptr.
     *    mMotionClassifier to become nullptr.
     */
     */
    void setMotionClassifier(std::unique_ptr<MotionClassifierInterface> motionClassifier);
    void setMotionClassifierLocked(std::unique_ptr<MotionClassifierInterface> motionClassifier)
            REQUIRES(mLock);


    /**
    static void onBinderDied(void* cookie);
     * 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:
    std::unique_ptr<ScopedDeathRecipient> mHalDeathRecipient GUARDED_BY(mLock);
        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
} // namespace android
+0 −379

File deleted.

Preview size limit exceeded, changes collapsed.

+339 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading