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