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

Commit 199532b4 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge changes I2dfc9f2d,I36d6b5ae into main

* changes:
  Extract FakeInputReceiver and FakeInputWindow into a separate cpp file
  Extract FakeInputDispatcherPolicy into a separate cpp file
parents a394761f c5340735
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ package {
cc_benchmark {
    name: "inputflinger_benchmarks",
    srcs: [
        ":inputdispatcher_common_test_sources",
        "InputDispatcher_benchmarks.cpp",
    ],
    defaults: [
@@ -31,6 +32,8 @@ cc_benchmark {
    ],
    static_libs: [
        "libattestation",
        "libgmock",
        "libgtest",
        "libinputdispatcher",
    ],
}
+29 −29
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@
#include "../dispatcher/InputDispatcher.h"
#include "../tests/FakeApplicationHandle.h"
#include "../tests/FakeInputDispatcherPolicy.h"
#include "../tests/FakeWindowHandle.h"
#include "../tests/FakeWindows.h"

using android::base::Result;
using android::gui::WindowInfo;
@@ -104,16 +104,16 @@ static NotifyMotionArgs generateMotionArgs() {
static void benchmarkNotifyMotion(benchmark::State& state) {
    // Create dispatcher
    FakeInputDispatcherPolicy fakePolicy;
    InputDispatcher dispatcher(fakePolicy);
    dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
    dispatcher.start();
    auto dispatcher = std::make_unique<InputDispatcher>(fakePolicy);
    dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
    dispatcher->start();

    // Create a window that will receive motion events
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window =
            sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window", DISPLAY_ID);

    dispatcher.onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
    dispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});

    NotifyMotionArgs motionArgs = generateMotionArgs();

@@ -122,60 +122,60 @@ static void benchmarkNotifyMotion(benchmark::State& state) {
        motionArgs.action = AMOTION_EVENT_ACTION_DOWN;
        motionArgs.downTime = now();
        motionArgs.eventTime = motionArgs.downTime;
        dispatcher.notifyMotion(motionArgs);
        dispatcher->notifyMotion(motionArgs);

        // Send ACTION_UP
        motionArgs.action = AMOTION_EVENT_ACTION_UP;
        motionArgs.eventTime = now();
        dispatcher.notifyMotion(motionArgs);
        dispatcher->notifyMotion(motionArgs);

        window->consumeMotion();
        window->consumeMotion();
        window->consumeMotionEvent();
        window->consumeMotionEvent();
    }

    dispatcher.stop();
    dispatcher->stop();
}

static void benchmarkInjectMotion(benchmark::State& state) {
    // Create dispatcher
    FakeInputDispatcherPolicy fakePolicy;
    InputDispatcher dispatcher(fakePolicy);
    dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
    dispatcher.start();
    auto dispatcher = std::make_unique<InputDispatcher>(fakePolicy);
    dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
    dispatcher->start();

    // Create a window that will receive motion events
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window =
            sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window", DISPLAY_ID);

    dispatcher.onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});
    dispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0});

    for (auto _ : state) {
        MotionEvent event = generateMotionEvent();
        // Send ACTION_DOWN
        dispatcher.injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
        dispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                     INJECT_EVENT_TIMEOUT,
                                     POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);

        // Send ACTION_UP
        event.setAction(AMOTION_EVENT_ACTION_UP);
        dispatcher.injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
        dispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE,
                                     INJECT_EVENT_TIMEOUT,
                                     POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);

        window->consumeMotion();
        window->consumeMotion();
        window->consumeMotionEvent();
        window->consumeMotionEvent();
    }

    dispatcher.stop();
    dispatcher->stop();
}

