1 /*
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 <android-base/stringprintf.h>
22 #include <android/looper.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <jni.h>
26 #include <linux/uhid.h>
27 #include <log/log.h>
28 #include <nativehelper/JNIHelp.h>
29 #include <nativehelper/ScopedLocalRef.h>
30 #include <nativehelper/ScopedPrimitiveArray.h>
31 #include <nativehelper/ScopedUtfChars.h>
32 #include <unistd.h>
33 
34 #include <cstdio>
35 #include <cstring>
36 #include <memory>
37 
38 // Log debug messages about the output.
39 static constexpr bool DEBUG_OUTPUT = false;
40 
41 namespace android {
42 namespace uhid {
43 
44 static const char* UHID_PATH = "/dev/uhid";
45 
46 static struct {
47     jmethodID onDeviceOpen;
48     jmethodID onDeviceGetReport;
49     jmethodID onDeviceSetReport;
50     jmethodID onDeviceOutput;
51     jmethodID onDeviceError;
52 } gDeviceCallbackClassInfo;
53 
handleLooperEvents(int,int events,void * data)54 static int handleLooperEvents(int /* fd */, int events, void* data) {
55     Device* d = reinterpret_cast<Device*>(data);
56     return d->handleEvents(events);
57 }
58 
checkAndClearException(JNIEnv * env,const char * methodName)59 static void checkAndClearException(JNIEnv* env, const char* methodName) {
60     if (env->ExceptionCheck()) {
61         ALOGE("An exception was thrown by callback '%s'.", methodName);
62         env->ExceptionClear();
63     }
64 }
65 
toJbyteArray(JNIEnv * env,const std::vector<uint8_t> & vector)66 static ScopedLocalRef<jbyteArray> toJbyteArray(JNIEnv* env, const std::vector<uint8_t>& vector) {
67     ScopedLocalRef<jbyteArray> array(env, env->NewByteArray(vector.size()));
68     if (array.get() == nullptr) {
69         jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
70         return array;
71     }
72     static_assert(sizeof(char) == sizeof(uint8_t));
73     env->SetByteArrayRegion(array.get(), 0, vector.size(),
74                             reinterpret_cast<const signed char*>(vector.data()));
75     return array;
76 }
77 
toString(const std::vector<uint8_t> & data)78 static std::string toString(const std::vector<uint8_t>& data) {
79     std::string s = "";
80     for (uint8_t b : data) {
81         s += android::base::StringPrintf("%x ", b);
82     }
83     return s;
84 }
85 
DeviceCallback(JNIEnv * env,jobject callback)86 DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
87     mCallbackObject(env->NewGlobalRef(callback)) {
88     env->GetJavaVM(&mJavaVM);
89  }
90 
~DeviceCallback()91 DeviceCallback::~DeviceCallback() {
92     JNIEnv* env = getJNIEnv();
93     env->DeleteGlobalRef(mCallbackObject);
94 }
95 
onDeviceError()96 void DeviceCallback::onDeviceError() {
97     JNIEnv* env = getJNIEnv();
98     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
99     checkAndClearException(env, "onDeviceError");
100 }
101 
onDeviceOpen()102 void DeviceCallback::onDeviceOpen() {
103     JNIEnv* env = getJNIEnv();
104     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen);
105     checkAndClearException(env, "onDeviceOpen");
106 }
107 
onDeviceGetReport(uint32_t requestId,uint8_t reportId)108 void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) {
109     JNIEnv* env = getJNIEnv();
110     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport, requestId,
111                         reportId);
112     checkAndClearException(env, "onDeviceGetReport");
113 }
114 
onDeviceSetReport(uint32_t id,uint8_t rType,const std::vector<uint8_t> & data)115 void DeviceCallback::onDeviceSetReport(uint32_t id, uint8_t rType,
116                                        const std::vector<uint8_t>& data) {
117     JNIEnv* env = getJNIEnv();
118     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceSetReport, id, rType,
119                         toJbyteArray(env, data).get());
120     checkAndClearException(env, "onDeviceSetReport");
121 }
122 
onDeviceOutput(uint8_t rType,const std::vector<uint8_t> & data)123 void DeviceCallback::onDeviceOutput(uint8_t rType,
124                                     const std::vector<uint8_t>& data) {
125     JNIEnv* env = getJNIEnv();
126     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOutput, rType,
127                         toJbyteArray(env, data).get());
128     checkAndClearException(env, "onDeviceOutput");
129 }
130 
getJNIEnv()131 JNIEnv* DeviceCallback::getJNIEnv() {
132     JNIEnv* env;
133     mJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
134     return env;
135 }
136 
open(int32_t id,const char * name,const char * uniq,int32_t vid,int32_t pid,uint16_t bus,const std::vector<uint8_t> & descriptor,std::unique_ptr<DeviceCallback> callback)137 std::unique_ptr<Device> Device::open(int32_t id, const char* name, const char* uniq, int32_t vid,
138                                      int32_t pid, uint16_t bus,
139                                      const std::vector<uint8_t>& descriptor,
140                                      std::unique_ptr<DeviceCallback> callback) {
141     size_t size = descriptor.size();
142     if (size > HID_MAX_DESCRIPTOR_SIZE) {
143         ALOGE("Received invalid hid report with descriptor size %zu, skipping", size);
144         return nullptr;
145     }
146 
147     android::base::unique_fd fd(::open(UHID_PATH, O_RDWR | O_CLOEXEC));
148     if (!fd.ok()) {
149         ALOGE("Failed to open uhid: %s", strerror(errno));
150         return nullptr;
151     }
152 
153     struct uhid_event ev = {};
154     ev.type = UHID_CREATE2;
155     strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
156     strlcpy(reinterpret_cast<char*>(ev.u.create2.uniq), uniq, sizeof(ev.u.create2.uniq));
157     memcpy(&ev.u.create2.rd_data, descriptor.data(), size * sizeof(ev.u.create2.rd_data[0]));
158     ev.u.create2.rd_size = size;
159     ev.u.create2.bus = bus;
160     ev.u.create2.vendor = vid;
161     ev.u.create2.product = pid;
162     ev.u.create2.version = 0;
163     ev.u.create2.country = 0;
164 
165     errno = 0;
166     ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
167     if (ret < 0 || ret != sizeof(ev)) {
168         ALOGE("Failed to create uhid node: %s", strerror(errno));
169         return nullptr;
170     }
171 
172     // Wait for the device to actually be created.
173     ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
174     if (ret < 0 || ev.type != UHID_START) {
175         ALOGE("uhid node failed to start: %s", strerror(errno));
176         return nullptr;
177     }
178     // using 'new' to access non-public constructor
179     return std::unique_ptr<Device>(new Device(id, std::move(fd), std::move(callback)));
180 }
181 
Device(int32_t id,android::base::unique_fd fd,std::unique_ptr<DeviceCallback> callback)182 Device::Device(int32_t id, android::base::unique_fd fd, std::unique_ptr<DeviceCallback> callback)
183       : mId(id), mFd(std::move(fd)), mDeviceCallback(std::move(callback)) {
184     ALooper* aLooper = ALooper_forThread();
185     if (aLooper == NULL) {
186         ALOGE("Could not get ALooper, ALooper_forThread returned NULL");
187         aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
188     }
189     ALooper_addFd(aLooper, mFd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
190                   reinterpret_cast<void*>(this));
191 }
192 
~Device()193 Device::~Device() {
194     ALooper* looper = ALooper_forThread();
195     if (looper != NULL) {
196         ALooper_removeFd(looper, mFd);
197     } else {
198         ALOGE("Could not remove fd, ALooper_forThread() returned NULL!");
199     }
200     struct uhid_event ev = {};
201     ev.type = UHID_DESTROY;
202     TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
203 }
204 
205 // Send event over the fd.
writeEvent(int fd,struct uhid_event & ev,const char * messageType)206 static void writeEvent(int fd, struct uhid_event& ev, const char* messageType) {
207     ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
208     if (ret < 0 || ret != sizeof(ev)) {
209         ALOGE("Failed to send uhid_event %s: %s", messageType, strerror(errno));
210     }
211 }
212 
sendReport(const std::vector<uint8_t> & report) const213 void Device::sendReport(const std::vector<uint8_t>& report) const {
214     if (report.size() > UHID_DATA_MAX) {
215         ALOGE("Received invalid report of size %zu, skipping", report.size());
216         return;
217     }
218 
219     struct uhid_event ev = {};
220     ev.type = UHID_INPUT2;
221     ev.u.input2.size = report.size();
222     memcpy(&ev.u.input2.data, report.data(), report.size() * sizeof(ev.u.input2.data[0]));
223     writeEvent(mFd, ev, "UHID_INPUT2");
224 }
225 
sendGetFeatureReportReply(uint32_t id,const std::vector<uint8_t> & report) const226 void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& report) const {
227     struct uhid_event ev = {};
228     ev.type = UHID_GET_REPORT_REPLY;
229     ev.u.get_report_reply.id = id;
230     ev.u.get_report_reply.err = report.size() == 0 ? EIO : 0;
231     ev.u.get_report_reply.size = report.size();
232     memcpy(&ev.u.get_report_reply.data, report.data(),
233             report.size() * sizeof(ev.u.get_report_reply.data[0]));
234     writeEvent(mFd, ev, "UHID_GET_REPORT_REPLY");
235 }
236 
sendSetReportReply(uint32_t id,bool success) const237 void Device::sendSetReportReply(uint32_t id, bool success) const {
238     struct uhid_event ev = {};
239     ev.type = UHID_SET_REPORT_REPLY;
240     ev.u.set_report_reply.id = id;
241     ev.u.set_report_reply.err = success ? 0 : EIO;
242     writeEvent(mFd, ev, "UHID_SET_REPORT_REPLY");
243 }
244 
handleEvents(int events)245 int Device::handleEvents(int events) {
246     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
247         ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
248         mDeviceCallback->onDeviceError();
249         return 0;
250     }
251     struct uhid_event ev;
252     ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev)));
253     if (ret < 0) {
254         ALOGE("Failed to read from uhid node: %s", strerror(errno));
255         mDeviceCallback->onDeviceError();
256         return 0;
257     }
258     switch (ev.type) {
259         case UHID_OPEN: {
260             mDeviceCallback->onDeviceOpen();
261             break;
262         }
263         case UHID_GET_REPORT: {
264             mDeviceCallback->onDeviceGetReport(ev.u.get_report.id, ev.u.get_report.rnum);
265             break;
266         }
267         case UHID_SET_REPORT: {
268             const struct uhid_set_report_req& set_report = ev.u.set_report;
269             if (set_report.size > UHID_DATA_MAX) {
270                 ALOGE("SET_REPORT contains too much data: size = %" PRIu16, set_report.size);
271                 return 0;
272             }
273 
274             std::vector<uint8_t> data(set_report.data, set_report.data + set_report.size);
275             if (DEBUG_OUTPUT) {
276                 ALOGD("Received SET_REPORT: id=%" PRIu32 " rnum=%" PRIu8 " data=%s", set_report.id,
277                       set_report.rnum, toString(data).c_str());
278             }
279             mDeviceCallback->onDeviceSetReport(set_report.id, set_report.rtype, data);
280             break;
281         }
282         case UHID_OUTPUT: {
283             struct uhid_output_req& output = ev.u.output;
284             std::vector<uint8_t> data(output.data, output.data + output.size);
285             if (DEBUG_OUTPUT) {
286                 ALOGD("UHID_OUTPUT rtype=%" PRIu8 " data=%s", output.rtype, toString(data).c_str());
287             }
288             mDeviceCallback->onDeviceOutput(output.rtype, data);
289             break;
290         }
291         default: {
292             ALOGI("Unhandled event type: %" PRIu32, ev.type);
293             break;
294         }
295     }
296 
297     return 1;
298 }
299 
300 } // namespace uhid
301 
getData(JNIEnv * env,jbyteArray javaArray)302 std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) {
303     std::vector<uint8_t> data;
304     if (javaArray == nullptr) {
305         return data;
306     }
307 
308     ScopedByteArrayRO scopedArray(env, javaArray);
309     size_t size = scopedArray.size();
310     data.reserve(size);
311     for (size_t i = 0; i < size; i++) {
312         data.push_back(static_cast<uint8_t>(scopedArray[i]));
313     }
314     return data;
315 }
316 
openDevice(JNIEnv * env,jclass,jstring rawName,jstring rawUniq,jint id,jint vid,jint pid,jint bus,jbyteArray rawDescriptor,jobject callback)317 static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jstring rawUniq, jint id,
318                         jint vid, jint pid, jint bus, jbyteArray rawDescriptor, jobject callback) {
319     ScopedUtfChars name(env, rawName);
320     if (name.c_str() == nullptr) {
321         return 0;
322     }
323 
324     std::string uniq;
325     if (rawUniq != nullptr) {
326         uniq = ScopedUtfChars(env, rawUniq);
327     } else {
328         uniq = android::base::StringPrintf("Id: %d", id);
329     }
330 
331     if (uniq.c_str() == nullptr) {
332         return 0;
333     }
334 
335     std::vector<uint8_t> desc = getData(env, rawDescriptor);
336 
337     std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
338 
339     std::unique_ptr<uhid::Device> d =
340             uhid::Device::open(id, reinterpret_cast<const char*>(name.c_str()),
341                                reinterpret_cast<const char*>(uniq.c_str()), vid, pid, bus, desc,
342                                std::move(cb));
343     return reinterpret_cast<jlong>(d.release());
344 }
345 
sendReport(JNIEnv * env,jclass,jlong ptr,jbyteArray rawReport)346 static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
347     std::vector<uint8_t> report = getData(env, rawReport);
348     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
349     if (d) {
350         d->sendReport(report);
351     } else {
352         ALOGE("Could not send report, Device* is null!");
353     }
354 }
355 
sendGetFeatureReportReply(JNIEnv * env,jclass,jlong ptr,jint id,jbyteArray rawReport)356 static void sendGetFeatureReportReply(JNIEnv* env, jclass /* clazz */, jlong ptr, jint id,
357         jbyteArray rawReport) {
358     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
359     if (d) {
360         std::vector<uint8_t> report = getData(env, rawReport);
361         d->sendGetFeatureReportReply(id, report);
362     } else {
363         ALOGE("Could not send get feature report reply, Device* is null!");
364     }
365 }
366 
sendSetReportReply(JNIEnv *,jclass,jlong ptr,jint id,jboolean success)367 static void sendSetReportReply(JNIEnv*, jclass /* clazz */, jlong ptr, jint id, jboolean success) {
368     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
369     if (d) {
370         d->sendSetReportReply(id, success);
371     } else {
372         ALOGE("Could not send set report reply, Device* is null!");
373     }
374 }
375 
closeDevice(JNIEnv *,jclass,jlong ptr)376 static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
377     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
378     if (d) {
379         delete d;
380     }
381 }
382 
383 static JNINativeMethod sMethods[] = {
384         {"nativeOpenDevice",
385          "(Ljava/lang/String;Ljava/lang/String;IIII[B"
386          "Lcom/android/commands/hid/Device$DeviceCallback;)J",
387          reinterpret_cast<void*>(openDevice)},
388         {"nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport)},
389         {"nativeSendGetFeatureReportReply", "(JI[B)V",
390          reinterpret_cast<void*>(sendGetFeatureReportReply)},
391         {"nativeSendSetReportReply", "(JIZ)V", reinterpret_cast<void*>(sendSetReportReply)},
392         {"nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice)},
393 };
394 
register_com_android_commands_hid_Device(JNIEnv * env)395 int register_com_android_commands_hid_Device(JNIEnv* env) {
396     jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback");
397     if (clazz == NULL) {
398         ALOGE("Unable to find class 'DeviceCallback'");
399         return JNI_ERR;
400     }
401     uhid::gDeviceCallbackClassInfo.onDeviceOpen =
402             env->GetMethodID(clazz, "onDeviceOpen", "()V");
403     uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
404             env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
405     uhid::gDeviceCallbackClassInfo.onDeviceSetReport =
406             env->GetMethodID(clazz, "onDeviceSetReport", "(IB[B)V");
407     uhid::gDeviceCallbackClassInfo.onDeviceOutput =
408             env->GetMethodID(clazz, "onDeviceOutput", "(B[B)V");
409     uhid::gDeviceCallbackClassInfo.onDeviceError =
410             env->GetMethodID(clazz, "onDeviceError", "()V");
411     if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL ||
412             uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) {
413         ALOGE("Unable to obtain onDeviceOpen or onDeviceError methods");
414         return JNI_ERR;
415     }
416 
417     return jniRegisterNativeMethods(env, "com/android/commands/hid/Device",
418             sMethods, NELEM(sMethods));
419 }
420 
421 } // namespace android
422 
JNI_OnLoad(JavaVM * jvm,void *)423 jint JNI_OnLoad(JavaVM* jvm, void*) {
424     JNIEnv *env = NULL;
425     if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
426         return JNI_ERR;
427     }
428 
429     if (android::register_com_android_commands_hid_Device(env) < 0 ){
430         return JNI_ERR;
431     }
432 
433     return JNI_VERSION_1_6;
434 }
435