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