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

Commit d078476b authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Add benchmarks for InputDispatcher

No logs are generated when these benchmarks are ran.

Bug: none
Test: atest inputflinger_benchmarks
Change-Id: Ifce2518657b2f266f8e8ccfaabac1331ecdf7935
parent 37c665dc
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
cc_benchmark {
    name: "inputflinger_benchmarks",
    srcs: [
        "InputDispatcher_benchmarks.cpp",
    ],
    defaults: ["inputflinger_defaults"],
    shared_libs: [
        "libbase",
        "libbinder",
        "libcutils",
        "libinput",
        "libinputflinger_base",
        "libinputreporter",
        "liblog",
        "libstatslog",
        "libui",
        "libutils",
    ],
    static_libs: [
        "libinputdispatcher",
    ],
}
+314 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <benchmark/benchmark.h>

#include <binder/Binder.h>
#include "../dispatcher/InputDispatcher.h"

namespace android::inputdispatcher {

// An arbitrary device id.
static const int32_t DEVICE_ID = 1;

// An arbitrary injector pid / uid pair that has permission to inject events.
static const int32_t INJECTOR_PID = 999;
static const int32_t INJECTOR_UID = 1001;

static const int32_t INJECT_EVENT_TIMEOUT = 5000;
static const int32_t DISPATCHING_TIMEOUT = 100000;

static nsecs_t now() {
    return systemTime(SYSTEM_TIME_MONOTONIC);
}

// --- FakeInputDispatcherPolicy ---

class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
public:
    FakeInputDispatcherPolicy() {}

protected:
    virtual ~FakeInputDispatcherPolicy() {}

private:
    virtual void notifyConfigurationChanged(nsecs_t) override {}

    virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&, const sp<IBinder>&,
                              const std::string& name) override {
        ALOGE("The window is not responding : %s", name.c_str());
        return 0;
    }

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

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

    virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
        *outConfig = mConfig;
    }

    virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override {
        return true;
    }

    virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {}

    virtual void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {}

    virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*,
                                                  uint32_t) override {
        return 0;
    }

    virtual bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t,
                                      KeyEvent*) override {
        return false;
    }

    virtual void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) override {}

    virtual void pokeUserActivity(nsecs_t, int32_t) override {}

    virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override {
        return false;
    }

    virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}

    InputDispatcherConfiguration mConfig;
};

class FakeApplicationHandle : public InputApplicationHandle {
public:
    FakeApplicationHandle() {}
    virtual ~FakeApplicationHandle() {}

    virtual bool updateInfo() {
        mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
        return true;
    }
};

class FakeInputReceiver {
public:
    void consumeEvent() {
        uint32_t consumeSeq;
        InputEvent* event;

        status_t result = WOULD_BLOCK;
        while (result == WOULD_BLOCK) {
            result = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq,
                                        &event);
        }
        if (result != OK) {
            ALOGE("Received result = %d from consume()", result);
        }
        result = mConsumer->sendFinishedSignal(consumeSeq, true);
        if (result != OK) {
            ALOGE("Received result = %d from sendFinishedSignal", result);
        }
    }

protected:
    explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher, const std::string name)
          : mDispatcher(dispatcher) {
        InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
        mConsumer = std::make_unique<InputConsumer>(mClientChannel);
    }

    virtual ~FakeInputReceiver() {}

    sp<InputDispatcher> mDispatcher;
    sp<InputChannel> mServerChannel, mClientChannel;
    std::unique_ptr<InputConsumer> mConsumer;
    PreallocatedInputEventFactory mEventFactory;
};

class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver {
public:
    static const int32_t WIDTH = 200;
    static const int32_t HEIGHT = 200;

    FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
                     const sp<InputDispatcher>& dispatcher, const std::string name)
          : FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) {
        mDispatcher->registerInputChannel(mServerChannel);

        inputApplicationHandle->updateInfo();
        mInfo.applicationInfo = *inputApplicationHandle->getInfo();
    }

    virtual bool updateInfo() override {
        mInfo.token = mServerChannel->getConnectionToken();
        mInfo.name = "FakeWindowHandle";
        mInfo.layoutParamsFlags = 0;
        mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
        mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
        mInfo.frameLeft = mFrame.left;
        mInfo.frameTop = mFrame.top;
        mInfo.frameRight = mFrame.right;
        mInfo.frameBottom = mFrame.bottom;
        mInfo.globalScaleFactor = 1.0;
        mInfo.touchableRegion.clear();
        mInfo.addTouchableRegion(mFrame);
        mInfo.visible = true;
        mInfo.canReceiveKeys = true;
        mInfo.hasFocus = true;
        mInfo.hasWallpaper = false;
        mInfo.paused = false;
        mInfo.layer = 0;
        mInfo.ownerPid = INJECTOR_PID;
        mInfo.ownerUid = INJECTOR_UID;
        mInfo.inputFeatures = 0;
        mInfo.displayId = ADISPLAY_ID_DEFAULT;

        return true;
    }

