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

Commit 0ff40ae4 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 6320329 from 1a683ceb to qt-qpr3-release

Change-Id: If10a78c294d6b490245ba4283b1dfa9f7c266fb1
parents a1b55870 1a683ceb
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -47,7 +47,6 @@ cc_library_shared {
        "liblog",
        "libutils",
        "libui",
        "server_configurable_flags",
    ],

    cflags: [
+59 −100
Original line number Diff line number Diff line
@@ -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);
    const bool linked = service->linkToDeath(deathRecipient, 0 /* cookie */).withDefault(false);
    if (!linked) {
            ALOGE("Could not link MotionClassifier to the HAL death");
            return false;
        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
+54 −38
Original line number Diff line number Diff line
@@ -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__
     */
    void ensureHalThread(const char* function);
    /**
     * Call the InputClassifier HAL
     * Process events and 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
+4 −0
Original line number Diff line number Diff line
@@ -133,4 +133,8 @@ void InputManager::unregisterInputChannel(const sp<InputChannel>& channel) {
    mDispatcher->unregisterInputChannel(channel);
}

void InputManager::setMotionClassifierEnabled(bool enabled) {
    mClassifier->setMotionClassifierEnabled(enabled);
}

} // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -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;
Loading