1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <benchmark/benchmark.h>
18 
19 #include <binder/Binder.h>
20 #include "../dispatcher/InputDispatcher.h"
21 
22 namespace android::inputdispatcher {
23 
24 // An arbitrary device id.
25 static const int32_t DEVICE_ID = 1;
26 
27 // An arbitrary injector pid / uid pair that has permission to inject events.
28 static const int32_t INJECTOR_PID = 999;
29 static const int32_t INJECTOR_UID = 1001;
30 
31 static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
32 static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
33 
now()34 static nsecs_t now() {
35     return systemTime(SYSTEM_TIME_MONOTONIC);
36 }
37 
38 // --- FakeInputDispatcherPolicy ---
39 
40 class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface {
41 public:
FakeInputDispatcherPolicy()42     FakeInputDispatcherPolicy() {}
43 
44 protected:
~FakeInputDispatcherPolicy()45     virtual ~FakeInputDispatcherPolicy() {}
46 
47 private:
notifyConfigurationChanged(nsecs_t)48     virtual void notifyConfigurationChanged(nsecs_t) override {}
49 
notifyAnr(const sp<InputApplicationHandle> &,const sp<IBinder> &,const std::string & name)50     virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>&, const sp<IBinder>&,
51                               const std::string& name) override {
52         ALOGE("The window is not responding : %s", name.c_str());
53         return 0;
54     }
55 
notifyInputChannelBroken(const sp<IBinder> &)56     virtual void notifyInputChannelBroken(const sp<IBinder>&) override {}
57 
notifyFocusChanged(const sp<IBinder> &,const sp<IBinder> &)58     virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {}
59 
getDispatcherConfiguration(InputDispatcherConfiguration * outConfig)60     virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
61         *outConfig = mConfig;
62     }
63 
filterInputEvent(const InputEvent * inputEvent,uint32_t policyFlags)64     virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override {
65         return true;
66     }
67 
interceptKeyBeforeQueueing(const KeyEvent *,uint32_t &)68     virtual void interceptKeyBeforeQueueing(const KeyEvent*, uint32_t&) override {}
69 
interceptMotionBeforeQueueing(int32_t,nsecs_t,uint32_t &)70     virtual void interceptMotionBeforeQueueing(int32_t, nsecs_t, uint32_t&) override {}
71 
interceptKeyBeforeDispatching(const sp<IBinder> &,const KeyEvent *,uint32_t)72     virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent*,
73                                                   uint32_t) override {
74         return 0;
75     }
76 
dispatchUnhandledKey(const sp<IBinder> &,const KeyEvent *,uint32_t,KeyEvent *)77     virtual bool dispatchUnhandledKey(const sp<IBinder>&, const KeyEvent*, uint32_t,
78                                       KeyEvent*) override {
79         return false;
80     }
81 
notifySwitch(nsecs_t,uint32_t,uint32_t,uint32_t)82     virtual void notifySwitch(nsecs_t, uint32_t, uint32_t, uint32_t) override {}
83 
pokeUserActivity(nsecs_t,int32_t)84     virtual void pokeUserActivity(nsecs_t, int32_t) override {}
85 
checkInjectEventsPermissionNonReentrant(int32_t,int32_t)86     virtual bool checkInjectEventsPermissionNonReentrant(int32_t, int32_t) override {
87         return false;
88     }
89 
onPointerDownOutsideFocus(const sp<IBinder> & newToken)90     virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
91 
92     InputDispatcherConfiguration mConfig;
93 };
94 
95 class FakeApplicationHandle : public InputApplicationHandle {
96 public:
FakeApplicationHandle()97     FakeApplicationHandle() {}
~FakeApplicationHandle()98     virtual ~FakeApplicationHandle() {}
99 
updateInfo()100     virtual bool updateInfo() {
101         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
102         return true;
103     }
104 };
105 
106 class FakeInputReceiver {
107 public:
consumeEvent()108     void consumeEvent() {
109         uint32_t consumeSeq;
110         InputEvent* event;
111 
112         std::chrono::time_point start = std::chrono::steady_clock::now();
113         status_t result = WOULD_BLOCK;
114         while (result == WOULD_BLOCK) {
115             std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
116             if (elapsed > 10ms) {
117                 ALOGE("Waited too long for consumer to produce an event, giving up");
118                 break;
119             }
120             result = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq,
121                                         &event);
122         }
123         if (result != OK) {
124             ALOGE("Received result = %d from consume()", result);
125         }
126         result = mConsumer->sendFinishedSignal(consumeSeq, true);
127         if (result != OK) {
128             ALOGE("Received result = %d from sendFinishedSignal", result);
129         }
130     }
131 
132 protected:
FakeInputReceiver(const sp<InputDispatcher> & dispatcher,const std::string name)133     explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher, const std::string name)
134           : mDispatcher(dispatcher) {
135         InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
136         mConsumer = std::make_unique<InputConsumer>(mClientChannel);
137     }
138 
~FakeInputReceiver()139     virtual ~FakeInputReceiver() {}
140 
141     sp<InputDispatcher> mDispatcher;
142     sp<InputChannel> mServerChannel, mClientChannel;
143     std::unique_ptr<InputConsumer> mConsumer;
144     PreallocatedInputEventFactory mEventFactory;
145 };
146 
147 class FakeWindowHandle : public InputWindowHandle, public FakeInputReceiver {
148 public:
149     static const int32_t WIDTH = 200;
150     static const int32_t HEIGHT = 200;
151 
FakeWindowHandle(const sp<InputApplicationHandle> & inputApplicationHandle,const sp<InputDispatcher> & dispatcher,const std::string name)152     FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
153                      const sp<InputDispatcher>& dispatcher, const std::string name)
154           : FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) {
155         mDispatcher->registerInputChannel(mServerChannel);
156 
157         inputApplicationHandle->updateInfo();
158         mInfo.applicationInfo = *inputApplicationHandle->getInfo();
159     }
160 
updateInfo()161     virtual bool updateInfo() override {
162         mInfo.token = mServerChannel->getConnectionToken();
163         mInfo.name = "FakeWindowHandle";
164         mInfo.layoutParamsFlags = 0;
165         mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
166         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT.count();
167         mInfo.frameLeft = mFrame.left;
168         mInfo.frameTop = mFrame.top;
169         mInfo.frameRight = mFrame.right;
170         mInfo.frameBottom = mFrame.bottom;
171         mInfo.globalScaleFactor = 1.0;
172         mInfo.touchableRegion.clear();
173         mInfo.addTouchableRegion(mFrame);
174         mInfo.visible = true;
175         mInfo.canReceiveKeys = true;
176         mInfo.hasFocus = true;
177         mInfo.hasWallpaper = false;
178         mInfo.paused = false;
179         mInfo.ownerPid = INJECTOR_PID;
180         mInfo.ownerUid = INJECTOR_UID;
181         mInfo.inputFeatures = 0;
182         mInfo.displayId = ADISPLAY_ID_DEFAULT;
183 
184         return true;
185     }
186 
187 protected:
188     Rect mFrame;
189 };
190 
generateMotionEvent()191 static MotionEvent generateMotionEvent() {
192     PointerProperties pointerProperties[1];
193     PointerCoords pointerCoords[1];
194 
195     pointerProperties[0].clear();
196     pointerProperties[0].id = 0;
197     pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
198 
199     pointerCoords[0].clear();
200     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
201     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 100);
202 
203     const nsecs_t currentTime = now();
204 
205     MotionEvent event;
206     event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
207                      ADISPLAY_ID_DEFAULT, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN,
208                      /* actionButton */ 0, /* flags */ 0,
209                      /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
210                      1 /* xScale */, 1 /* yScale */,
211                      /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
212                      /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
213                      AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, currentTime,
214                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
215     return event;
216 }
217 
generateMotionArgs()218 static NotifyMotionArgs generateMotionArgs() {
219     PointerProperties pointerProperties[1];
220     PointerCoords pointerCoords[1];
221 
222     pointerProperties[0].clear();
223     pointerProperties[0].id = 0;
224     pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
225 
226     pointerCoords[0].clear();
227     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
228     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 100);
229 
230     const nsecs_t currentTime = now();
231     // Define a valid motion event.
232     NotifyMotionArgs args(/* id */ 0, currentTime, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
233                           ADISPLAY_ID_DEFAULT, POLICY_FLAG_PASS_TO_USER, AMOTION_EVENT_ACTION_DOWN,
234                           /* actionButton */ 0, /* flags */ 0, AMETA_NONE, /* buttonState */ 0,
235                           MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
236                           pointerProperties, pointerCoords,
237                           /* xPrecision */ 0, /* yPrecision */ 0,
238                           AMOTION_EVENT_INVALID_CURSOR_POSITION,
239                           AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {});
240 
241     return args;
242 }
243 
benchmarkNotifyMotion(benchmark::State & state)244 static void benchmarkNotifyMotion(benchmark::State& state) {
245     // Create dispatcher
246     sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
247     sp<InputDispatcher> dispatcher = new InputDispatcher(fakePolicy);
248     dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
249     dispatcher->start();
250 
251     // Create a window that will receive motion events
252     sp<FakeApplicationHandle> application = new FakeApplicationHandle();
253     sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
254 
255     dispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
256 
257     NotifyMotionArgs motionArgs = generateMotionArgs();
258 
259     for (auto _ : state) {
260         // Send ACTION_DOWN
261         motionArgs.action = AMOTION_EVENT_ACTION_DOWN;
262         motionArgs.id = 0;
263         motionArgs.downTime = now();
264         motionArgs.eventTime = motionArgs.downTime;
265         dispatcher->notifyMotion(&motionArgs);
266 
267         // Send ACTION_UP
268         motionArgs.action = AMOTION_EVENT_ACTION_UP;
269         motionArgs.id = 1;
270         motionArgs.eventTime = now();
271         dispatcher->notifyMotion(&motionArgs);
272 
273         window->consumeEvent();
274         window->consumeEvent();
275     }
276 
277     dispatcher->stop();
278 }
279 
benchmarkInjectMotion(benchmark::State & state)280 static void benchmarkInjectMotion(benchmark::State& state) {
281     // Create dispatcher
282     sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
283     sp<InputDispatcher> dispatcher = new InputDispatcher(fakePolicy);
284     dispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
285     dispatcher->start();
286 
287     // Create a window that will receive motion events
288     sp<FakeApplicationHandle> application = new FakeApplicationHandle();
289     sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
290 
291     dispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
292 
293     for (auto _ : state) {
294         MotionEvent event = generateMotionEvent();
295         // Send ACTION_DOWN
296         dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
297                                      INPUT_EVENT_INJECTION_SYNC_NONE, INJECT_EVENT_TIMEOUT,
298                                      POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
299 
300         // Send ACTION_UP
301         event.setAction(AMOTION_EVENT_ACTION_UP);
302         dispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
303                                      INPUT_EVENT_INJECTION_SYNC_NONE, INJECT_EVENT_TIMEOUT,
304                                      POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
305 
306         window->consumeEvent();
307         window->consumeEvent();
308     }
309 
310     dispatcher->stop();
311 }
312 
313 BENCHMARK(benchmarkNotifyMotion);
314 BENCHMARK(benchmarkInjectMotion);
315 
316 } // namespace android::inputdispatcher
317 
318 BENCHMARK_MAIN();
319