blob: b3e287bae76a817fa0e8080691d7c0041451e0b5 [file] [log] [blame]
Michael Wright1f2c7682015-06-03 13:46:48 +01001/*
2 * Copyright (C) 2015 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 "HidCommandDevice"
18
19#include "com_android_commands_hid_Device.h"
20
21#include <linux/uhid.h>
22
23#include <fcntl.h>
24#include <cstdio>
25#include <cstring>
26#include <memory>
27#include <unistd.h>
28
Michael Wright1f2c7682015-06-03 13:46:48 +010029#include <jni.h>
Steven Morelandc95dca82017-08-01 10:18:40 -070030#include <nativehelper/JNIHelp.h>
31#include <nativehelper/ScopedPrimitiveArray.h>
Steven Moreland65e2ca22017-08-10 15:55:12 -070032#include <nativehelper/ScopedUtfChars.h>
Siarhei Vishniakou55656e42017-03-31 17:23:39 -070033#include <android/looper.h>
34#include <android/log.h>
35
36#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
37#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
38#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
39#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
Michael Wright1f2c7682015-06-03 13:46:48 +010040
41namespace android {
42namespace uhid {
43
44static const char* UHID_PATH = "/dev/uhid";
Michael Wright1f2c7682015-06-03 13:46:48 +010045
46static struct {
47 jmethodID onDeviceOpen;
48 jmethodID onDeviceError;
49} gDeviceCallbackClassInfo;
50
Aurimas Liutikas1c8cbb52016-02-19 13:44:25 -080051static int handleLooperEvents(int /* fd */, int events, void* data) {
Michael Wright1f2c7682015-06-03 13:46:48 +010052 Device* d = reinterpret_cast<Device*>(data);
53 return d->handleEvents(events);
54}
55
56static void checkAndClearException(JNIEnv* env, const char* methodName) {
57 if (env->ExceptionCheck()) {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -070058 LOGE("An exception was thrown by callback '%s'.", methodName);
Michael Wright1f2c7682015-06-03 13:46:48 +010059 env->ExceptionClear();
60 }
61}
62
63DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
Siarhei Vishniakou55656e42017-03-31 17:23:39 -070064 mCallbackObject(env->NewGlobalRef(callback)) {
65 env->GetJavaVM(&mJavaVM);
66 }
Michael Wright1f2c7682015-06-03 13:46:48 +010067
68DeviceCallback::~DeviceCallback() {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -070069 JNIEnv* env = getJNIEnv();
Michael Wright1f2c7682015-06-03 13:46:48 +010070 env->DeleteGlobalRef(mCallbackObject);
71}
72
73void DeviceCallback::onDeviceError() {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -070074 JNIEnv* env = getJNIEnv();
Michael Wright1f2c7682015-06-03 13:46:48 +010075 env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
76 checkAndClearException(env, "onDeviceError");
77}
78
79void DeviceCallback::onDeviceOpen() {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -070080 JNIEnv* env = getJNIEnv();
Michael Wright1f2c7682015-06-03 13:46:48 +010081 env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen);
82 checkAndClearException(env, "onDeviceOpen");
83}
84
Siarhei Vishniakou55656e42017-03-31 17:23:39 -070085JNIEnv* DeviceCallback::getJNIEnv() {
86 JNIEnv* env;
87 mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
88 return env;
89}
90
Michael Wright1f2c7682015-06-03 13:46:48 +010091Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +010092 std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback) {
93
94 size_t size = descriptor.size();
95 if (size > HID_MAX_DESCRIPTOR_SIZE) {
96 LOGE("Received invalid hid report with descriptor size %zu, skipping", size);
97 return nullptr;
98 }
Michael Wright1f2c7682015-06-03 13:46:48 +010099
100 int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
101 if (fd < 0) {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700102 LOGE("Failed to open uhid: %s", strerror(errno));
Michael Wright1f2c7682015-06-03 13:46:48 +0100103 return nullptr;
104 }
105
106 struct uhid_event ev;
107 memset(&ev, 0, sizeof(ev));
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700108 ev.type = UHID_CREATE2;
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100109 strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
110 memcpy(&ev.u.create2.rd_data, descriptor.data(),
111 size * sizeof(ev.u.create2.rd_data[0]));
112 ev.u.create2.rd_size = size;
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700113 ev.u.create2.bus = BUS_BLUETOOTH;
114 ev.u.create2.vendor = vid;
115 ev.u.create2.product = pid;
116 ev.u.create2.version = 0;
117 ev.u.create2.country = 0;
Michael Wright1f2c7682015-06-03 13:46:48 +0100118
119 errno = 0;
120 ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
121 if (ret < 0 || ret != sizeof(ev)) {
122 ::close(fd);
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700123 LOGE("Failed to create uhid node: %s", strerror(errno));
Michael Wright1f2c7682015-06-03 13:46:48 +0100124 return nullptr;
125 }
126
127 // Wait for the device to actually be created.
128 ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
129 if (ret < 0 || ev.type != UHID_START) {
130 ::close(fd);
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700131 LOGE("uhid node failed to start: %s", strerror(errno));
Michael Wright1f2c7682015-06-03 13:46:48 +0100132 return nullptr;
133 }
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700134 return new Device(id, fd, std::move(callback));
Michael Wright1f2c7682015-06-03 13:46:48 +0100135}
136
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700137Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback) :
138 mId(id), mFd(fd), mDeviceCallback(std::move(callback)) {
139 ALooper* aLooper = ALooper_forThread();
140 if (aLooper == NULL) {
141 LOGE("Could not get ALooper, ALooper_forThread returned NULL");
142 aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
143 }
144 ALooper_addFd(aLooper, fd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
145 reinterpret_cast<void*>(this));
Michael Wright1f2c7682015-06-03 13:46:48 +0100146}
147
148Device::~Device() {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700149 ALooper* looper = ALooper_forThread();
150 if (looper != NULL) {
151 ALooper_removeFd(looper, mFd);
152 } else {
153 LOGE("Could not remove fd, ALooper_forThread() returned NULL!");
154 }
Michael Wright1f2c7682015-06-03 13:46:48 +0100155 struct uhid_event ev;
156 memset(&ev, 0, sizeof(ev));
157 ev.type = UHID_DESTROY;
158 TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
159 ::close(mFd);
160 mFd = -1;
161}
162
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100163void Device::sendReport(const std::vector<uint8_t>& report) const {
164 if (report.size() > UHID_DATA_MAX) {
165 LOGE("Received invalid report of size %zu, skipping", report.size());
166 return;
167 }
168
Michael Wright1f2c7682015-06-03 13:46:48 +0100169 struct uhid_event ev;
170 memset(&ev, 0, sizeof(ev));
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700171 ev.type = UHID_INPUT2;
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100172 ev.u.input2.size = report.size();
173 memcpy(&ev.u.input2.data, report.data(), report.size() * sizeof(ev.u.input2.data[0]));
Michael Wright1f2c7682015-06-03 13:46:48 +0100174 ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
175 if (ret < 0 || ret != sizeof(ev)) {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700176 LOGE("Failed to send hid event: %s", strerror(errno));
Michael Wright1f2c7682015-06-03 13:46:48 +0100177 }
178}
179
180int Device::handleEvents(int events) {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700181 if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
182 LOGE("uhid node was closed or an error occurred. events=0x%x", events);
Michael Wright1f2c7682015-06-03 13:46:48 +0100183 mDeviceCallback->onDeviceError();
184 return 0;
185 }
186 struct uhid_event ev;
187 ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev)));
188 if (ret < 0) {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700189 LOGE("Failed to read from uhid node: %s", strerror(errno));
Michael Wright1f2c7682015-06-03 13:46:48 +0100190 mDeviceCallback->onDeviceError();
191 return 0;
192 }
193
194 if (ev.type == UHID_OPEN) {
195 mDeviceCallback->onDeviceOpen();
196 }
197
198 return 1;
199}
200
201} // namespace uhid
202
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100203std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) {
Michael Wright1f2c7682015-06-03 13:46:48 +0100204 ScopedByteArrayRO scopedArray(env, javaArray);
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100205 size_t size = scopedArray.size();
206 std::vector<uint8_t> data;
207 data.reserve(size);
208 for (size_t i = 0; i < size; i++) {
209 data.push_back(static_cast<uint8_t>(scopedArray[i]));
Michael Wright1f2c7682015-06-03 13:46:48 +0100210 }
211 return data;
212}
213
Aurimas Liutikas1c8cbb52016-02-19 13:44:25 -0800214static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700215 jbyteArray rawDescriptor, jobject callback) {
Michael Wright1f2c7682015-06-03 13:46:48 +0100216 ScopedUtfChars name(env, rawName);
217 if (name.c_str() == nullptr) {
218 return 0;
219 }
220
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100221 std::vector<uint8_t> desc = getData(env, rawDescriptor);
Michael Wright1f2c7682015-06-03 13:46:48 +0100222
223 std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
Michael Wright1f2c7682015-06-03 13:46:48 +0100224
225 uhid::Device* d = uhid::Device::open(
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100226 id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc, std::move(cb));
Michael Wright1f2c7682015-06-03 13:46:48 +0100227 return reinterpret_cast<jlong>(d);
228}
229
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700230static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100231 std::vector<uint8_t> report = getData(env, rawReport);
Michael Wright1f2c7682015-06-03 13:46:48 +0100232 uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
233 if (d) {
Siarhei Vishniakou6c6dd652018-07-16 17:01:40 +0100234 d->sendReport(report);
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700235 } else {
236 LOGE("Could not send report, Device* is null!");
Michael Wright1f2c7682015-06-03 13:46:48 +0100237 }
238}
239
Aurimas Liutikas1c8cbb52016-02-19 13:44:25 -0800240static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
Michael Wright1f2c7682015-06-03 13:46:48 +0100241 uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
242 if (d) {
243 delete d;
244 }
245}
246
247static JNINativeMethod sMethods[] = {
248 { "nativeOpenDevice",
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700249 "(Ljava/lang/String;III[B"
Michael Wright1f2c7682015-06-03 13:46:48 +0100250 "Lcom/android/commands/hid/Device$DeviceCallback;)J",
251 reinterpret_cast<void*>(openDevice) },
252 { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
253 { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) },
254};
255
256int register_com_android_commands_hid_Device(JNIEnv* env) {
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700257 jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback");
258 if (clazz == NULL) {
259 LOGE("Unable to find class 'DeviceCallback'");
260 return JNI_ERR;
261 }
Michael Wright1f2c7682015-06-03 13:46:48 +0100262 uhid::gDeviceCallbackClassInfo.onDeviceOpen =
Siarhei Vishniakou55656e42017-03-31 17:23:39 -0700263 env->GetMethodID(clazz, "onDeviceOpen", "()V");
264 uhid::gDeviceCallbackClassInfo.onDeviceError =
265 env->GetMethodID(clazz, "onDeviceError", "()V");
266 if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL ||
267 uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) {
268 LOGE("Unable to obtain onDeviceOpen or onDeviceError methods");
269 return JNI_ERR;
270 }
271
Michael Wright1f2c7682015-06-03 13:46:48 +0100272 return jniRegisterNativeMethods(env, "com/android/commands/hid/Device",
273 sMethods, NELEM(sMethods));
274}
275
276} // namespace android
277
278jint JNI_OnLoad(JavaVM* jvm, void*) {
279 JNIEnv *env = NULL;
280 if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
281 return JNI_ERR;
282 }
283
284 if (android::register_com_android_commands_hid_Device(env) < 0 ){
285 return JNI_ERR;
286 }
287
288 return JNI_VERSION_1_6;
289}