1 /*
2 * Copyright (C) 2021 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 #define LOG_TAG "InputController"
18
19 #include <android-base/unique_fd.h>
20 #include <android/input.h>
21 #include <android/keycodes.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <input/Input.h>
25 #include <input/VirtualInputDevice.h>
26 #include <linux/uinput.h>
27 #include <math.h>
28 #include <nativehelper/JNIHelp.h>
29 #include <nativehelper/ScopedUtfChars.h>
30 #include <utils/Log.h>
31
32 #include <map>
33 #include <set>
34 #include <string>
35
36 using android::base::unique_fd;
37
38 namespace android {
39
40 static constexpr jlong INVALID_PTR = 0;
41
42 enum class DeviceType {
43 KEYBOARD,
44 MOUSE,
45 TOUCHSCREEN,
46 DPAD,
47 };
48
invalidFd()49 static unique_fd invalidFd() {
50 return unique_fd(-1);
51 }
52
53 /** Creates a new uinput device and assigns a file descriptor. */
openUinput(const char * readableName,jint vendorId,jint productId,const char * phys,DeviceType deviceType,jint screenHeight,jint screenWidth)54 static unique_fd openUinput(const char* readableName, jint vendorId, jint productId,
55 const char* phys, DeviceType deviceType, jint screenHeight,
56 jint screenWidth) {
57 unique_fd fd(TEMP_FAILURE_RETRY(::open("/dev/uinput", O_WRONLY | O_NONBLOCK)));
58 if (fd < 0) {
59 ALOGE("Error creating uinput device: %s", strerror(errno));
60 return invalidFd();
61 }
62
63 ioctl(fd, UI_SET_PHYS, phys);
64
65 ioctl(fd, UI_SET_EVBIT, EV_KEY);
66 ioctl(fd, UI_SET_EVBIT, EV_SYN);
67 switch (deviceType) {
68 case DeviceType::DPAD:
69 for (const auto& [_, keyCode] : VirtualDpad::DPAD_KEY_CODE_MAPPING) {
70 ioctl(fd, UI_SET_KEYBIT, keyCode);
71 }
72 break;
73 case DeviceType::KEYBOARD:
74 for (const auto& [_, keyCode] : VirtualKeyboard::KEY_CODE_MAPPING) {
75 ioctl(fd, UI_SET_KEYBIT, keyCode);
76 }
77 break;
78 case DeviceType::MOUSE:
79 ioctl(fd, UI_SET_EVBIT, EV_REL);
80 ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
81 ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
82 ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
83 ioctl(fd, UI_SET_KEYBIT, BTN_BACK);
84 ioctl(fd, UI_SET_KEYBIT, BTN_FORWARD);
85 ioctl(fd, UI_SET_RELBIT, REL_X);
86 ioctl(fd, UI_SET_RELBIT, REL_Y);
87 ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
88 ioctl(fd, UI_SET_RELBIT, REL_HWHEEL);
89 break;
90 case DeviceType::TOUCHSCREEN:
91 ioctl(fd, UI_SET_EVBIT, EV_ABS);
92 ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
93 ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT);
94 ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
95 ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
96 ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
97 ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE);
98 ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR);
99 ioctl(fd, UI_SET_ABSBIT, ABS_MT_PRESSURE);
100 ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
101 }
102
103 int version;
104 if (ioctl(fd, UI_GET_VERSION, &version) == 0 && version >= 5) {
105 uinput_setup setup;
106 memset(&setup, 0, sizeof(setup));
107 strlcpy(setup.name, readableName, UINPUT_MAX_NAME_SIZE);
108 setup.id.version = 1;
109 setup.id.bustype = BUS_VIRTUAL;
110 setup.id.vendor = vendorId;
111 setup.id.product = productId;
112 if (deviceType == DeviceType::TOUCHSCREEN) {
113 uinput_abs_setup xAbsSetup;
114 xAbsSetup.code = ABS_MT_POSITION_X;
115 xAbsSetup.absinfo.maximum = screenWidth - 1;
116 xAbsSetup.absinfo.minimum = 0;
117 if (ioctl(fd, UI_ABS_SETUP, &xAbsSetup) != 0) {
118 ALOGE("Error creating touchscreen uinput x axis: %s", strerror(errno));
119 return invalidFd();
120 }
121 uinput_abs_setup yAbsSetup;
122 yAbsSetup.code = ABS_MT_POSITION_Y;
123 yAbsSetup.absinfo.maximum = screenHeight - 1;
124 yAbsSetup.absinfo.minimum = 0;
125 if (ioctl(fd, UI_ABS_SETUP, &yAbsSetup) != 0) {
126 ALOGE("Error creating touchscreen uinput y axis: %s", strerror(errno));
127 return invalidFd();
128 }
129 uinput_abs_setup majorAbsSetup;
130 majorAbsSetup.code = ABS_MT_TOUCH_MAJOR;
131 majorAbsSetup.absinfo.maximum = screenWidth - 1;
132 majorAbsSetup.absinfo.minimum = 0;
133 if (ioctl(fd, UI_ABS_SETUP, &majorAbsSetup) != 0) {
134 ALOGE("Error creating touchscreen uinput major axis: %s", strerror(errno));
135 return invalidFd();
136 }
137 uinput_abs_setup pressureAbsSetup;
138 pressureAbsSetup.code = ABS_MT_PRESSURE;
139 pressureAbsSetup.absinfo.maximum = 255;
140 pressureAbsSetup.absinfo.minimum = 0;
141 if (ioctl(fd, UI_ABS_SETUP, &pressureAbsSetup) != 0) {
142 ALOGE("Error creating touchscreen uinput pressure axis: %s", strerror(errno));
143 return invalidFd();
144 }
145 uinput_abs_setup slotAbsSetup;
146 slotAbsSetup.code = ABS_MT_SLOT;
147 slotAbsSetup.absinfo.maximum = MAX_POINTERS;
148 slotAbsSetup.absinfo.minimum = 0;
149 if (ioctl(fd, UI_ABS_SETUP, &slotAbsSetup) != 0) {
150 ALOGE("Error creating touchscreen uinput slots: %s", strerror(errno));
151 return invalidFd();
152 }
153 }
154 if (ioctl(fd, UI_DEV_SETUP, &setup) != 0) {
155 ALOGE("Error creating uinput device: %s", strerror(errno));
156 return invalidFd();
157 }
158 } else {
159 // UI_DEV_SETUP was not introduced until version 5. Try setting up manually.
160 ALOGI("Falling back to version %d manual setup", version);
161 uinput_user_dev fallback;
162 memset(&fallback, 0, sizeof(fallback));
163 strlcpy(fallback.name, readableName, UINPUT_MAX_NAME_SIZE);
164 fallback.id.version = 1;
165 fallback.id.bustype = BUS_VIRTUAL;
166 fallback.id.vendor = vendorId;
167 fallback.id.product = productId;
168 if (deviceType == DeviceType::TOUCHSCREEN) {
169 fallback.absmin[ABS_MT_POSITION_X] = 0;
170 fallback.absmax[ABS_MT_POSITION_X] = screenWidth - 1;
171 fallback.absmin[ABS_MT_POSITION_Y] = 0;
172 fallback.absmax[ABS_MT_POSITION_Y] = screenHeight - 1;
173 fallback.absmin[ABS_MT_TOUCH_MAJOR] = 0;
174 fallback.absmax[ABS_MT_TOUCH_MAJOR] = screenWidth - 1;
175 fallback.absmin[ABS_MT_PRESSURE] = 0;
176 fallback.absmax[ABS_MT_PRESSURE] = 255;
177 }
178 if (TEMP_FAILURE_RETRY(write(fd, &fallback, sizeof(fallback))) != sizeof(fallback)) {
179 ALOGE("Error creating uinput device: %s", strerror(errno));
180 return invalidFd();
181 }
182 }
183
184 if (ioctl(fd, UI_DEV_CREATE) != 0) {
185 ALOGE("Error creating uinput device: %s", strerror(errno));
186 return invalidFd();
187 }
188
189 return fd;
190 }
191
openUinputJni(JNIEnv * env,jstring name,jint vendorId,jint productId,jstring phys,DeviceType deviceType,int screenHeight,int screenWidth)192 static unique_fd openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productId,
193 jstring phys, DeviceType deviceType, int screenHeight,
194 int screenWidth) {
195 ScopedUtfChars readableName(env, name);
196 ScopedUtfChars readablePhys(env, phys);
197 return openUinput(readableName.c_str(), vendorId, productId, readablePhys.c_str(), deviceType,
198 screenHeight, screenWidth);
199 }
200
nativeOpenUinputDpad(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys)201 static jlong nativeOpenUinputDpad(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
202 jint productId, jstring phys) {
203 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::DPAD,
204 /* screenHeight= */ 0, /* screenWidth= */ 0);
205 return fd.ok() ? reinterpret_cast<jlong>(new VirtualDpad(std::move(fd))) : INVALID_PTR;
206 }
207
nativeOpenUinputKeyboard(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys)208 static jlong nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
209 jint productId, jstring phys) {
210 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
211 /* screenHeight= */ 0, /* screenWidth= */ 0);
212 return fd.ok() ? reinterpret_cast<jlong>(new VirtualKeyboard(std::move(fd))) : INVALID_PTR;
213 }
214
nativeOpenUinputMouse(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys)215 static jlong nativeOpenUinputMouse(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
216 jint productId, jstring phys) {
217 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::MOUSE,
218 /* screenHeight= */ 0, /* screenWidth= */ 0);
219 return fd.ok() ? reinterpret_cast<jlong>(new VirtualMouse(std::move(fd))) : INVALID_PTR;
220 }
221
nativeOpenUinputTouchscreen(JNIEnv * env,jobject thiz,jstring name,jint vendorId,jint productId,jstring phys,jint height,jint width)222 static jlong nativeOpenUinputTouchscreen(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
223 jint productId, jstring phys, jint height, jint width) {
224 auto fd = openUinputJni(env, name, vendorId, productId, phys, DeviceType::TOUCHSCREEN, height,
225 width);
226 return fd.ok() ? reinterpret_cast<jlong>(new VirtualTouchscreen(std::move(fd))) : INVALID_PTR;
227 }
228
nativeCloseUinput(JNIEnv * env,jobject thiz,jlong ptr)229 static void nativeCloseUinput(JNIEnv* env, jobject thiz, jlong ptr) {
230 VirtualInputDevice* virtualInputDevice = reinterpret_cast<VirtualInputDevice*>(ptr);
231 delete virtualInputDevice;
232 }
233
234 // Native methods for VirtualDpad
nativeWriteDpadKeyEvent(JNIEnv * env,jobject thiz,jlong ptr,jint androidKeyCode,jint action,jlong eventTimeNanos)235 static bool nativeWriteDpadKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
236 jint action, jlong eventTimeNanos) {
237 VirtualDpad* virtualDpad = reinterpret_cast<VirtualDpad*>(ptr);
238 return virtualDpad->writeDpadKeyEvent(androidKeyCode, action,
239 std::chrono::nanoseconds(eventTimeNanos));
240 }
241
242 // Native methods for VirtualKeyboard
nativeWriteKeyEvent(JNIEnv * env,jobject thiz,jlong ptr,jint androidKeyCode,jint action,jlong eventTimeNanos)243 static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jlong ptr, jint androidKeyCode,
244 jint action, jlong eventTimeNanos) {
245 VirtualKeyboard* virtualKeyboard = reinterpret_cast<VirtualKeyboard*>(ptr);
246 return virtualKeyboard->writeKeyEvent(androidKeyCode, action,
247 std::chrono::nanoseconds(eventTimeNanos));
248 }
249
250 // Native methods for VirtualTouchscreen
nativeWriteTouchEvent(JNIEnv * env,jobject thiz,jlong ptr,jint pointerId,jint toolType,jint action,jfloat locationX,jfloat locationY,jfloat pressure,jfloat majorAxisSize,jlong eventTimeNanos)251 static bool nativeWriteTouchEvent(JNIEnv* env, jobject thiz, jlong ptr, jint pointerId,
252 jint toolType, jint action, jfloat locationX, jfloat locationY,
253 jfloat pressure, jfloat majorAxisSize, jlong eventTimeNanos) {
254 VirtualTouchscreen* virtualTouchscreen = reinterpret_cast<VirtualTouchscreen*>(ptr);
255 return virtualTouchscreen->writeTouchEvent(pointerId, toolType, action, locationX, locationY,
256 pressure, majorAxisSize,
257 std::chrono::nanoseconds(eventTimeNanos));
258 }
259
260 // Native methods for VirtualMouse
nativeWriteButtonEvent(JNIEnv * env,jobject thiz,jlong ptr,jint buttonCode,jint action,jlong eventTimeNanos)261 static bool nativeWriteButtonEvent(JNIEnv* env, jobject thiz, jlong ptr, jint buttonCode,
262 jint action, jlong eventTimeNanos) {
263 VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
264 return virtualMouse->writeButtonEvent(buttonCode, action,
265 std::chrono::nanoseconds(eventTimeNanos));
266 }
267
nativeWriteRelativeEvent(JNIEnv * env,jobject thiz,jlong ptr,jfloat relativeX,jfloat relativeY,jlong eventTimeNanos)268 static bool nativeWriteRelativeEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat relativeX,
269 jfloat relativeY, jlong eventTimeNanos) {
270 VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
271 return virtualMouse->writeRelativeEvent(relativeX, relativeY,
272 std::chrono::nanoseconds(eventTimeNanos));
273 }
274
nativeWriteScrollEvent(JNIEnv * env,jobject thiz,jlong ptr,jfloat xAxisMovement,jfloat yAxisMovement,jlong eventTimeNanos)275 static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jlong ptr, jfloat xAxisMovement,
276 jfloat yAxisMovement, jlong eventTimeNanos) {
277 VirtualMouse* virtualMouse = reinterpret_cast<VirtualMouse*>(ptr);
278 return virtualMouse->writeScrollEvent(xAxisMovement, yAxisMovement,
279 std::chrono::nanoseconds(eventTimeNanos));
280 }
281
282 static JNINativeMethod methods[] = {
283 {"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)J",
284 (void*)nativeOpenUinputDpad},
285 {"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)J",
286 (void*)nativeOpenUinputKeyboard},
287 {"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)J",
288 (void*)nativeOpenUinputMouse},
289 {"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)J",
290 (void*)nativeOpenUinputTouchscreen},
291 {"nativeCloseUinput", "(J)V", (void*)nativeCloseUinput},
292 {"nativeWriteDpadKeyEvent", "(JIIJ)Z", (void*)nativeWriteDpadKeyEvent},
293 {"nativeWriteKeyEvent", "(JIIJ)Z", (void*)nativeWriteKeyEvent},
294 {"nativeWriteButtonEvent", "(JIIJ)Z", (void*)nativeWriteButtonEvent},
295 {"nativeWriteTouchEvent", "(JIIIFFFFJ)Z", (void*)nativeWriteTouchEvent},
296 {"nativeWriteRelativeEvent", "(JFFJ)Z", (void*)nativeWriteRelativeEvent},
297 {"nativeWriteScrollEvent", "(JFFJ)Z", (void*)nativeWriteScrollEvent},
298 };
299
register_android_server_companion_virtual_InputController(JNIEnv * env)300 int register_android_server_companion_virtual_InputController(JNIEnv* env) {
301 return jniRegisterNativeMethods(env, "com/android/server/companion/virtual/InputController",
302 methods, NELEM(methods));
303 }
304
305 } // namespace android
306