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 <cstdio>
25 #include <cstring>
26 #include <memory>
27 #include <unistd.h>
28 
29 #include <jni.h>
30 #include <nativehelper/JNIHelp.h>
31 #include <nativehelper/ScopedPrimitiveArray.h>
32 #include <nativehelper/ScopedUtfChars.h>
33 #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__)
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 onDeviceError;
50 } gDeviceCallbackClassInfo;
51 
handleLooperEvents(int,int events,void * data)52 static int handleLooperEvents(int /* fd */, int events, void* data) {
53     Device* d = reinterpret_cast<Device*>(data);
54     return d->handleEvents(events);
55 }
56 
checkAndClearException(JNIEnv * env,const char * methodName)57 static void checkAndClearException(JNIEnv* env, const char* methodName) {
58     if (env->ExceptionCheck()) {
59         LOGE("An exception was thrown by callback '%s'.", methodName);
60         env->ExceptionClear();
61     }
62 }
63 
DeviceCallback(JNIEnv * env,jobject callback)64 DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
65     mCallbackObject(env->NewGlobalRef(callback)) {
66     env->GetJavaVM(&mJavaVM);
67  }
68 
~DeviceCallback()69 DeviceCallback::~DeviceCallback() {
70     JNIEnv* env = getJNIEnv();
71     env->DeleteGlobalRef(mCallbackObject);
72 }
73 
onDeviceError()74 void DeviceCallback::onDeviceError() {
75     JNIEnv* env = getJNIEnv();
76     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
77     checkAndClearException(env, "onDeviceError");
78 }
79 
onDeviceOpen()80 void DeviceCallback::onDeviceOpen() {
81     JNIEnv* env = getJNIEnv();
82     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen);
83     checkAndClearException(env, "onDeviceOpen");
84 }
85 
onDeviceGetReport(uint32_t requestId,uint8_t reportId)86 void DeviceCallback::onDeviceGetReport(uint32_t requestId, uint8_t reportId) {
87     JNIEnv* env = getJNIEnv();
88     env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceGetReport,
89             requestId, reportId);
90     checkAndClearException(env, "onDeviceGetReport");
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 vid,int32_t pid,std::vector<uint8_t> descriptor,std::unique_ptr<DeviceCallback> callback)99 Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
100         std::vector<uint8_t> descriptor, std::unique_ptr<DeviceCallback> callback) {
101 
102     size_t size = descriptor.size();
103     if (size > HID_MAX_DESCRIPTOR_SIZE) {
104         LOGE("Received invalid hid report with descriptor size %zu, skipping", size);
105         return nullptr;
106     }
107 
108     int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
109     if (fd < 0) {
110         LOGE("Failed to open uhid: %s", strerror(errno));
111         return nullptr;
112     }
113 
114     struct uhid_event ev = {};
115     ev.type = UHID_CREATE2;
116     strlcpy(reinterpret_cast<char*>(ev.u.create2.name), name, sizeof(ev.u.create2.name));
117     memcpy(&ev.u.create2.rd_data, descriptor.data(),
118             size * sizeof(ev.u.create2.rd_data[0]));
119     ev.u.create2.rd_size = size;
120     ev.u.create2.bus = BUS_BLUETOOTH;
121     ev.u.create2.vendor = vid;
122     ev.u.create2.product = pid;
123     ev.u.create2.version = 0;
124     ev.u.create2.country = 0;
125 
126     errno = 0;
127     ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
128     if (ret < 0 || ret != sizeof(ev)) {
129         ::close(fd);
130         LOGE("Failed to create uhid node: %s", strerror(errno));
131         return nullptr;
132     }
133 
134     // Wait for the device to actually be created.
135     ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
136     if (ret < 0 || ev.type != UHID_START) {
137         ::close(fd);
138         LOGE("uhid node failed to start: %s", strerror(errno));
139         return nullptr;
140     }
141     return new Device(id, fd, std::move(callback));
142 }
143 
Device(int32_t id,int fd,std::unique_ptr<DeviceCallback> callback)144 Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback) :
145             mId(id), mFd(fd), mDeviceCallback(std::move(callback)) {
146     ALooper* aLooper = ALooper_forThread();
147     if (aLooper == NULL) {
148         LOGE("Could not get ALooper, ALooper_forThread returned NULL");
149         aLooper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
150     }
151     ALooper_addFd(aLooper, fd, 0, ALOOPER_EVENT_INPUT, handleLooperEvents,
152                   reinterpret_cast<void*>(this));
153 }
154 
~Device()155 Device::~Device() {
156     ALooper* looper = ALooper_forThread();
157     if (looper != NULL) {
158         ALooper_removeFd(looper, mFd);
159     } else {
160         LOGE("Could not remove fd, ALooper_forThread() returned NULL!");
161     }
162     struct uhid_event ev = {};
163     ev.type = UHID_DESTROY;
164     TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
165     ::close(mFd);
166     mFd = -1;
167 }
168 
sendReport(const std::vector<uint8_t> & report) const169 void Device::sendReport(const std::vector<uint8_t>& report) const {
170     if (report.size() > UHID_DATA_MAX) {
171         LOGE("Received invalid report of size %zu, skipping", report.size());
172         return;
173     }
174 
175     struct uhid_event ev = {};
176     ev.type = UHID_INPUT2;
177     ev.u.input2.size = report.size();
178     memcpy(&ev.u.input2.data, report.data(), report.size() * sizeof(ev.u.input2.data[0]));
179     ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
180     if (ret < 0 || ret != sizeof(ev)) {
181         LOGE("Failed to send hid event: %s", strerror(errno));
182     }
183 }
184 
sendGetFeatureReportReply(uint32_t id,const std::vector<uint8_t> & report) const185 void Device::sendGetFeatureReportReply(uint32_t id, const std::vector<uint8_t>& report) const {
186     struct uhid_event ev = {};
187     ev.type = UHID_GET_REPORT_REPLY;
188     ev.u.get_report_reply.id = id;
189     ev.u.get_report_reply.err = report.size() == 0 ? EIO : 0;
190     ev.u.get_report_reply.size = report.size();
191     memcpy(&ev.u.get_report_reply.data, report.data(),
192             report.size() * sizeof(ev.u.get_report_reply.data[0]));
193     ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
194     if (ret < 0 || ret != sizeof(ev)) {
195         LOGE("Failed to send hid event (UHID_GET_REPORT_REPLY): %s", strerror(errno));
196     }
197 }
198 
handleEvents(int events)199 int Device::handleEvents(int events) {
200     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
201         LOGE("uhid node was closed or an error occurred. events=0x%x", events);
202         mDeviceCallback->onDeviceError();
203         return 0;
204     }
205     struct uhid_event ev;
206     ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev)));
207     if (ret < 0) {
208         LOGE("Failed to read from uhid node: %s", strerror(errno));
209         mDeviceCallback->onDeviceError();
210         return 0;
211     }
212 
213     if (ev.type == UHID_OPEN) {
214         mDeviceCallback->onDeviceOpen();
215     } else if (ev.type == UHID_GET_REPORT) {
216         mDeviceCallback->onDeviceGetReport(ev.u.get_report.id, ev.u.get_report.rnum);
217     } else if (ev.type == UHID_SET_REPORT) {
218         LOGE("UHID_SET_REPORT is currently not supported");
219         return 0;
220     }
221 
222     return 1;
223 }
224 
225 } // namespace uhid
226 
getData(JNIEnv * env,jbyteArray javaArray)227 std::vector<uint8_t> getData(JNIEnv* env, jbyteArray javaArray) {
228     std::vector<uint8_t> data;
229     if (javaArray == nullptr) {
230         return data;
231     }
232 
233     ScopedByteArrayRO scopedArray(env, javaArray);
234     size_t size = scopedArray.size();
235     data.reserve(size);
236     for (size_t i = 0; i < size; i++) {
237         data.push_back(static_cast<uint8_t>(scopedArray[i]));
238     }
239     return data;
240 }
241 
openDevice(JNIEnv * env,jclass,jstring rawName,jint id,jint vid,jint pid,jbyteArray rawDescriptor,jobject callback)242 static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid,
243         jbyteArray rawDescriptor, jobject callback) {
244     ScopedUtfChars name(env, rawName);
245     if (name.c_str() == nullptr) {
246         return 0;
247     }
248 
249     std::vector<uint8_t> desc = getData(env, rawDescriptor);
250 
251     std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
252 
253     uhid::Device* d = uhid::Device::open(
254             id, reinterpret_cast<const char*>(name.c_str()), vid, pid, desc, std::move(cb));
255     return reinterpret_cast<jlong>(d);
256 }
257 
sendReport(JNIEnv * env,jclass,jlong ptr,jbyteArray rawReport)258 static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr, jbyteArray rawReport) {
259     std::vector<uint8_t> report = getData(env, rawReport);
260     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
261     if (d) {
262         d->sendReport(report);
263     } else {
264         LOGE("Could not send report, Device* is null!");
265     }
266 }
267 
sendGetFeatureReportReply(JNIEnv * env,jclass,jlong ptr,jint id,jbyteArray rawReport)268 static void sendGetFeatureReportReply(JNIEnv* env, jclass /* clazz */, jlong ptr, jint id,
269         jbyteArray rawReport) {
270     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
271     if (d) {
272         std::vector<uint8_t> report = getData(env, rawReport);
273         d->sendGetFeatureReportReply(id, report);
274     } else {
275         LOGE("Could not send get feature report reply, Device* is null!");
276     }
277 }
278 
closeDevice(JNIEnv *,jclass,jlong ptr)279 static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
280     uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
281     if (d) {
282         delete d;
283     }
284 }
285 
286 static JNINativeMethod sMethods[] = {
287     { "nativeOpenDevice",
288             "(Ljava/lang/String;III[B"
289             "Lcom/android/commands/hid/Device$DeviceCallback;)J",
290             reinterpret_cast<void*>(openDevice) },
291     { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
292     { "nativeSendGetFeatureReportReply", "(JI[B)V",
293             reinterpret_cast<void*>(sendGetFeatureReportReply) },
294     { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) },
295 };
296 
register_com_android_commands_hid_Device(JNIEnv * env)297 int register_com_android_commands_hid_Device(JNIEnv* env) {
298     jclass clazz = env->FindClass("com/android/commands/hid/Device$DeviceCallback");
299     if (clazz == NULL) {
300         LOGE("Unable to find class 'DeviceCallback'");
301         return JNI_ERR;
302     }
303     uhid::gDeviceCallbackClassInfo.onDeviceOpen =
304             env->GetMethodID(clazz, "onDeviceOpen", "()V");
305     uhid::gDeviceCallbackClassInfo.onDeviceGetReport =
306             env->GetMethodID(clazz, "onDeviceGetReport", "(II)V");
307     uhid::gDeviceCallbackClassInfo.onDeviceError =
308             env->GetMethodID(clazz, "onDeviceError", "()V");
309     if (uhid::gDeviceCallbackClassInfo.onDeviceOpen == NULL ||
310             uhid::gDeviceCallbackClassInfo.onDeviceError == NULL) {
311         LOGE("Unable to obtain onDeviceOpen or onDeviceError methods");
312         return JNI_ERR;
313     }
314 
315     return jniRegisterNativeMethods(env, "com/android/commands/hid/Device",
316             sMethods, NELEM(sMethods));
317 }
318 
319 } // namespace android
320 
JNI_OnLoad(JavaVM * jvm,void *)321 jint JNI_OnLoad(JavaVM* jvm, void*) {
322     JNIEnv *env = NULL;
323     if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
324         return JNI_ERR;
325     }
326 
327     if (android::register_com_android_commands_hid_Device(env) < 0 ){
328         return JNI_ERR;
329     }
330 
331     return JNI_VERSION_1_6;
332 }
333