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