protected:
    Rect mFrame;
};

static MotionEvent generateMotionEvent() {
    PointerProperties pointerProperties[1];
    PointerCoords pointerCoords[1];

    pointerProperties[0].clear();
    pointerProperties[0].id = 0;
    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;

    pointerCoords[0].clear();
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 100);

    const nsecs_t currentTime = now();

    MotionEvent event;
    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                     AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0,
                     /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
                     /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
                     /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                     AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, currentTime,
                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
    return event;
}

static NotifyMotionArgs generateMotionArgs() {
    PointerProperties pointerProperties[1];
    PointerCoords pointerCoords[1];

    pointerProperties[0].clear();
    pointerProperties[0].id = 0;
    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;

    pointerCoords[0].clear();
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 100);

    const nsecs_t currentTime = now();
    // Define a valid motion event.
    NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
                          ADISPLAY_ID_DEFAULT, POLICY_FLAG_PASS_TO_USER, AMOTION_EVENT_ACTION_DOWN,
                          /* actionButton */ 0, /* flags */ 0, AMETA_NONE, /* buttonState */ 0,
                          MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
                          pointerProperties, pointerCoords,
                          /* xPrecision */ 0, /* yPrecision */ 0,
                          AMOTION_EVENT_INVALID_CURSOR_POSITION,
                          AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {});

    return args;
}

static void benchmarkNotifyMotion(benchmark::State& state) {
    // Create dispatcher
    sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
    sp<InputDispatcher> dispatcher = new InputDispatcher(fakePolicy);
    dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
    dispatcher->start();

    // Create a window that will receive motion events
    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
    sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");

    dispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);

    NotifyMotionArgs motionArgs = generateMotionArgs();

    for (auto _ : state) {
        // Send ACTION_DOWN
        motionArgs.action = AMOTION_EVENT_ACTION_DOWN;
        motionArgs.sequenceNum = 0;
        motionArgs.downTime = now();
        motionArgs.eventTime = motionArgs.downTime;
        dispatcher->notifyMotion(&motionArgs);

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

        window->consumeEvent();
        window->consumeEvent();
    }

    dispatcher->stop();
}

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

    // Create a window that will receive motion events
    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
    sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");

    dispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);

    MotionEvent event = generateMotionEvent();

    for (auto _ : state) {
        // Send ACTION_DOWN
        event.setAction(AMOTION_EVENT_ACTION_DOWN);
        event.setDownTime(now());
        dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
                                     INPUT_EVENT_INJECTION_SYNC_NONE, INJECT_EVENT_TIMEOUT,
                                     POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);

        // Send ACTION_UP
        event.setAction(AMOTION_EVENT_ACTION_UP);
        dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
                                     INPUT_EVENT_INJECTION_SYNC_NONE, INJECT_EVENT_TIMEOUT,
                                     POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);

        window->consumeEvent();
        window->consumeEvent();
    }

    dispatcher->stop();
}

BENCHMARK(benchmarkNotifyMotion);
BENCHMARK(benchmarkInjectMotion);

} // namespace android::inputdispatcher

BENCHMARK_MAIN();
+2 −2
Original line number Diff line number Diff line
@@ -505,7 +505,7 @@ protected:
            const std::string name, int32_t displayId) :
                mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
            InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
            mConsumer = new InputConsumer(mClientChannel);
            mConsumer = std::make_unique<InputConsumer>(mClientChannel);
        }

        virtual ~FakeInputReceiver() {
@@ -518,7 +518,7 @@ protected:

        sp<InputDispatcher> mDispatcher;
        sp<InputChannel> mServerChannel, mClientChannel;
        InputConsumer *mConsumer;
        std::unique_ptr<InputConsumer> mConsumer;
        PreallocatedInputEventFactory mEventFactory;

        std::string mName;