/* * 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 #include #include #include "../dispatcher/InputDispatcher.h" #include "../tests/FakeApplicationHandle.h" #include "../tests/FakeInputDispatcherPolicy.h" #include "../tests/FakeWindows.h" using android::base::Result; using android::gui::WindowInfo; using android::os::IInputConstants; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; namespace android::inputdispatcher { namespace { // An arbitrary device id. constexpr DeviceId DEVICE_ID = 1; // An arbitrary display id constexpr ui::LogicalDisplayId DISPLAY_ID = ui::LogicalDisplayId::DEFAULT; static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s; static nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); } static MotionEvent generateMotionEvent() { PointerProperties pointerProperties[1]; PointerCoords pointerCoords[1]; pointerProperties[0].clear(); pointerProperties[0].id = 0; pointerProperties[0].toolType = ToolType::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(); ui::Transform identityTransform; MotionEvent event; event.initialize(IInputConstants::INVALID_INPUT_EVENT_ID, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::DEFAULT, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, identityTransform, /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 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 = ToolType::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(IInputConstants::INVALID_INPUT_EVENT_ID, currentTime, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, ui::LogicalDisplayId::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 FakeInputDispatcherPolicy fakePolicy; auto dispatcher = std::make_unique(fakePolicy); dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); dispatcher->start(); // Create a window that will receive motion events std::shared_ptr application = std::make_shared(); sp window = sp::make(application, dispatcher, "Fake Window", DISPLAY_ID); dispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); NotifyMotionArgs motionArgs = generateMotionArgs(); for (auto _ : state) { // Send ACTION_DOWN motionArgs.action = AMOTION_EVENT_ACTION_DOWN; motionArgs.downTime = now(); motionArgs.eventTime = motionArgs.downTime; dispatcher->notifyMotion(motionArgs); // Send ACTION_UP motionArgs.action = AMOTION_EVENT_ACTION_UP; motionArgs.eventTime = now(); dispatcher->notifyMotion(motionArgs); window->consumeMotionEvent(); window->consumeMotionEvent(); } dispatcher->stop(); } static void benchmarkInjectMotion(benchmark::State& state) { // Create dispatcher FakeInputDispatcherPolicy fakePolicy; auto dispatcher = std::make_unique(fakePolicy); dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); dispatcher->start(); // Create a window that will receive motion events std::shared_ptr application = std::make_shared(); sp window = sp::make(application, dispatcher, "Fake Window", DISPLAY_ID); dispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); for (auto _ : state) { MotionEvent event = generateMotionEvent(); // Send ACTION_DOWN 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, INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER); window->consumeMotionEvent(); window->consumeMotionEvent(); } dispatcher->stop(); } static void benchmarkOnWindowInfosChanged(benchmark::State& state) { // Create dispatcher FakeInputDispatcherPolicy fakePolicy; auto dispatcher = std::make_unique(fakePolicy); dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); dispatcher->start(); // Create a window std::shared_ptr application = std::make_shared(); sp window = sp::make(application, dispatcher, "Fake Window", DISPLAY_ID); std::vector windowInfos{*window->getInfo()}; gui::DisplayInfo info; info.displayId = window->getInfo()->displayId; std::vector displayInfos{info}; for (auto _ : state) { dispatcher->onWindowInfosChanged( {windowInfos, displayInfos, /*vsyncId=*/0, /*timestamp=*/0}); dispatcher->onWindowInfosChanged( {/*windowInfos=*/{}, /*displayInfos=*/{}, /*vsyncId=*/{}, /*timestamp=*/0}); } dispatcher->stop(); } } // namespace BENCHMARK(benchmarkNotifyMotion); BENCHMARK(benchmarkInjectMotion); BENCHMARK(benchmarkOnWindowInfosChanged); } // namespace android::inputdispatcher BENCHMARK_MAIN();