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 <android_runtime/AndroidRuntime.h> 30#include <android_runtime/Log.h> 31#include <android_os_MessageQueue.h> 32#include <core_jni_helpers.h> 33#include <jni.h> 34#include <JNIHelp.h> 35#include <ScopedPrimitiveArray.h> 36#include <ScopedUtfChars.h> 37#include <utils/Log.h> 38#include <utils/Looper.h> 39#include <utils/StrongPointer.h> 40 41namespace android { 42namespace uhid { 43 44static const char* UHID_PATH = "/dev/uhid"; 45static const size_t UHID_MAX_NAME_LENGTH = 128; 46 47static struct { 48 jmethodID onDeviceOpen; 49 jmethodID onDeviceError; 50} gDeviceCallbackClassInfo; 51 52static int handleLooperEvents(int /* fd */, int events, void* data) { 53 Device* d = reinterpret_cast<Device*>(data); 54 return d->handleEvents(events); 55} 56 57static void checkAndClearException(JNIEnv* env, const char* methodName) { 58 if (env->ExceptionCheck()) { 59 ALOGE("An exception was thrown by callback '%s'.", methodName); 60 LOGE_EX(env); 61 env->ExceptionClear(); 62 } 63} 64 65DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) : 66 mCallbackObject(env->NewGlobalRef(callback)) { } 67 68DeviceCallback::~DeviceCallback() { 69 JNIEnv* env = AndroidRuntime::getJNIEnv(); 70 env->DeleteGlobalRef(mCallbackObject); 71} 72 73void DeviceCallback::onDeviceError() { 74 JNIEnv* env = AndroidRuntime::getJNIEnv(); 75 env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError); 76 checkAndClearException(env, "onDeviceError"); 77} 78 79void DeviceCallback::onDeviceOpen() { 80 JNIEnv* env = AndroidRuntime::getJNIEnv(); 81 env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen); 82 checkAndClearException(env, "onDeviceOpen"); 83} 84 85Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid, 86 std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize, 87 std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) { 88 89 int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC); 90 if (fd < 0) { 91 ALOGE("Failed to open uhid: %s", strerror(errno)); 92 return nullptr; 93 } 94 95 struct uhid_event ev; 96 memset(&ev, 0, sizeof(ev)); 97 ev.type = UHID_CREATE; 98 strncpy((char*)ev.u.create.name, name, UHID_MAX_NAME_LENGTH); 99 ev.u.create.rd_data = descriptor.get(); 100 ev.u.create.rd_size = descriptorSize; 101 ev.u.create.bus = BUS_BLUETOOTH; 102 ev.u.create.vendor = vid; 103 ev.u.create.product = pid; 104 ev.u.create.version = 0; 105 ev.u.create.country = 0; 106 107 errno = 0; 108 ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev))); 109 if (ret < 0 || ret != sizeof(ev)) { 110 ::close(fd); 111 ALOGE("Failed to create uhid node: %s", strerror(errno)); 112 return nullptr; 113 } 114 115 // Wait for the device to actually be created. 116 ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev))); 117 if (ret < 0 || ev.type != UHID_START) { 118 ::close(fd); 119 ALOGE("uhid node failed to start: %s", strerror(errno)); 120 return nullptr; 121 } 122 123 return new Device(id, fd, std::move(callback), looper); 124} 125 126Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) : 127 mId(id), mFd(fd), mDeviceCallback(std::move(callback)), mLooper(looper) { 128 looper->addFd(fd, 0, Looper::EVENT_INPUT, handleLooperEvents, reinterpret_cast<void*>(this)); 129} 130 131Device::~Device() { 132 mLooper->removeFd(mFd); 133 struct uhid_event ev; 134 memset(&ev, 0, sizeof(ev)); 135 ev.type = UHID_DESTROY; 136 TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev))); 137 ::close(mFd); 138 mFd = -1; 139} 140 141void Device::sendReport(uint8_t* report, size_t reportSize) { 142 struct uhid_event ev; 143 memset(&ev, 0, sizeof(ev)); 144 ev.type = UHID_INPUT; 145 ev.u.input.size = reportSize; 146 memcpy(&ev.u.input.data, report, reportSize); 147 ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev))); 148 if (ret < 0 || ret != sizeof(ev)) { 149 ALOGE("Failed to send hid event: %s", strerror(errno)); 150 } 151} 152 153int Device::handleEvents(int events) { 154 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { 155 ALOGE("uhid node was closed or an error occurred. events=0x%x", events); 156 mDeviceCallback->onDeviceError(); 157 return 0; 158 } 159 struct uhid_event ev; 160 ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev))); 161 if (ret < 0) { 162 ALOGE("Failed to read from uhid node: %s", strerror(errno)); 163 mDeviceCallback->onDeviceError(); 164 return 0; 165 } 166 167 if (ev.type == UHID_OPEN) { 168 mDeviceCallback->onDeviceOpen(); 169 } 170 171 return 1; 172} 173 174} // namespace uhid 175 176std::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& outSize) { 177 ScopedByteArrayRO scopedArray(env, javaArray); 178 outSize = scopedArray.size(); 179 std::unique_ptr<uint8_t[]> data(new uint8_t[outSize]); 180 for (size_t i = 0; i < outSize; i++) { 181 data[i] = static_cast<uint8_t>(scopedArray[i]); 182 } 183 return data; 184} 185 186static jlong openDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid, jint pid, 187 jbyteArray rawDescriptor, jobject queue, jobject callback) { 188 ScopedUtfChars name(env, rawName); 189 if (name.c_str() == nullptr) { 190 return 0; 191 } 192 193 size_t size; 194 std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size); 195 196 std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback)); 197 sp<Looper> looper = android_os_MessageQueue_getMessageQueue(env, queue)->getLooper(); 198 199 uhid::Device* d = uhid::Device::open( 200 id, reinterpret_cast<const char*>(name.c_str()), vid, pid, 201 std::move(desc), size, std::move(cb), std::move(looper)); 202 return reinterpret_cast<jlong>(d); 203} 204 205static void sendReport(JNIEnv* env, jclass /* clazz */, jlong ptr,jbyteArray rawReport) { 206 size_t size; 207 std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size); 208 uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr); 209 if (d) { 210 d->sendReport(report.get(), size); 211 } 212} 213 214static void closeDevice(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { 215 uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr); 216 if (d) { 217 delete d; 218 } 219} 220 221static JNINativeMethod sMethods[] = { 222 { "nativeOpenDevice", 223 "(Ljava/lang/String;III[BLandroid/os/MessageQueue;" 224 "Lcom/android/commands/hid/Device$DeviceCallback;)J", 225 reinterpret_cast<void*>(openDevice) }, 226 { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) }, 227 { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) }, 228}; 229 230int register_com_android_commands_hid_Device(JNIEnv* env) { 231 jclass clazz = FindClassOrDie(env, "com/android/commands/hid/Device$DeviceCallback"); 232 uhid::gDeviceCallbackClassInfo.onDeviceOpen = 233 GetMethodIDOrDie(env, clazz, "onDeviceOpen", "()V"); 234 uhid::gDeviceCallbackClassInfo.onDeviceError= 235 GetMethodIDOrDie(env, clazz, "onDeviceError", "()V"); 236 return jniRegisterNativeMethods(env, "com/android/commands/hid/Device", 237 sMethods, NELEM(sMethods)); 238} 239 240} // namespace android 241 242jint JNI_OnLoad(JavaVM* jvm, void*) { 243 JNIEnv *env = NULL; 244 if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) { 245 return JNI_ERR; 246 } 247 248 if (android::register_com_android_commands_hid_Device(env) < 0 ){ 249 return JNI_ERR; 250 } 251 252 return JNI_VERSION_1_6; 253} 254