1 /*
2  * Copyright (C) 2020 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 "UinputCommandDevice"
18 
19 #include "com_android_commands_uinput_Device.h"
20 
21 #include <android-base/stringprintf.h>
22 #include <android/looper.h>
23 #include <android_os_Parcel.h>
24 #include <fcntl.h>
25 #include <input/InputEventLabels.h>
26 #include <inttypes.h>
27 #include <jni.h>
28 #include <linux/uinput.h>
29 #include <log/log.h>
30 #include <nativehelper/JNIHelp.h>
31 #include <nativehelper/ScopedLocalRef.h>
32 #include <nativehelper/ScopedPrimitiveArray.h>
33 #include <nativehelper/ScopedUtfChars.h>
34 #include <time.h>
35 #include <unistd.h>
36 
37 #include <algorithm>
38 #include <array>
39 #include <cstdio>
40 #include <cstring>
41 #include <iterator>
42 #include <memory>
43 #include <vector>
44 
45 namespace android {
46 namespace uinput {
47 
48 using src::com::android::commands::uinput::InputAbsInfo;
49 
50 static constexpr const char* UINPUT_PATH = "/dev/uinput";
51 
52 static struct {
53     jmethodID onDeviceConfigure;
54     jmethodID onDeviceVibrating;
55     jmethodID onDeviceError;
56 } gDeviceCallbackClassInfo;
57 
checkAndClearException(JNIEnv * env,const char * methodName)58 static void checkAndClearException(JNIEnv* env, const char* methodName) {
59     if (env->ExceptionCheck()) {
60         ALOGE("An exception was thrown by callback '%s'.", methodName);
61         env->ExceptionClear();
62     }
63 }
64 
DeviceCallback(JNIEnv * env,jobject callback)65 DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback)
66       : mCallbackObject(env->NewGlobalRef(callback)) {
67     env->GetJavaVM(&mJavaVM);
68 }
69 
~DeviceCallback()70 DeviceCallback::~DeviceCallback() {
71     JNIEnv* env = getJNIEnv();
72     env->DeleteGlobalRef(mCallbackObject);
73 }
74 
onDeviceError()75 void DeviceCallback::onDeviceError() {
76     JNIEnv* env = getJNIEnv();
77     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
78     checkAndClearException(env, "onDeviceError");
79 }
80 
onDeviceConfigure(int handle)81 void DeviceCallback::onDeviceConfigure(int handle) {
82     JNIEnv* env = getJNIEnv();
83     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceConfigure, handle);
84     checkAndClearException(env, "onDeviceConfigure");
85 }
86 
onDeviceVibrating(int value)87 void DeviceCallback::onDeviceVibrating(int value) {
88     JNIEnv* env = getJNIEnv();
89     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceVibrating, value);
90     checkAndClearException(env, "onDeviceVibrating");
91 }
92 
getJNIEnv()93 JNIEnv* DeviceCallback::getJNIEnv() {
94     JNIEnv* env;
95     mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
96     return env;
97 }
98 
open(int32_t id,const char * name,int32_t vendorId,int32_t productId,int32_t versionId,uint16_t bus,uint32_t ffEffectsMax,const char * port,std::unique_ptr<DeviceCallback> callback)99 std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vendorId,
100                                                  int32_t productId, int32_t versionId, uint16_t bus,
101                                                  uint32_t ffEffectsMax, const char* port,
102                                                  std::unique_ptr<DeviceCallback> callback) {
103     android::base::unique_fd fd(::open(UINPUT_PATH, O_RDWR | O_NONBLOCK | O_CLOEXEC));
104     if (!fd.ok()) {
105         ALOGE("Failed to open uinput: %s", strerror(errno));
106         return nullptr;
107     }
108 
109     int32_t version;
110     ::ioctl(fd, UI_GET_VERSION, &version);
111     if (version < 5) {
112         ALOGE("Kernel version %d older than 5 is not supported", version);
113         return nullptr;
114     }
115 
116     struct uinput_setup setupDescriptor;
117     memset(&setupDescriptor, 0, sizeof(setupDescriptor));
118     strlcpy(setupDescriptor.name, name, UINPUT_MAX_NAME_SIZE);
119     setupDescriptor.id.version = 1;
120     setupDescriptor.id.bustype = bus;
121     setupDescriptor.id.vendor = vendorId;
122     setupDescriptor.id.product = productId;
123     setupDescriptor.id.version = versionId;
124     setupDescriptor.ff_effects_max = ffEffectsMax;
125 
126     // Request device configuration.
127     callback->onDeviceConfigure(fd.get());
128 
129     // register the input device
130     if (::ioctl(fd, UI_DEV_SETUP, &setupDescriptor)) {
131         ALOGE("UI_DEV_SETUP ioctl failed on fd %d: %s.", fd.get(), strerror(errno));
132         return nullptr;
133     }
134 
135     // set the physical port.
136     ::ioctl(fd, UI_SET_PHYS, port);
137 
138     if (::ioctl(fd, UI_DEV_CREATE) != 0) {
139         ALOGE("Unable to create uinput device: %s.", strerror(errno));
140         return nullptr;
141     }
142 
143     // using 'new' to access non-public constructor
144     return std::unique_ptr<UinputDevice>(new UinputDevice(id, std::move(fd), std::move(callback)));
145 }
146 
UinputDevice(int32_t id,android::base::unique_fd fd,std::unique_ptr<DeviceCallback> callback)147 UinputDevice::UinputDevice(int32_t id, android::base::unique_fd fd,
148                            std::unique_ptr<DeviceCallback> callback)
149       : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) {
150     ALooper* aLooper = ALooper_forThread();
151     if (aLooper == nullptr) {
152         ALOGE("Could not get ALooper, ALooper_forThread returned NULL");
153         aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
154     }
155     ALooper_addFd(
156             aLooper, mFd, 0, ALOOPER_EVENT_INPUT,
157             [](int, int events, void* data) {
158                 UinputDevice* d = reinterpret_cast<UinputDevice*>(data);
159                 return d->handleEvents(events);
160             },
161             reinterpret_cast<void*>(this));
162     ALOGI("uinput device %d created: version = %d, fd = %d", mId, UINPUT_VERSION, mFd.get());
163 }
164 
~UinputDevice()165 UinputDevice::~UinputDevice() {
166     ::ioctl(mFd, UI_DEV_DESTROY);
167 }
168 
injectEvent(std::chrono::microseconds timestamp,uint16_t type,uint16_t code,int32_t value)169 void UinputDevice::injectEvent(std::chrono::microseconds timestamp, uint16_t type, uint16_t code,
170                                int32_t value) {
171     struct input_event event = {};
172     event.type = type;
173     event.code = code;
174     event.value = value;
175     event.time.tv_sec = timestamp.count() / 1'000'000;
176     event.time.tv_usec = timestamp.count() % 1'000'000;
177 
178     if (::write(mFd, &event, sizeof(input_event)) < 0) {
179         ALOGE("Could not write event %" PRIu16 " %" PRIu16 " with value %" PRId32 " : %s", type,
180               code, value, strerror(errno));
181     }
182 }
183 
handleEvents(int events)184 int UinputDevice::handleEvents(int events) {
185     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
186         ALOGE("uinput node was closed or an error occurred. events=0x%x", events);
187         mDeviceCallback->onDeviceError();
188         return 0;
189     }
190     struct input_event ev;
191     ssize_t ret = ::read(mFd, &ev, sizeof(ev));
192     if (ret < 0) {
193         ALOGE("Failed to read from uinput node: %s", strerror(errno));
194         mDeviceCallback->onDeviceError();
195         return 0;
196     }
197 
198     switch (ev.type) {
199         case EV_UINPUT: {
200             if (ev.code == UI_FF_UPLOAD) {
201                 struct uinput_ff_upload ff_upload;
202                 ff_upload.request_id = ev.value;
203                 ::ioctl(mFd, UI_BEGIN_FF_UPLOAD, &ff_upload);
204                 ff_upload.retval = 0;
205                 ::ioctl(mFd, UI_END_FF_UPLOAD, &ff_upload);
206             } else if (ev.code == UI_FF_ERASE) {
207                 struct uinput_ff_erase ff_erase;
208                 ff_erase.request_id = ev.value;
209                 ::ioctl(mFd, UI_BEGIN_FF_ERASE, &ff_erase);
210                 ff_erase.retval = 0;
211                 ::ioctl(mFd, UI_END_FF_ERASE, &ff_erase);
212             }
213             break;
214         }
215         case EV_FF: {
216             ALOGI("EV_FF effect = %d value = %d", ev.code, ev.value);
217             mDeviceCallback->onDeviceVibrating(ev.value);
218             break;
219         }
220         default: {
221             ALOGI("Unhandled event type: %" PRIu32, ev.type);
222             break;
223         }
224     }
225 
226     return 1;
227 }
228 
229 } // namespace uinput
230 
toVector(JNIEnv * env,jintArray javaArray)231 std::vector<int32_t> toVector(JNIEnv* env, jintArray javaArray) {
232     std::vector<int32_t> data;
233     if (javaArray == nullptr) {
234         return data;
235     }
236 
237     ScopedIntArrayRO scopedArray(env, javaArray);
238     size_t size = scopedArray.size();
239     data.reserve(size);
240     for (size_t i = 0; i < size; i++) {
241         data.push_back(static_cast<int32_t>(scopedArray[i]));
242     }
243     return data;
244 }
245 
openUinputDevice(JNIEnv * env,jclass,jstring rawName,jint id,jint vendorId,jint productId,jint versionId,jint bus,jint ffEffectsMax,jstring rawPort,jobject callback)246 static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id,
247                               jint vendorId, jint productId, jint versionId, jint bus,
248                               jint ffEffectsMax, jstring rawPort, jobject callback) {
249     ScopedUtfChars name(env, rawName);
250     if (name.c_str() == nullptr) {
251         return 0;
252     }
253 
254     ScopedUtfChars port(env, rawPort);
255     std::unique_ptr<uinput::DeviceCallback> cb =
256             std::make_unique<uinput::DeviceCallback>(env, callback);
257 
258     std::unique_ptr<uinput::UinputDevice> d =
259             uinput::UinputDevice::open(id, name.c_str(), vendorId, productId, versionId, bus,
260                                        ffEffectsMax, port.c_str(), std::move(cb));
261     return reinterpret_cast<jlong>(d.release());
262 }
263 
closeUinputDevice(JNIEnv *,jclass,jlong ptr)264 static void closeUinputDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
265     uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr);
266     if (d != nullptr) {
267         delete d;
268     }
269 }
270 
injectEvent(JNIEnv *,jclass,jlong ptr,jlong timestampMicros,jint type,jint code,jint value)271 static void injectEvent(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jlong timestampMicros,
272                         jint type, jint code, jint value) {
273     uinput::UinputDevice* d = reinterpret_cast<uinput::UinputDevice*>(ptr);
274     if (d != nullptr) {
275         d->injectEvent(std::chrono::microseconds(timestampMicros), static_cast<uint16_t>(type),
276                        static_cast<uint16_t>(code), static_cast<int32_t>(value));
277     } else {
278         ALOGE("Could not inject event, Device* is null!");
279     }
280 }
281 
configure(JNIEnv * env,jclass,jint handle,jint code,jintArray rawConfigs)282 static void configure(JNIEnv* env, jclass /* clazz */, jint handle, jint code,
283                       jintArray rawConfigs) {
284     std::vector<int32_t> configs = toVector(env, rawConfigs);
285     // Configure uinput device, with user specified code and value.
286     for (auto& config : configs) {
287         if (::ioctl(static_cast<int>(handle), _IOW(UINPUT_IOCTL_BASE, code, int), config) < 0) {
288             ALOGE("Error configuring device (ioctl %d, value 0x%x): %s", code, config,
289                   strerror(errno));
290         }
291     }
292 }
293 
setAbsInfo(JNIEnv * env,jclass,jint handle,jint axisCode,jobject infoObj)294 static void setAbsInfo(JNIEnv* env, jclass /* clazz */, jint handle, jint axisCode,
295                        jobject infoObj) {
296     Parcel* parcel = parcelForJavaObject(env, infoObj);
297     uinput::InputAbsInfo info;
298 
299     info.readFromParcel(parcel);
300 
301     struct uinput_abs_setup absSetup;
302     absSetup.code = axisCode;
303     absSetup.absinfo.maximum = info.maximum;
304     absSetup.absinfo.minimum = info.minimum;
305     absSetup.absinfo.value = info.value;
306     absSetup.absinfo.fuzz = info.fuzz;
307     absSetup.absinfo.flat = info.flat;
308     absSetup.absinfo.resolution = info.resolution;
309 
310     ::ioctl(static_cast<int>(handle), UI_ABS_SETUP, &absSetup);
311 }
312 
getEvdevEventTypeByLabel(JNIEnv * env,jclass,jstring rawLabel)313 static jint getEvdevEventTypeByLabel(JNIEnv* env, jclass /* clazz */, jstring rawLabel) {
314     ScopedUtfChars label(env, rawLabel);
315     return InputEventLookup::getLinuxEvdevEventTypeByLabel(label.c_str()).value_or(-1);
316 }
317 
getEvdevEventCodeByLabel(JNIEnv * env,jclass,jint type,jstring rawLabel)318 static jint getEvdevEventCodeByLabel(JNIEnv* env, jclass /* clazz */, jint type, jstring rawLabel) {
319     ScopedUtfChars label(env, rawLabel);
320     return InputEventLookup::getLinuxEvdevEventCodeByLabel(type, label.c_str()).value_or(-1);
321 }
322 
getEvdevInputPropByLabel(JNIEnv * env,jclass,jstring rawLabel)323 static jint getEvdevInputPropByLabel(JNIEnv* env, jclass /* clazz */, jstring rawLabel) {
324     ScopedUtfChars label(env, rawLabel);
325     return InputEventLookup::getLinuxEvdevInputPropByLabel(label.c_str()).value_or(-1);
326 }
327 
328 static JNINativeMethod sMethods[] = {
329         {"nativeOpenUinputDevice",
330          "(Ljava/lang/String;IIIIIILjava/lang/String;"
331          "Lcom/android/commands/uinput/Device$DeviceCallback;)J",
332          reinterpret_cast<void*>(openUinputDevice)},
333         {"nativeInjectEvent", "(JJIII)V", reinterpret_cast<void*>(injectEvent)},
334         {"nativeConfigure", "(II[I)V", reinterpret_cast<void*>(configure)},
335         {"nativeSetAbsInfo", "(IILandroid/os/Parcel;)V", reinterpret_cast<void*>(setAbsInfo)},
336         {"nativeCloseUinputDevice", "(J)V", reinterpret_cast<void*>(closeUinputDevice)},
337         {"nativeGetEvdevEventTypeByLabel", "(Ljava/lang/String;)I",
338          reinterpret_cast<void*>(getEvdevEventTypeByLabel)},
339         {"nativeGetEvdevEventCodeByLabel", "(ILjava/lang/String;)I",
340          reinterpret_cast<void*>(getEvdevEventCodeByLabel)},
341         {"nativeGetEvdevInputPropByLabel", "(Ljava/lang/String;)I",
342          reinterpret_cast<void*>(getEvdevInputPropByLabel)},
343 };
344 
register_com_android_commands_uinput_Device(JNIEnv * env)345 int register_com_android_commands_uinput_Device(JNIEnv* env) {
346     jclass clazz = env->FindClass("com/android/commands/uinput/Device$DeviceCallback");
347     if (clazz == nullptr) {
348         ALOGE("Unable to find class 'DeviceCallback'");
349         return JNI_ERR;
350     }
351 
352     uinput::gDeviceCallbackClassInfo.onDeviceConfigure =
353             env->GetMethodID(clazz, "onDeviceConfigure", "(I)V");
354     uinput::gDeviceCallbackClassInfo.onDeviceVibrating =
355             env->GetMethodID(clazz, "onDeviceVibrating", "(I)V");
356     uinput::gDeviceCallbackClassInfo.onDeviceError =
357             env->GetMethodID(clazz, "onDeviceError", "()V");
358     if (uinput::gDeviceCallbackClassInfo.onDeviceConfigure == nullptr ||
359         uinput::gDeviceCallbackClassInfo.onDeviceError == nullptr ||
360         uinput::gDeviceCallbackClassInfo.onDeviceVibrating == nullptr) {
361         ALOGE("Unable to obtain onDeviceConfigure or onDeviceError or onDeviceVibrating methods");
362         return JNI_ERR;
363     }
364     return jniRegisterNativeMethods(env, "com/android/commands/uinput/Device", sMethods,
365                                     NELEM(sMethods));
366 }
367 
368 } // namespace android
369 
JNI_OnLoad(JavaVM * jvm,void *)370 jint JNI_OnLoad(JavaVM* jvm, void*) {
371     JNIEnv* env = nullptr;
372     if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
373         return JNI_ERR;
374     }
375 
376     if (android::register_com_android_commands_uinput_Device(env) < 0) {
377         return JNI_ERR;
378     }
379 
380     return JNI_VERSION_1_6;
381 }
382