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_TvKeys.h" 20 21 #include "jni.h" 22 #include <android_runtime/AndroidRuntime.h> 23 #include <ScopedUtfChars.h> 24 #include <android/keycodes.h> 25 26 #include <utils/BitSet.h> 27 #include <utils/Errors.h> 28 #include <utils/misc.h> 29 #include <utils/Log.h> 30 #include <utils/String8.h> 31 32 #include <ctype.h> 33 #include <linux/input.h> 34 #include <unistd.h> 35 #include <sys/time.h> 36 #include <time.h> 37 #include <stdint.h> 38 #include <map> 39 #include <fcntl.h> 40 #include <linux/uinput.h> 41 #include <signal.h> 42 #include <sys/inotify.h> 43 #include <sys/stat.h> 44 #include <sys/types.h> 45 46 // Refer to EventHub.h 47 #define MSC_ANDROID_TIME_SEC 0x6 48 #define MSC_ANDROID_TIME_USEC 0x7 49 50 #define SLOT_UNKNOWN -1 51 52 namespace android { 53 54 static std::map<int32_t,int> keysMap; 55 static std::map<int32_t,int32_t> slotsMap; 56 static BitSet32 mtSlots; 57 58 static void initKeysMap() { 59 if (keysMap.empty()) { 60 for (size_t i = 0; i < NELEM(KEYS); i++) { 61 keysMap[KEYS[i].androidKeyCode] = KEYS[i].linuxKeyCode; 62 } 63 } 64 } 65 66 static int32_t getLinuxKeyCode(int32_t androidKeyCode) { 67 std::map<int,int>::iterator it = keysMap.find(androidKeyCode); 68 if (it != keysMap.end()) { 69 return it->second; 70 } 71 return KEY_UNKNOWN; 72 } 73 74 static int findSlot(int32_t pointerId) { 75 std::map<int,int>::iterator it = slotsMap.find(pointerId); 76 if (it != slotsMap.end()) { 77 return it->second; 78 } 79 return SLOT_UNKNOWN; 80 } 81 82 static int assignSlot(int32_t pointerId) { 83 if (!mtSlots.isFull()) { 84 uint32_t slot = mtSlots.markFirstUnmarkedBit(); 85 slotsMap[pointerId] = slot; 86 return slot; 87 } 88 return SLOT_UNKNOWN; 89 } 90 91 static void unassignSlot(int32_t pointerId) { 92 int slot = findSlot(pointerId); 93 if (slot != SLOT_UNKNOWN) { 94 mtSlots.clearBit(slot); 95 slotsMap.erase(pointerId); 96 } 97 } 98 99 class NativeConnection { 100 public: 101 ~NativeConnection(); 102 103 static NativeConnection* open(const char* name, const char* uniqueId, 104 int32_t width, int32_t height, int32_t maxPointerId); 105 106 void sendEvent(int32_t type, int32_t code, int32_t value); 107 108 int32_t getMaxPointers() const { return mMaxPointers; } 109 110 private: 111 NativeConnection(int fd, int32_t maxPointers); 112 113 const int mFd; 114 const int32_t mMaxPointers; 115 }; 116 117 NativeConnection::NativeConnection(int fd, int32_t maxPointers) : 118 mFd(fd), mMaxPointers(maxPointers) { 119 } 120 121 NativeConnection::~NativeConnection() { 122 ALOGI("Un-Registering uinput device %d.", mFd); 123 ioctl(mFd, UI_DEV_DESTROY); 124 close(mFd); 125 } 126 127 NativeConnection* NativeConnection::open(const char* name, const char* uniqueId, 128 int32_t width, int32_t height, int32_t maxPointers) { 129 ALOGI("Registering uinput device %s: touch pad size %dx%d, " 130 "max pointers %d.", name, width, height, maxPointers); 131 132 int fd = ::open("/dev/uinput", O_WRONLY | O_NDELAY); 133 if (fd < 0) { 134 ALOGE("Cannot open /dev/uinput: %s.", strerror(errno)); 135 return nullptr; 136 } 137 138 struct uinput_user_dev uinp; 139 memset(&uinp, 0, sizeof(struct uinput_user_dev)); 140 strlcpy(uinp.name, name, UINPUT_MAX_NAME_SIZE); 141 uinp.id.version = 1; 142 uinp.id.bustype = BUS_VIRTUAL; 143 144 // initialize keymap 145 initKeysMap(); 146 147 // write device unique id to the phys property 148 ioctl(fd, UI_SET_PHYS, uniqueId); 149 150 // set the keys mapped 151 ioctl(fd, UI_SET_EVBIT, EV_KEY); 152 for (size_t i = 0; i < NELEM(KEYS); i++) { 153 ioctl(fd, UI_SET_KEYBIT, KEYS[i].linuxKeyCode); 154 } 155 156 // set the misc events maps 157 ioctl(fd, UI_SET_EVBIT, EV_MSC); 158 ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_SEC); 159 ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_USEC); 160 161 // register the input device 162 if (write(fd, &uinp, sizeof(uinp)) != sizeof(uinp)) { 163 ALOGE("Cannot write uinput_user_dev to fd %d: %s.", fd, strerror(errno)); 164 close(fd); 165 return NULL; 166 } 167 if (ioctl(fd, UI_DEV_CREATE) != 0) { 168 ALOGE("Unable to create uinput device: %s.", strerror(errno)); 169 close(fd); 170 return nullptr; 171 } 172 173 ALOGV("Created uinput device, fd=%d.", fd); 174 return new NativeConnection(fd, maxPointers); 175 } 176 177 void NativeConnection::sendEvent(int32_t type, int32_t code, int32_t value) { 178 struct input_event iev; 179 memset(&iev, 0, sizeof(iev)); 180 iev.type = type; 181 iev.code = code; 182 iev.value = value; 183 write(mFd, &iev, sizeof(iev)); 184 } 185 186 187 static jlong nativeOpen(JNIEnv* env, jclass clazz, 188 jstring nameStr, jstring uniqueIdStr, 189 jint width, jint height, jint maxPointers) { 190 ScopedUtfChars name(env, nameStr); 191 ScopedUtfChars uniqueId(env, uniqueIdStr); 192 193 NativeConnection* connection = NativeConnection::open(name.c_str(), uniqueId.c_str(), 194 width, height, maxPointers); 195 return reinterpret_cast<jlong>(connection); 196 } 197 198 static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) { 199 NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); 200 delete connection; 201 } 202 203 static void nativeSendTimestamp(JNIEnv* env, jclass clazz, jlong ptr, jlong timestamp) { 204 NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); 205 206 connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_SEC, timestamp / 1000L); 207 connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_USEC, (timestamp % 1000L) * 1000L); 208 } 209 210 static void nativeSendKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode, jboolean down) { 211 int32_t code = getLinuxKeyCode(keyCode); 212 NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); 213 if (code != KEY_UNKNOWN) { 214 connection->sendEvent(EV_KEY, code, down ? 1 : 0); 215 } else { 216 ALOGE("Received an unknown keycode of %d.", keyCode); 217 } 218 } 219 220 static void nativeSendPointerDown(JNIEnv* env, jclass clazz, jlong ptr, 221 jint pointerId, jint x, jint y) { 222 NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); 223 224 int32_t slot = findSlot(pointerId); 225 if (slot == SLOT_UNKNOWN) { 226 slot = assignSlot(pointerId); 227 } 228 if (slot != SLOT_UNKNOWN) { 229 connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot); 230 connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, pointerId); 231 connection->sendEvent(EV_ABS, ABS_MT_POSITION_X, x); 232 connection->sendEvent(EV_ABS, ABS_MT_POSITION_Y, y); 233 } 234 } 235 236 static void nativeSendPointerUp(JNIEnv* env, jclass clazz, jlong ptr, 237 jint pointerId) { 238 NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); 239 240 int32_t slot = findSlot(pointerId); 241 if (slot != SLOT_UNKNOWN) { 242 connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot); 243 connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1); 244 unassignSlot(pointerId); 245 } 246 } 247 248 static void nativeSendPointerSync(JNIEnv* env, jclass clazz, jlong ptr) { 249 NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); 250 connection->sendEvent(EV_SYN, SYN_REPORT, 0); 251 } 252 253 static void nativeClear(JNIEnv* env, jclass clazz, jlong ptr) { 254 NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr); 255 256 // Clear keys. 257 for (size_t i = 0; i < NELEM(KEYS); i++) { 258 connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0); 259 } 260 261 // Clear pointers. 262 int32_t slot = SLOT_UNKNOWN; 263 for (int32_t i = 0; i < connection->getMaxPointers(); i++) { 264 slot = findSlot(i); 265 if (slot != SLOT_UNKNOWN) { 266 connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot); 267 connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1); 268 } 269 } 270 271 // Sync pointer events 272 connection->sendEvent(EV_SYN, SYN_REPORT, 0); 273 } 274 275 /* 276 * JNI registration 277 */ 278 279 static JNINativeMethod gUinputBridgeMethods[] = { 280 { "nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J", 281 (void*)nativeOpen }, 282 { "nativeClose", "(J)V", 283 (void*)nativeClose }, 284 { "nativeSendTimestamp", "(JJ)V", 285 (void*)nativeSendTimestamp }, 286 { "nativeSendKey", "(JIZ)V", 287 (void*)nativeSendKey }, 288 { "nativeSendPointerDown", "(JIII)V", 289 (void*)nativeSendPointerDown }, 290 { "nativeSendPointerUp", "(JI)V", 291 (void*)nativeSendPointerUp }, 292 { "nativeClear", "(J)V", 293 (void*)nativeClear }, 294 { "nativeSendPointerSync", "(J)V", 295 (void*)nativeSendPointerSync }, 296 }; 297 298 int register_android_server_tv_TvUinputBridge(JNIEnv* env) { 299 int res = jniRegisterNativeMethods(env, "com/android/server/tv/UinputBridge", 300 gUinputBridgeMethods, NELEM(gUinputBridgeMethods)); 301 302 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 303 (void)res; // Don't complain about unused variable in the LOG_NDEBUG case 304 305 return 0; 306 } 307 308 } // namespace android 309