static void benchmarkOnWindowInfosChanged(benchmark::State& state) {
    // Create dispatcher
    FakeInputDispatcherPolicy fakePolicy;
    InputDispatcher dispatcher(fakePolicy);
    dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
    dispatcher.start();
    auto dispatcher = std::make_unique<InputDispatcher>(fakePolicy);
    dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
    dispatcher->start();

    // Create a window
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
@@ -188,12 +188,12 @@ static void benchmarkOnWindowInfosChanged(benchmark::State& state) {
    std::vector<gui::DisplayInfo> displayInfos{info};

    for (auto _ : state) {
        dispatcher.onWindowInfosChanged(
        dispatcher->onWindowInfosChanged(
                {windowInfos, displayInfos, /*vsyncId=*/0, /*timestamp=*/0});
        dispatcher.onWindowInfosChanged(
        dispatcher->onWindowInfosChanged(
                {/*windowInfos=*/{}, /*displayInfos=*/{}, /*vsyncId=*/{}, /*timestamp=*/0});
    }
    dispatcher.stop();
    dispatcher->stop();
}

} // namespace
+10 −0
Original line number Diff line number Diff line
@@ -22,6 +22,15 @@ package {
    default_applicable_licenses: ["frameworks_native_license"],
}

// Source files shared with InputDispatcher's benchmarks and fuzzers
filegroup {
    name: "inputdispatcher_common_test_sources",
    srcs: [
        "FakeInputDispatcherPolicy.cpp",
        "FakeWindows.cpp",
    ],
}

cc_test {
    name: "inputflinger_tests",
    host_supported: true,
@@ -38,6 +47,7 @@ cc_test {
        "libinputflinger_defaults",
    ],
    srcs: [
        ":inputdispatcher_common_test_sources",
        "AnrTracker_test.cpp",
        "CapturedTouchpadEventConverter_test.cpp",
        "CursorInputMapper_test.cpp",
+473 −0

File added.

Preview size limit exceeded, changes collapsed.

+170 −58
Original line number Diff line number Diff line
@@ -16,78 +16,190 @@

#pragma once

#include <android-base/logging.h>
#include "InputDispatcherPolicyInterface.h"

namespace android {
#include "InputDispatcherInterface.h"
#include "NotifyArgs.h"

// --- FakeInputDispatcherPolicy ---
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <queue>
#include <string>
#include <vector>

#include <android-base/logging.h>
#include <android-base/thread_annotations.h>
#include <binder/IBinder.h>
#include <gui/PidUid.h>
#include <gui/WindowInfo.h>
#include <input/BlockingQueue.h>
#include <input/Input.h>

namespace android {

class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
public:
    FakeInputDispatcherPolicy() = default;
    virtual ~FakeInputDispatcherPolicy() = default;

private:
    void notifyConfigurationChanged(nsecs_t) override {}

    void notifyNoFocusedWindowAnr(
            const std::shared_ptr<InputApplicationHandle>& applicationHandle) override {
        LOG(ERROR) << "There is no focused window for " << applicationHandle->getName();
    }

    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<gui::Pid> pid,
                                  const std::string& reason) override {
        LOG(ERROR) << "Window is not responding: " << reason;
    }

    void notifyWindowResponsive(const sp<IBinder>& connectionToken,
                                std::optional<gui::Pid> pid) override {}

    void notifyInputChannelBroken(const sp<IBinder>&) override {}

    void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}

    void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
                           InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
                           const std::vector<float>& values) override {}

    void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
                              InputDeviceSensorAccuracy accuracy) override {}
    struct AnrResult {
        sp<IBinder> token{};
        std::optional<gui::Pid> pid{};
    };

    void notifyVibratorState(int32_t deviceId, bool isOn) override {}
    struct UserActivityPokeEvent {
        nsecs_t eventTime;
        int32_t eventType;
        int32_t displayId;

    bool filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) override {
        return true; // dispatch event normally
        bool operator==(const UserActivityPokeEvent& rhs) const = default;
        inline friend std::ostream& operator<<(std::ostream& os, const UserActivityPokeEvent& ev) {
            os << "UserActivityPokeEvent[time=" << ev.eventTime << ", eventType=" << ev.eventType
               << ", displayId=" << ev.displayId << "]";
            return os;
        }
    };

    void interceptKeyBeforeQueueing(const KeyEvent&, uint32_t&) override {}
    void assertFilterInputEventWasCalled(const NotifyKeyArgs& args);
    void assertFilterInputEventWasCalled(const NotifyMotionArgs& args, vec2 point);
    void assertFilterInputEventWasNotCalled();
    void assertNotifyConfigurationChangedWasCalled(nsecs_t when);
    void assertNotifySwitchWasCalled(const NotifySwitchArgs& args);
    void assertOnPointerDownEquals(const sp<IBinder>& touchedToken);
    void assertOnPointerDownWasNotCalled();
    /**
     * This function must be called soon after the expected ANR timer starts,
     * because we are also checking how much time has passed.
     */
    void assertNotifyNoFocusedWindowAnrWasCalled(
            std::chrono::nanoseconds timeout,
            const std::shared_ptr<InputApplicationHandle>& expectedApplication);
    void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
                                                 const sp<gui::WindowInfoHandle>& window);
    void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout,
                                                 const sp<IBinder>& expectedToken,
                                                 std::optional<gui::Pid> expectedPid);
    /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
    sp<IBinder> getUnresponsiveWindowToken(std::chrono::nanoseconds timeout);
    void assertNotifyWindowResponsiveWasCalled(const sp<IBinder>& expectedToken,
                                               std::optional<gui::Pid> expectedPid);
    /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */
    sp<IBinder> getResponsiveWindowToken();
    void assertNotifyAnrWasNotCalled();
    PointerCaptureRequest assertSetPointerCaptureCalled(const sp<gui::WindowInfoHandle>& window,
                                                        bool enabled);
    void assertSetPointerCaptureNotCalled();
    void assertDropTargetEquals(const InputDispatcherInterface& dispatcher,
                                const sp<IBinder>& targetToken);
    void assertNotifyInputChannelBrokenWasCalled(const sp<IBinder>& token);
    /**
     * Set policy timeout. A value of zero means next key will not be intercepted.
     */
    void setInterceptKeyTimeout(std::chrono::milliseconds timeout);
    std::chrono::nanoseconds getKeyWaitingForEventsTimeout() override;
    void setStaleEventTimeout(std::chrono::nanoseconds timeout);
    void assertUserActivityNotPoked();
    /**
     * Asserts that a user activity poke has happened. The earliest recorded poke event will be
     * cleared after this call.
     *
     * If an expected UserActivityPokeEvent is provided, asserts that the given event is the
     * earliest recorded poke event.
     */
    void assertUserActivityPoked(std::optional<UserActivityPokeEvent> expectedPokeEvent = {});
    void assertNotifyDeviceInteractionWasCalled(int32_t deviceId, std::set<gui::Uid> uids);
    void assertNotifyDeviceInteractionWasNotCalled();
    void setUnhandledKeyHandler(std::function<std::optional<KeyEvent>(const KeyEvent&)> handler);
    void assertUnhandledKeyReported(int32_t keycode);
    void assertUnhandledKeyNotReported();

    void interceptMotionBeforeQueueing(int32_t, uint32_t, int32_t, nsecs_t, uint32_t&) override {}
