1 /*
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 <fuzzer/FuzzedDataProvider.h>
18
19 namespace android {
20
21 static constexpr int32_t MAX_RANDOM_POINTERS = 4;
22 static constexpr int32_t MAX_RANDOM_DEVICES = 4;
23
24 // The maximum value that we use for the action button field of NotifyMotionArgs. (We allow multiple
25 // bits to be set for this since we're just trying to generate a fuzzed event stream that doesn't
26 // cause crashes when enum values are converted to Rust — we don't necessarily want it to be valid.)
27 //
28 // AMOTION_EVENT_BUTTON_STYLUS_SECONDARY should be replaced with whatever AMOTION_EVENT_BUTTON_
29 // value is highest if the enum is edited.
30 static constexpr int8_t MAX_ACTION_BUTTON_VALUE = (AMOTION_EVENT_BUTTON_STYLUS_SECONDARY << 1) - 1;
31
getFuzzedMotionAction(FuzzedDataProvider & fdp)32 int getFuzzedMotionAction(FuzzedDataProvider& fdp) {
33 int actionMasked = fdp.PickValueInArray<int>({
34 AMOTION_EVENT_ACTION_DOWN, AMOTION_EVENT_ACTION_UP, AMOTION_EVENT_ACTION_MOVE,
35 AMOTION_EVENT_ACTION_HOVER_ENTER, AMOTION_EVENT_ACTION_HOVER_MOVE,
36 AMOTION_EVENT_ACTION_HOVER_EXIT, AMOTION_EVENT_ACTION_CANCEL,
37 // do not inject AMOTION_EVENT_ACTION_OUTSIDE,
38 AMOTION_EVENT_ACTION_SCROLL, AMOTION_EVENT_ACTION_POINTER_DOWN,
39 AMOTION_EVENT_ACTION_POINTER_UP,
40 // do not send buttons until verifier supports them
41 // AMOTION_EVENT_ACTION_BUTTON_PRESS,
42 // AMOTION_EVENT_ACTION_BUTTON_RELEASE,
43 });
44 switch (actionMasked) {
45 case AMOTION_EVENT_ACTION_POINTER_DOWN:
46 case AMOTION_EVENT_ACTION_POINTER_UP: {
47 const int32_t index = fdp.ConsumeIntegralInRange(0, MAX_RANDOM_POINTERS - 1);
48 const int32_t action =
49 actionMasked | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
50 return action;
51 }
52 default:
53 return actionMasked;
54 }
55 }
56
57 /**
58 * For now, focus on the 3 main sources.
59 */
getFuzzedSource(FuzzedDataProvider & fdp)60 int getFuzzedSource(FuzzedDataProvider& fdp) {
61 return fdp.PickValueInArray<int>({
62 // AINPUT_SOURCE_UNKNOWN,
63 // AINPUT_SOURCE_KEYBOARD,
64 // AINPUT_SOURCE_DPAD,
65 // AINPUT_SOURCE_GAMEPAD,
66 AINPUT_SOURCE_TOUCHSCREEN, AINPUT_SOURCE_MOUSE, AINPUT_SOURCE_STYLUS,
67 // AINPUT_SOURCE_BLUETOOTH_STYLUS,
68 // AINPUT_SOURCE_TRACKBALL,
69 // AINPUT_SOURCE_MOUSE_RELATIVE,
70 // AINPUT_SOURCE_TOUCHPAD,
71 // AINPUT_SOURCE_TOUCH_NAVIGATION,
72 // AINPUT_SOURCE_JOYSTICK,
73 // AINPUT_SOURCE_HDMI,
74 // AINPUT_SOURCE_SENSOR,
75 // AINPUT_SOURCE_ROTARY_ENCODER,
76 // AINPUT_SOURCE_ANY,
77 });
78 }
79
getFuzzedButtonState(FuzzedDataProvider & fdp)80 int getFuzzedButtonState(FuzzedDataProvider& fdp) {
81 return fdp.PickValueInArray<int>({
82 0,
83 // AMOTION_EVENT_BUTTON_PRIMARY,
84 // AMOTION_EVENT_BUTTON_SECONDARY,
85 // AMOTION_EVENT_BUTTON_TERTIARY,
86 // AMOTION_EVENT_BUTTON_BACK,
87 // AMOTION_EVENT_BUTTON_FORWARD,
88 // AMOTION_EVENT_BUTTON_STYLUS_PRIMARY,
89 // AMOTION_EVENT_BUTTON_STYLUS_SECONDARY,
90 });
91 }
92
getFuzzedFlags(FuzzedDataProvider & fdp,int32_t action)93 int32_t getFuzzedFlags(FuzzedDataProvider& fdp, int32_t action) {
94 constexpr std::array<int32_t, 4> FLAGS{
95 AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
96 AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED,
97 AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT,
98 AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE,
99 };
100
101 int32_t flags = 0;
102 for (size_t i = 0; i < fdp.ConsumeIntegralInRange(size_t(0), FLAGS.size()); i++) {
103 flags |= fdp.PickValueInArray<int32_t>(FLAGS);
104 }
105 if (action == AMOTION_EVENT_ACTION_CANCEL) {
106 flags |= AMOTION_EVENT_FLAG_CANCELED;
107 }
108 if (MotionEvent::getActionMasked(action) == AMOTION_EVENT_ACTION_POINTER_UP) {
109 if (fdp.ConsumeBool()) {
110 flags |= AMOTION_EVENT_FLAG_CANCELED;
111 }
112 }
113 return flags;
114 }
115
getFuzzedPointerCount(FuzzedDataProvider & fdp,int32_t action)116 int32_t getFuzzedPointerCount(FuzzedDataProvider& fdp, int32_t action) {
117 switch (MotionEvent::getActionMasked(action)) {
118 case AMOTION_EVENT_ACTION_DOWN:
119 case AMOTION_EVENT_ACTION_UP: {
120 return 1;
121 }
122 case AMOTION_EVENT_ACTION_OUTSIDE:
123 case AMOTION_EVENT_ACTION_CANCEL:
124 case AMOTION_EVENT_ACTION_MOVE:
125 return fdp.ConsumeIntegralInRange<int32_t>(1, MAX_RANDOM_POINTERS);
126 case AMOTION_EVENT_ACTION_HOVER_ENTER:
127 case AMOTION_EVENT_ACTION_HOVER_MOVE:
128 case AMOTION_EVENT_ACTION_HOVER_EXIT:
129 return 1;
130 case AMOTION_EVENT_ACTION_SCROLL:
131 return 1;
132 case AMOTION_EVENT_ACTION_POINTER_DOWN:
133 case AMOTION_EVENT_ACTION_POINTER_UP: {
134 const uint8_t actionIndex = MotionEvent::getActionIndex(action);
135 const int32_t count =
136 std::max(actionIndex + 1,
137 fdp.ConsumeIntegralInRange<int32_t>(1, MAX_RANDOM_POINTERS));
138 // Need to have at least 2 pointers
139 return std::max(2, count);
140 }
141 case AMOTION_EVENT_ACTION_BUTTON_PRESS:
142 case AMOTION_EVENT_ACTION_BUTTON_RELEASE: {
143 return 1;
144 }
145 }
146 return 1;
147 }
148
getToolType(int32_t source)149 ToolType getToolType(int32_t source) {
150 switch (source) {
151 case AINPUT_SOURCE_TOUCHSCREEN:
152 return ToolType::FINGER;
153 case AINPUT_SOURCE_MOUSE:
154 return ToolType::MOUSE;
155 case AINPUT_SOURCE_STYLUS:
156 return ToolType::STYLUS;
157 }
158 return ToolType::UNKNOWN;
159 }
160
now()161 inline nsecs_t now() {
162 return systemTime(SYSTEM_TIME_MONOTONIC);
163 }
164
generateFuzzedMotionArgs(IdGenerator & idGenerator,FuzzedDataProvider & fdp,int32_t maxDisplays)165 NotifyMotionArgs generateFuzzedMotionArgs(IdGenerator& idGenerator, FuzzedDataProvider& fdp,
166 int32_t maxDisplays) {
167 // Create a basic motion event for testing
168 const int32_t source = getFuzzedSource(fdp);
169 const ToolType toolType = getToolType(source);
170 const int32_t action = getFuzzedMotionAction(fdp);
171 const int32_t pointerCount = getFuzzedPointerCount(fdp, action);
172 std::vector<PointerProperties> pointerProperties;
173 std::vector<PointerCoords> pointerCoords;
174 for (int i = 0; i < pointerCount; i++) {
175 PointerProperties properties{};
176 properties.id = i;
177 properties.toolType = toolType;
178 pointerProperties.push_back(properties);
179
180 PointerCoords coords{};
181 coords.setAxisValue(AMOTION_EVENT_AXIS_X, fdp.ConsumeIntegralInRange<int>(-1000, 1000));
182 coords.setAxisValue(AMOTION_EVENT_AXIS_Y, fdp.ConsumeIntegralInRange<int>(-1000, 1000));
183 coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1);
184 pointerCoords.push_back(coords);
185 }
186
187 const ui::LogicalDisplayId displayId{fdp.ConsumeIntegralInRange<int32_t>(0, maxDisplays - 1)};
188 const int32_t deviceId = fdp.ConsumeIntegralInRange<int32_t>(0, MAX_RANDOM_DEVICES - 1);
189
190 // Current time +- 5 seconds
191 const nsecs_t currentTime = now();
192 const nsecs_t downTime =
193 fdp.ConsumeIntegralInRange<nsecs_t>(currentTime - 5E9, currentTime + 5E9);
194 const nsecs_t readTime = downTime;
195 const nsecs_t eventTime = fdp.ConsumeIntegralInRange<nsecs_t>(downTime, downTime + 1E9);
196 const int32_t actionButton = fdp.ConsumeIntegralInRange<int32_t>(0, MAX_ACTION_BUTTON_VALUE);
197
198 const float cursorX = fdp.ConsumeIntegralInRange<int>(-10000, 10000);
199 const float cursorY = fdp.ConsumeIntegralInRange<int>(-10000, 10000);
200 return NotifyMotionArgs(idGenerator.nextId(), eventTime, readTime, deviceId, source, displayId,
201 POLICY_FLAG_PASS_TO_USER, action, actionButton,
202 getFuzzedFlags(fdp, action), AMETA_NONE, getFuzzedButtonState(fdp),
203 MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
204 pointerProperties.data(), pointerCoords.data(), /*xPrecision=*/0,
205 /*yPrecision=*/0, cursorX, cursorY, downTime, /*videoFrames=*/{});
206 }
207
208 } // namespace android
209