blob: dc5a2130e74b406e5d58b2a3db1dafb1a05f4c37 [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)
Siarhei Vishniakou119604e2023-12-06 14:22:35 -080044 : mFdp(fdp), mIdGenerator(IdGenerator::Source::OTHER) {}
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070045
46 std::optional<NotifyMotionArgs> nextMotion() {
47 NotifyMotionArgs args = generateFuzzedMotionArgs(mIdGenerator, mFdp, MAX_RANDOM_DISPLAYS);
Siarhei Vishniakou119604e2023-12-06 14:22:35 -080048 auto [it, _] = mVerifiers.emplace(args.displayId, "Fuzz Verifier");
49 InputVerifier& verifier = it->second;
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070050 const Result<void> result =
Siarhei Vishniakou119604e2023-12-06 14:22:35 -080051 verifier.processMovement(args.deviceId, args.source, args.action,
52 args.getPointerCount(), args.pointerProperties.data(),
53 args.pointerCoords.data(), args.flags);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070054 if (result.ok()) {
55 return args;
56 }
57 return {};
58 }
59
60private:
61 FuzzedDataProvider& mFdp;
62
63 IdGenerator mIdGenerator;
64
Siarhei Vishniakou119604e2023-12-06 14:22:35 -080065 std::map<int32_t /*displayId*/, InputVerifier> mVerifiers;
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070066};
67
Siarhei Vishniakouf1930a12023-11-16 10:28:05 -080068void scrambleWindow(FuzzedDataProvider& fdp, FakeWindowHandle& window) {
69 const int32_t left = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
70 const int32_t top = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
71 const int32_t width = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
72 const int32_t height = fdp.ConsumeIntegralInRange<int32_t>(0, 100);
73
74 window.setFrame(Rect(left, top, left + width, top + height));
75 window.setSlippery(fdp.ConsumeBool());
76 window.setDupTouchToWallpaper(fdp.ConsumeBool());
77 window.setIsWallpaper(fdp.ConsumeBool());
78 window.setVisible(fdp.ConsumeBool());
79 window.setPreventSplitting(fdp.ConsumeBool());
80 const bool isTrustedOverlay = fdp.ConsumeBool();
81 window.setTrustedOverlay(isTrustedOverlay);
82 if (isTrustedOverlay) {
83 window.setSpy(fdp.ConsumeBool());
84 } else {
85 window.setSpy(false);
86 }
87}
88
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070089} // namespace
90
91sp<FakeWindowHandle> generateFuzzedWindow(FuzzedDataProvider& fdp, InputDispatcher& dispatcher,
92 int32_t displayId) {
93 static size_t windowNumber = 0;
94 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
95 std::string windowName = android::base::StringPrintf("Win") + std::to_string(windowNumber++);
96 sp<FakeWindowHandle> window =
Siarhei Vishniakouf1930a12023-11-16 10:28:05 -080097 sp<FakeWindowHandle>::make(application, dispatcher, windowName, displayId);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -070098
Siarhei Vishniakouf1930a12023-11-16 10:28:05 -080099 scrambleWindow(fdp, *window);
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700100 return window;
101}
102
103void randomizeWindows(
104 std::unordered_map<int32_t, std::vector<sp<FakeWindowHandle>>>& windowsPerDisplay,
105 FuzzedDataProvider& fdp, InputDispatcher& dispatcher) {
106 const int32_t displayId = fdp.ConsumeIntegralInRange<int32_t>(0, MAX_RANDOM_DISPLAYS - 1);
107 std::vector<sp<FakeWindowHandle>>& windows = windowsPerDisplay[displayId];
108
109 fdp.PickValueInArray<std::function<void()>>({
110 // Add a new window
111 [&]() -> void {
112 if (windows.size() < MAX_RANDOM_WINDOWS) {
113 windows.push_back(generateFuzzedWindow(fdp, dispatcher, displayId));
114 }
115 },
116 // Remove a window
117 [&]() -> void {
118 if (windows.empty()) {
119 return;
120 }
121 const int32_t erasedPosition =
122 fdp.ConsumeIntegralInRange<int32_t>(0, windows.size() - 1);
123
124 windows.erase(windows.begin() + erasedPosition);
125 if (windows.empty()) {
126 windowsPerDisplay.erase(displayId);
127 }
128 },
Siarhei Vishniakouf1930a12023-11-16 10:28:05 -0800129 // Change flags or move some of the existing windows
130 [&]() -> void {
131 for (auto& window : windows) {
132 if (fdp.ConsumeBool()) {
133 scrambleWindow(fdp, *window);
134 }
135 }
136 },
Siarhei Vishniakou2defec02023-06-08 17:24:44 -0700137 })();
138}
139
140extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
141 FuzzedDataProvider fdp(data, size);
142 NotifyStreamProvider streamProvider(fdp);
143
144 FakeInputDispatcherPolicy fakePolicy;
145 InputDispatcher dispatcher(fakePolicy);
146 dispatcher.setInputDispatchMode(/*enabled=*/true, /*frozen=*/false);
147 // Start InputDispatcher thread
148 dispatcher.start();
149
150 std::unordered_map<int32_t, std::vector<sp<FakeWindowHandle>>> windowsPerDisplay;
151
152 // Randomly invoke InputDispatcher api's until randomness is exhausted.
153 while (fdp.remaining_bytes() > 0) {
154 fdp.PickValueInArray<std::function<void()>>({
155 [&]() -> void {
156 std::optional<NotifyMotionArgs> motion = streamProvider.nextMotion();
157 if (motion) {
158 dispatcher.notifyMotion(*motion);
159 }
160 },
161 [&]() -> void {
162 // Scramble the windows we currently have
163 randomizeWindows(/*byref*/ windowsPerDisplay, fdp, dispatcher);
164
165 std::vector<WindowInfo> windowInfos;
166 for (const auto& [displayId, windows] : windowsPerDisplay) {
167 for (const sp<FakeWindowHandle>& window : windows) {
168 windowInfos.emplace_back(*window->getInfo());
169 }
170 }
171
172 dispatcher.onWindowInfosChanged(
173 {windowInfos, {}, /*vsyncId=*/0, /*timestamp=*/0});
174 },
175 // Consume on all the windows
176 [&]() -> void {
177 for (const auto& [_, windows] : windowsPerDisplay) {
178 for (const sp<FakeWindowHandle>& window : windows) {
179 // To speed up the fuzzing, don't wait for consumption. If there's an
180 // event pending, this can be consumed on the next call instead.
181 // We also don't care about whether consumption succeeds here, or what
182 // kind of event is returned.
183 window->consume(0ms);
184 }
185 }
186 },
187 })();
188 }
189
190 dispatcher.stop();
191
192 return 0;
193}
194
195} // namespace inputdispatcher
196
197} // namespace android