private:
    std::mutex mLock;
    std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
    std::optional<nsecs_t> mConfigurationChangedTime GUARDED_BY(mLock);
    sp<IBinder> mOnPointerDownToken GUARDED_BY(mLock);
    std::optional<NotifySwitchArgs> mLastNotifySwitch GUARDED_BY(mLock);

    nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent&, uint32_t) override {
        return 0;
    }
    std::condition_variable mPointerCaptureChangedCondition;

    std::optional<KeyEvent> dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent&,
                                                 uint32_t) override {
        return {};
    }
    std::optional<PointerCaptureRequest> mPointerCaptureRequest GUARDED_BY(mLock);
    // ANR handling
    std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock);
    std::queue<AnrResult> mAnrWindows GUARDED_BY(mLock);
    std::queue<AnrResult> mResponsiveWindows GUARDED_BY(mLock);
    std::condition_variable mNotifyAnr;
    std::queue<sp<IBinder>> mBrokenInputChannels GUARDED_BY(mLock);
    std::condition_variable mNotifyInputChannelBroken;

    void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) override {}
    sp<IBinder> mDropTargetWindowToken GUARDED_BY(mLock);
    bool mNotifyDropWindowWasCalled GUARDED_BY(mLock) = false;

    void pokeUserActivity(nsecs_t, int32_t, int32_t) override {}
    std::condition_variable mNotifyUserActivity;
    std::queue<UserActivityPokeEvent> mUserActivityPokeEvents;

    void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
    std::chrono::milliseconds mInterceptKeyTimeout = 0ms;

    void setPointerCapture(const PointerCaptureRequest&) override {}
    std::chrono::nanoseconds mStaleEventTimeout = 1000ms;

    void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
    BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions;

    void notifyDeviceInteraction(DeviceId deviceId, nsecs_t timestamp,
                                 const std::set<gui::Uid>& uids) override {}
    std::condition_variable mNotifyUnhandledKey;
    std::queue<int32_t> mReportedUnhandledKeycodes GUARDED_BY(mLock);
    std::function<std::optional<KeyEvent>(const KeyEvent&)> mUnhandledKeyHandler GUARDED_BY(mLock);

    gui::Uid getPackageUid(std::string) override { return gui::Uid::INVALID; }
    /**
     * All three ANR-related callbacks behave the same way, so we use this generic function to wait
     * for a specific container to become non-empty. When the container is non-empty, return the
     * first entry from the container and erase it.
     */
    template <class T>
    T getAnrTokenLockedInterruptible(std::chrono::nanoseconds timeout, std::queue<T>& storage,
                                     std::unique_lock<std::mutex>& lock) REQUIRES(mLock);

    template <class T>
    std::optional<T> getItemFromStorageLockedInterruptible(std::chrono::nanoseconds timeout,
                                                           std::queue<T>& storage,
                                                           std::unique_lock<std::mutex>& lock,
                                                           std::condition_variable& condition)
            REQUIRES(mLock);

    void notifyConfigurationChanged(nsecs_t when) override;
    void notifyWindowUnresponsive(const sp<IBinder>& connectionToken, std::optional<gui::Pid> pid,
                                  const std::string&) override;
    void notifyWindowResponsive(const sp<IBinder>& connectionToken,
                                std::optional<gui::Pid> pid) override;
    void notifyNoFocusedWindowAnr(
            const std::shared_ptr<InputApplicationHandle>& applicationHandle) override;
    void notifyInputChannelBroken(const sp<IBinder>& connectionToken) override;
    void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override;
    void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
                           InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
                           const std::vector<float>& values) override;
    void notifySensorAccuracy(int deviceId, InputDeviceSensorType sensorType,
                              InputDeviceSensorAccuracy accuracy) override;
    void notifyVibratorState(int32_t deviceId, bool isOn) override;
    bool filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) override;
    void interceptKeyBeforeQueueing(const KeyEvent& inputEvent, uint32_t&) override;
    void interceptMotionBeforeQueueing(int32_t, uint32_t, int32_t, nsecs_t, uint32_t&) override;
    nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent&, uint32_t) override;
    std::optional<KeyEvent> dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent& event,
                                                 uint32_t) override;
    void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
                      uint32_t policyFlags) override;
    void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) override;
    bool isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) override;
    void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override;
    void setPointerCapture(const PointerCaptureRequest& request) override;
    void notifyDropWindow(const sp<IBinder>& token, float x, float y) override;
    void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
                                 const std::set<gui::Uid>& uids) override;
    gui::Uid getPackageUid(std::string) override;

    void assertFilterInputEventWasCalledInternal(
            const std::function<void(const InputEvent&)>& verify);
};

} // namespace android
Loading