1 /*
2  * Copyright 2016, 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 "TvRemote-native-uiBridge"
18 
19 #include "com_android_server_tv_GamepadKeys.h"
20 #include "com_android_server_tv_TvKeys.h"
21 
22 #include "jni.h"
23 #include <android_runtime/AndroidRuntime.h>
24 #include <nativehelper/ScopedUtfChars.h>
25 #include <android/keycodes.h>
26 
27 #include <utils/BitSet.h>
28 #include <utils/Errors.h>
29 #include <utils/misc.h>
30 #include <utils/Log.h>
31 #include <utils/String8.h>
32 
33 #include <ctype.h>
34 #include <fcntl.h>
35 #include <linux/input.h>
36 #include <linux/uinput.h>
37 #include <signal.h>
38 #include <stdint.h>
39 #include <sys/inotify.h>
40 #include <sys/stat.h>
41 #include <sys/time.h>
42 #include <sys/types.h>
43 #include <time.h>
44 #include <unistd.h>
45 #include <unordered_map>
46 
47 #define SLOT_UNKNOWN -1
48 
49 namespace android {
50 
51 #define GOOGLE_VENDOR_ID 0x18d1
52 
53 #define GOOGLE_VIRTUAL_REMOTE_PRODUCT_ID 0x0100
54 #define GOOGLE_VIRTUAL_GAMEPAD_PROUCT_ID 0x0200
55 
56 static std::unordered_map<int32_t, int> keysMap;
57 static std::unordered_map<int32_t, int32_t> slotsMap;
58 static BitSet32 mtSlots;
59 
60 // Maps android key code to linux key code.
61 static std::unordered_map<int32_t, int> gamepadAndroidToLinuxKeyMap;
62 
63 // Maps an android gamepad axis to the index within the GAMEPAD_AXES array.
64 static std::unordered_map<int32_t, int> gamepadAndroidAxisToIndexMap;
65 
initKeysMap()66 static void initKeysMap() {
67     if (keysMap.empty()) {
68         for (size_t i = 0; i < NELEM(KEYS); i++) {
69             keysMap[KEYS[i].androidKeyCode] = KEYS[i].linuxKeyCode;
70         }
71     }
72 }
73 
initGamepadKeyMap()74 static void initGamepadKeyMap() {
75     if (gamepadAndroidToLinuxKeyMap.empty()) {
76         for (size_t i = 0; i < NELEM(GAMEPAD_KEYS); i++) {
77             gamepadAndroidToLinuxKeyMap[GAMEPAD_KEYS[i].androidKeyCode] =
78                     GAMEPAD_KEYS[i].linuxUinputKeyCode;
79         }
80     }
81 
82     if (gamepadAndroidAxisToIndexMap.empty()) {
83         for (size_t i = 0; i < NELEM(GAMEPAD_AXES); i++) {
84             gamepadAndroidAxisToIndexMap[GAMEPAD_AXES[i].androidAxis] = i;
85         }
86     }
87 }
88 
getLinuxKeyCode(int32_t androidKeyCode)89 static int32_t getLinuxKeyCode(int32_t androidKeyCode) {
90     std::unordered_map<int, int>::iterator it = keysMap.find(androidKeyCode);
91     if (it != keysMap.end()) {
92         return it->second;
93     }
94     return KEY_UNKNOWN;
95 }
96 
getGamepadkeyCode(int32_t androidKeyCode)97 static int getGamepadkeyCode(int32_t androidKeyCode) {
98     std::unordered_map<int32_t, int>::iterator it =
99             gamepadAndroidToLinuxKeyMap.find(androidKeyCode);
100     if (it != gamepadAndroidToLinuxKeyMap.end()) {
101         return it->second;
102     }
103     return KEY_UNKNOWN;
104 }
105 
getGamepadAxis(int32_t androidAxisCode)106 static const GamepadAxis* getGamepadAxis(int32_t androidAxisCode) {
107     std::unordered_map<int32_t, int>::iterator it =
108             gamepadAndroidAxisToIndexMap.find(androidAxisCode);
109     if (it == gamepadAndroidAxisToIndexMap.end()) {
110         return nullptr;
111     }
112     return &GAMEPAD_AXES[it->second];
113 }
114 
findSlot(int32_t pointerId)115 static int findSlot(int32_t pointerId) {
116     std::unordered_map<int, int>::iterator it = slotsMap.find(pointerId);
117     if (it != slotsMap.end()) {
118         return it->second;
119     }
120     return SLOT_UNKNOWN;
121 }
122 
assignSlot(int32_t pointerId)123 static int assignSlot(int32_t pointerId) {
124     if (!mtSlots.isFull()) {
125         uint32_t slot = mtSlots.markFirstUnmarkedBit();
126         slotsMap[pointerId] = slot;
127         return slot;
128     }
129     return SLOT_UNKNOWN;
130 }
131 
unassignSlot(int32_t pointerId)132 static void unassignSlot(int32_t pointerId) {
133     int slot = findSlot(pointerId);
134     if (slot != SLOT_UNKNOWN) {
135         mtSlots.clearBit(slot);
136         slotsMap.erase(pointerId);
137     }
138 }
139 
140 static const int kInvalidFileDescriptor = -1;
141 
142 // Convenience class to manage an opened /dev/uinput device
143 class UInputDescriptor {
144 public:
UInputDescriptor()145     UInputDescriptor() : mFd(kInvalidFileDescriptor) {
146         memset(&mUinputDescriptor, 0, sizeof(mUinputDescriptor));
147     }
148 
149     // Auto-closes any open /dev/uinput descriptor unless detached.
150     ~UInputDescriptor();
151 
152     // Open /dev/uinput and prepare to register
153     // the device with the given name and unique Id
154     bool Open(const char* name, const char* uniqueId, uint16_t product);
155 
156     // Checks if the current file descriptor is valid
IsValid() const157     bool IsValid() const { return mFd != kInvalidFileDescriptor; }
158 
159     void EnableKey(int keyCode);
160 
161     void EnableAxesEvents();
162     void EnableAxis(int axis, int rangeMin, int rangeMax);
163 
164     bool Create();
165 
166     // Detaches from the current file descriptor
167     // Returns the file descriptor for /dev/uniput
168     int Detach();
169 
170 private:
171     int mFd;
172     struct uinput_user_dev mUinputDescriptor;
173 };
174 
~UInputDescriptor()175 UInputDescriptor::~UInputDescriptor() {
176     if (mFd != kInvalidFileDescriptor) {
177         close(mFd);
178         mFd = kInvalidFileDescriptor;
179     }
180 }
181 
Detach()182 int UInputDescriptor::Detach() {
183     int fd = mFd;
184     mFd = kInvalidFileDescriptor;
185     return fd;
186 }
187 
Open(const char * name,const char * uniqueId,uint16_t product)188 bool UInputDescriptor::Open(const char* name, const char* uniqueId, uint16_t product) {
189     if (IsValid()) {
190         ALOGE("UInput device already open");
191         return false;
192     }
193 
194     mFd = ::open("/dev/uinput", O_WRONLY | O_NDELAY);
195     if (mFd < 0) {
196         ALOGE("Cannot open /dev/uinput: %s.", strerror(errno));
197         mFd = kInvalidFileDescriptor;
198         return false;
199     }
200 
201     // write device unique id to the phys property
202     ioctl(mFd, UI_SET_PHYS, uniqueId);
203 
204     memset(&mUinputDescriptor, 0, sizeof(mUinputDescriptor));
205     strlcpy(mUinputDescriptor.name, name, UINPUT_MAX_NAME_SIZE);
206     mUinputDescriptor.id.version = 1;
207     mUinputDescriptor.id.bustype = BUS_VIRTUAL;
208     mUinputDescriptor.id.vendor = GOOGLE_VENDOR_ID;
209     mUinputDescriptor.id.product = product;
210 
211     // All UInput devices we use process keys
212     ioctl(mFd, UI_SET_EVBIT, EV_KEY);
213 
214     return true;
215 }
216 
EnableKey(int keyCode)217 void UInputDescriptor::EnableKey(int keyCode) {
218     ioctl(mFd, UI_SET_KEYBIT, keyCode);
219 }
220 
EnableAxesEvents()221 void UInputDescriptor::EnableAxesEvents() {
222     ioctl(mFd, UI_SET_EVBIT, EV_ABS);
223 }
224 
EnableAxis(int axis,int rangeMin,int rangeMax)225 void UInputDescriptor::EnableAxis(int axis, int rangeMin, int rangeMax) {
226     if ((axis < 0) || (axis >= NELEM(mUinputDescriptor.absmin))) {
227         ALOGE("Invalid axis number: %d", axis);
228         return;
229     }
230 
231     if (ioctl(mFd, UI_SET_ABSBIT, axis) != 0) {
232         ALOGE("Failed to set absbit for %d", axis);
233     }
234 
235     mUinputDescriptor.absmin[axis] = rangeMin;
236     mUinputDescriptor.absmax[axis] = rangeMax;
237     mUinputDescriptor.absfuzz[axis] = 0;
238     mUinputDescriptor.absflat[axis] = 0;
239 }
240 
Create()241 bool UInputDescriptor::Create() {
242     // register the input device
243     if (write(mFd, &mUinputDescriptor, sizeof(mUinputDescriptor)) != sizeof(mUinputDescriptor)) {
244         ALOGE("Cannot write uinput_user_dev to fd %d: %s.", mFd, strerror(errno));
245         return false;
246     }
247 
248     if (ioctl(mFd, UI_DEV_CREATE) != 0) {
249         ALOGE("Unable to create uinput device: %s.", strerror(errno));
250         return false;
251     }
252 
253     ALOGV("Created uinput device, fd=%d.", mFd);
254 
255     return true;
256 }
257 
258 class NativeConnection {
259 public:
260     enum class ConnectionType {
261         kRemoteDevice,
262         kGamepadDevice,
263     };
264 
265     ~NativeConnection();
266 
267     static NativeConnection* open(const char* name, const char* uniqueId,
268             int32_t width, int32_t height, int32_t maxPointerId);
269 
270     static NativeConnection* openGamepad(const char* name, const char* uniqueId);
271 
272     void sendEvent(int32_t type, int32_t code, int32_t value);
273 
getMaxPointers() const274     int32_t getMaxPointers() const { return mMaxPointers; }
275 
getType() const276     ConnectionType getType() const { return mType; }
277 
IsGamepad() const278     bool IsGamepad() const { return getType() == ConnectionType::kGamepadDevice; }
279 
IsRemote() const280     bool IsRemote() const { return getType() == ConnectionType::kRemoteDevice; }
281 
282 private:
283     NativeConnection(int fd, int32_t maxPointers, ConnectionType type);
284 
285     const int mFd;
286     const int32_t mMaxPointers;
287     const ConnectionType mType;
288 };
289 
NativeConnection(int fd,int32_t maxPointers,ConnectionType type)290 NativeConnection::NativeConnection(int fd, int32_t maxPointers, ConnectionType type)
291       : mFd(fd), mMaxPointers(maxPointers), mType(type) {}
292 
~NativeConnection()293 NativeConnection::~NativeConnection() {
294     ALOGI("Un-Registering uinput device %d.", mFd);
295     ioctl(mFd, UI_DEV_DESTROY);
296     close(mFd);
297 }
298 
open(const char * name,const char * uniqueId,int32_t width,int32_t height,int32_t maxPointers)299 NativeConnection* NativeConnection::open(const char* name, const char* uniqueId,
300         int32_t width, int32_t height, int32_t maxPointers) {
301     ALOGI("Registering uinput device %s: touch pad size %dx%d, "
302             "max pointers %d.", name, width, height, maxPointers);
303 
304     initKeysMap();
305 
306     UInputDescriptor descriptor;
307     if (!descriptor.Open(name, uniqueId, GOOGLE_VIRTUAL_REMOTE_PRODUCT_ID)) {
308         return nullptr;
309     }
310 
311     // set the keys mapped
312     for (size_t i = 0; i < NELEM(KEYS); i++) {
313         descriptor.EnableKey(KEYS[i].linuxKeyCode);
314     }
315 
316     if (!descriptor.Create()) {
317         return nullptr;
318     }
319 
320     return new NativeConnection(descriptor.Detach(), maxPointers, ConnectionType::kRemoteDevice);
321 }
322 
openGamepad(const char * name,const char * uniqueId)323 NativeConnection* NativeConnection::openGamepad(const char* name, const char* uniqueId) {
324     ALOGI("Registering uinput device %s: gamepad", name);
325 
326     initGamepadKeyMap();
327 
328     UInputDescriptor descriptor;
329     if (!descriptor.Open(name, uniqueId, GOOGLE_VIRTUAL_GAMEPAD_PROUCT_ID)) {
330         return nullptr;
331     }
332 
333     // set the keys mapped for gamepads
334     for (size_t i = 0; i < NELEM(GAMEPAD_KEYS); i++) {
335         descriptor.EnableKey(GAMEPAD_KEYS[i].linuxUinputKeyCode);
336     }
337 
338     // define the axes that are required
339     descriptor.EnableAxesEvents();
340     for (size_t i = 0; i < NELEM(GAMEPAD_AXES); i++) {
341         const GamepadAxis& axis = GAMEPAD_AXES[i];
342         descriptor.EnableAxis(axis.linuxUinputAxis, axis.linuxUinputRangeMin,
343                               axis.linuxUinputRangeMax);
344     }
345 
346     if (!descriptor.Create()) {
347         return nullptr;
348     }
349 
350     return new NativeConnection(descriptor.Detach(), 0, ConnectionType::kGamepadDevice);
351 }
352 
sendEvent(int32_t type,int32_t code,int32_t value)353 void NativeConnection::sendEvent(int32_t type, int32_t code, int32_t value) {
354     struct input_event iev;
355     memset(&iev, 0, sizeof(iev));
356     iev.type = type;
357     iev.code = code;
358     iev.value = value;
359     write(mFd, &iev, sizeof(iev));
360 }
361 
nativeOpen(JNIEnv * env,jclass clazz,jstring nameStr,jstring uniqueIdStr,jint width,jint height,jint maxPointers)362 static jlong nativeOpen(JNIEnv* env, jclass clazz,
363         jstring nameStr, jstring uniqueIdStr,
364         jint width, jint height, jint maxPointers) {
365     ScopedUtfChars name(env, nameStr);
366     ScopedUtfChars uniqueId(env, uniqueIdStr);
367 
368     NativeConnection* connection = NativeConnection::open(name.c_str(), uniqueId.c_str(),
369             width, height, maxPointers);
370     return reinterpret_cast<jlong>(connection);
371 }
372 
nativeGamepadOpen(JNIEnv * env,jclass clazz,jstring nameStr,jstring uniqueIdStr)373 static jlong nativeGamepadOpen(JNIEnv* env, jclass clazz, jstring nameStr, jstring uniqueIdStr) {
374     ScopedUtfChars name(env, nameStr);
375     ScopedUtfChars uniqueId(env, uniqueIdStr);
376 
377     NativeConnection* connection = NativeConnection::openGamepad(name.c_str(), uniqueId.c_str());
378     return reinterpret_cast<jlong>(connection);
379 }
380 
nativeClose(JNIEnv * env,jclass clazz,jlong ptr)381 static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
382     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
383     delete connection;
384 }
385 
nativeSendKey(JNIEnv * env,jclass clazz,jlong ptr,jint keyCode,jboolean down)386 static void nativeSendKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode, jboolean down) {
387     int32_t code = getLinuxKeyCode(keyCode);
388     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
389 
390     if (connection->IsGamepad()) {
391         ALOGE("Invalid key even for a gamepad - need to send gamepad events");
392         return;
393     }
394 
395     if (code != KEY_UNKNOWN) {
396         connection->sendEvent(EV_KEY, code, down ? 1 : 0);
397     } else {
398         ALOGE("Received an unknown keycode of %d.", keyCode);
399     }
400 }
401 
nativeSendGamepadKey(JNIEnv * env,jclass clazz,jlong ptr,jint keyCode,jboolean down)402 static void nativeSendGamepadKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode,
403                                  jboolean down) {
404     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
405 
406     if (!connection->IsGamepad()) {
407         ALOGE("Invalid gamepad key for non-gamepad device");
408         return;
409     }
410 
411     int linuxKeyCode = getGamepadkeyCode(keyCode);
412     if (linuxKeyCode == KEY_UNKNOWN) {
413         ALOGE("Gamepad: received an unknown keycode of %d.", keyCode);
414         return;
415     }
416     connection->sendEvent(EV_KEY, linuxKeyCode, down ? 1 : 0);
417 }
418 
nativeSendGamepadAxisValue(JNIEnv * env,jclass clazz,jlong ptr,jint axis,jfloat value)419 static void nativeSendGamepadAxisValue(JNIEnv* env, jclass clazz, jlong ptr, jint axis,
420                                        jfloat value) {
421     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
422 
423     if (!connection->IsGamepad()) {
424         ALOGE("Invalid axis send for non-gamepad device");
425         return;
426     }
427 
428     const GamepadAxis* axisInfo = getGamepadAxis(axis);
429     if (axisInfo == nullptr) {
430         ALOGE("Invalid axis: %d", axis);
431         return;
432     }
433 
434     if (value > axisInfo->androidRangeMax) {
435         value = axisInfo->androidRangeMax;
436     } else if (value < axisInfo->androidRangeMin) {
437         value = axisInfo->androidRangeMin;
438     }
439 
440     // Converts the android range into the device range
441     float movementPercent = (value - axisInfo->androidRangeMin) /
442             (axisInfo->androidRangeMax - axisInfo->androidRangeMin);
443     int axisRawValue = axisInfo->linuxUinputRangeMin +
444             movementPercent * (axisInfo->linuxUinputRangeMax - axisInfo->linuxUinputRangeMin);
445 
446     connection->sendEvent(EV_ABS, axisInfo->linuxUinputAxis, axisRawValue);
447 }
448 
nativeSendPointerDown(JNIEnv * env,jclass clazz,jlong ptr,jint pointerId,jint x,jint y)449 static void nativeSendPointerDown(JNIEnv* env, jclass clazz, jlong ptr,
450         jint pointerId, jint x, jint y) {
451     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
452 
453     if (connection->IsGamepad()) {
454         ALOGE("Invalid pointer down event for a gamepad.");
455         return;
456     }
457 
458     int32_t slot = findSlot(pointerId);
459     if (slot == SLOT_UNKNOWN) {
460         slot = assignSlot(pointerId);
461     }
462     if (slot != SLOT_UNKNOWN) {
463         connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
464         connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, pointerId);
465         connection->sendEvent(EV_ABS, ABS_MT_POSITION_X, x);
466         connection->sendEvent(EV_ABS, ABS_MT_POSITION_Y, y);
467     }
468 }
469 
nativeSendPointerUp(JNIEnv * env,jclass clazz,jlong ptr,jint pointerId)470 static void nativeSendPointerUp(JNIEnv* env, jclass clazz, jlong ptr,
471         jint pointerId) {
472     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
473 
474     if (connection->IsGamepad()) {
475         ALOGE("Invalid pointer up event for a gamepad.");
476         return;
477     }
478 
479     int32_t slot = findSlot(pointerId);
480     if (slot != SLOT_UNKNOWN) {
481         connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
482         connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
483         unassignSlot(pointerId);
484     }
485 }
486 
nativeSendPointerSync(JNIEnv * env,jclass clazz,jlong ptr)487 static void nativeSendPointerSync(JNIEnv* env, jclass clazz, jlong ptr) {
488     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
489     connection->sendEvent(EV_SYN, SYN_REPORT, 0);
490 }
491 
nativeClear(JNIEnv * env,jclass clazz,jlong ptr)492 static void nativeClear(JNIEnv* env, jclass clazz, jlong ptr) {
493     NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
494 
495     // Clear keys.
496     if (connection->IsRemote()) {
497         for (size_t i = 0; i < NELEM(KEYS); i++) {
498             connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0);
499         }
500 
501         // Clear pointers.
502         int32_t slot = SLOT_UNKNOWN;
503         for (int32_t i = 0; i < connection->getMaxPointers(); i++) {
504             slot = findSlot(i);
505             if (slot != SLOT_UNKNOWN) {
506                 connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
507                 connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
508             }
509         }
510     } else {
511         for (size_t i = 0; i < NELEM(GAMEPAD_KEYS); i++) {
512             connection->sendEvent(EV_KEY, GAMEPAD_KEYS[i].linuxUinputKeyCode, 0);
513         }
514 
515         for (size_t i = 0; i < NELEM(GAMEPAD_AXES); i++) {
516             const GamepadAxis& axis = GAMEPAD_AXES[i];
517 
518             if ((axis.linuxUinputAxis == ABS_Z) || (axis.linuxUinputAxis == ABS_RZ)) {
519                 // Mark triggers unpressed
520                 connection->sendEvent(EV_ABS, axis.linuxUinputAxis, axis.linuxUinputRangeMin);
521             } else {
522                 // Joysticks and dpad rests on center
523                 connection->sendEvent(EV_ABS, axis.linuxUinputAxis,
524                                       (axis.linuxUinputRangeMin + axis.linuxUinputRangeMax) / 2);
525             }
526         }
527     }
528 
529     // Sync pointer events
530     connection->sendEvent(EV_SYN, SYN_REPORT, 0);
531 }
532 
533 /*
534  * JNI registration
535  */
536 
537 static JNINativeMethod gUinputBridgeMethods[] = {
538         {"nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J", (void*)nativeOpen},
539         {"nativeGamepadOpen", "(Ljava/lang/String;Ljava/lang/String;)J", (void*)nativeGamepadOpen},
540         {"nativeClose", "(J)V", (void*)nativeClose},
541         {"nativeSendKey", "(JIZ)V", (void*)nativeSendKey},
542         {"nativeSendPointerDown", "(JIII)V", (void*)nativeSendPointerDown},
543         {"nativeSendPointerUp", "(JI)V", (void*)nativeSendPointerUp},
544         {"nativeClear", "(J)V", (void*)nativeClear},
545         {"nativeSendPointerSync", "(J)V", (void*)nativeSendPointerSync},
546         {"nativeSendGamepadKey", "(JIZ)V", (void*)nativeSendGamepadKey},
547         {"nativeSendGamepadAxisValue", "(JIF)V", (void*)nativeSendGamepadAxisValue},
548 };
549 
register_android_server_tv_TvUinputBridge(JNIEnv * env)550 int register_android_server_tv_TvUinputBridge(JNIEnv* env) {
551     int res = jniRegisterNativeMethods(env, "com/android/server/tv/UinputBridge",
552               gUinputBridgeMethods, NELEM(gUinputBridgeMethods));
553 
554     LOG_FATAL_IF(res < 0, "Unable to register native methods.");
555     (void)res; // Don't complain about unused variable in the LOG_NDEBUG case
556 
557     return 0;
558 }
559 
560 } // namespace android
561