blob: 214649cf415d1295744e270b57ac190e5263983e [file] [log] [blame]
Siarhei Vishniakou2defec02023-06-08 17:24:44 -07001/*
2 * Copyright 2023 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 <android-base/stringprintf.h>
18#include <fuzzer/FuzzedDataProvider.h>
19#include "../FakeApplicationHandle.h"
20#include "../FakeInputDispatcherPolicy.h"
21#include "../FakeWindowHandle.h"
22#include "FuzzedInputStream.h"
23#include "dispatcher/InputDispatcher.h"
24#include "input/InputVerifier.h"
25
26namespace android {
27
28using android::base::Result;
29using android::gui::WindowInfo;
30
31namespace inputdispatcher {
32
33namespace {
34
35static constexpr int32_t MAX_RANDOM_DISPLAYS = 4;
36static constexpr int32_t MAX_RANDOM_WINDOWS = 4;
37
38/**
39 * Provide a valid motion stream, to make the fuzzer more effective.
40 */
41class NotifyStreamProvider {
42public:
43 NotifyStreamProvider(FuzzedDataProvider& fdp)
44 : mFdp(fdp), mIdGenerator(IdGenerator::Source::OTHER), mVerifier("Fuzz verifier") {}
45
46 std::optional<NotifyMotionArgs> nextMotion() {
47 NotifyMotionArgs args = generateFuzzedMotionArgs(mIdGenerator, mFdp, MAX_RANDOM_DISPLAYS);
48 const Result<void> result =
49 mVerifier.processMovement(args.deviceId, args.source, args.action,
50 args.getPointerCount(), args.pointerProperties.data(),
51 args.pointerCoords.data(), args.flags);
52 if (result.ok()) {
53 return args;
54 }
55 return {};
56 }
57
58private:
59 FuzzedDataProvider& mFdp;
60
61 IdGenerator mIdGenerator;
62
63 InputVerifier mVerifier;
64};
65
66} // namespace
67
68sp<FakeWindowHandle> generateFuzzedWindow(FuzzedDataProvider& fdp, InputDispatcher& dispatcher,
69 int32_t displayId) {
70 static size_t windowNumber = 0;
71 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
72 std::string windowName = android::base::StringPrintf("Win") + std::to_string(windowNumber++);
73 sp<FakeWindowHandle> window =
74 sp<FakeWindowHandle>::make(application, dispatcher, "Fake", displayId);
75
76 const int32_t left = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
77 const int32_t top = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
78 const int32_t width = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
79 const int32_t height = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
80
81 window->setFrame(Rect(left, top, left + width, top + height));
82 window->setSlippery(fdp.ConsumeBool());
83 window->setDupTouchToWallpaper(fdp.ConsumeBool());
84 window->setTrustedOverlay(fdp.ConsumeBool());
85 return window;
86}
87
88void randomizeWindows(
89 std::unordered_map<int32_t, std::vector<sp<FakeWindowHandle>>>& windowsPerDisplay,
90 FuzzedDataProvider& fdp, InputDispatcher& dispatcher) {
91 const int32_t displayId = fdp.ConsumeIntegralInRange<int32_t>(0, MAX_RANDOM_DISPLAYS - 1);
92 std::vector<sp<FakeWindowHandle>>& windows = windowsPerDisplay[displayId];
93
94 fdp.PickValueInArray<std::function<void()>>({
95 // Add a new window
96 [&]() -> void {
97 if (windows.size() < MAX_RANDOM_WINDOWS) {
98 windows.push_back(generateFuzzedWindow(fdp, dispatcher, displayId));
99 }
100 },
101 // Remove a window
102 [&]() -> void {
103 if (windows.empty()) {
104 return;
105 }
106 const int32_t erasedPosition =
107 fdp.ConsumeIntegralInRange<int32_t>(0, windows.size() - 1);
108
109 windows.erase(windows.begin() + erasedPosition);
110 if (windows.empty()) {
111 windowsPerDisplay.erase(displayId);
112 }
113 },
114 // Could also clone a window, change flags, reposition, etc...
115 })();
116}
117
118extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
119 FuzzedDataProvider fdp(data, size);
120 NotifyStreamProvider streamProvider(fdp);
121
122 FakeInputDispatcherPolicy fakePolicy;
123 InputDispatcher dispatcher(fakePolicy);
124 dispatcher.setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
125 // Start InputDispatcher thread
126 dispatcher.start();
127
128 std::unordered_map<int32_t, std::vector<sp<FakeWindowHandle>>> windowsPerDisplay;
129
130 // Randomly invoke InputDispatcher api's until randomness is exhausted.
131 while (fdp.remaining_bytes() > 0) {
132 fdp.PickValueInArray<std::function<void()>>({
133 [&]() -> void {
134 std::optional<NotifyMotionArgs> motion = streamProvider.nextMotion();
135 if (motion) {
136 dispatcher.notifyMotion(*motion);
137 }
138 },
139 [&]() -> void {
140 // Scramble the windows we currently have
141 randomizeWindows(/*byref*/ windowsPerDisplay, fdp, dispatcher);
142
143 std::vector<WindowInfo> windowInfos;
144 for (const auto& [displayId, windows] : windowsPerDisplay) {
145 for (const sp<FakeWindowHandle>& window : windows) {
146 windowInfos.emplace_back(*window->getInfo());
147 }
148 }
149
150 dispatcher.onWindowInfosChanged(
151 {windowInfos, {}, /*vsyncId=*/0, /*timestamp=*/0});
152 },
153 // Consume on all the windows
154 [&]() -> void {
155 for (const auto& [_, windows] : windowsPerDisplay) {
156 for (const sp<FakeWindowHandle>& window : windows) {
157 // To speed up the fuzzing, don't wait for consumption. If there's an
158 // event pending, this can be consumed on the next call instead.
159 // We also don't care about whether consumption succeeds here, or what
160 // kind of event is returned.
161 window->consume(0ms);
162 }
163 }
164 },
165 })();
166 }
167
168 dispatcher.stop();
169
170 return 0;
171}
172
173} // namespace inputdispatcher
174
175} // namespace android