1/* 2 * Copyright (C) 2010 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 "UsbHostManagerJNI" 18#include "utils/Log.h" 19 20#include "jni.h" 21#include <nativehelper/JNIHelp.h> 22#include "android_runtime/AndroidRuntime.h" 23#include "android_runtime/Log.h" 24 25#include <stdio.h> 26#include <asm/byteorder.h> 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <fcntl.h> 30#include <sys/ioctl.h> 31 32#include <usbhost/usbhost.h> 33 34#define MAX_DESCRIPTORS_LENGTH 4096 35 36namespace android 37{ 38 39static struct parcel_file_descriptor_offsets_t 40{ 41 jclass mClass; 42 jmethodID mConstructor; 43} gParcelFileDescriptorOffsets; 44 45static jmethodID method_usbDeviceAdded; 46static jmethodID method_usbDeviceRemoved; 47 48static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { 49 if (env->ExceptionCheck()) { 50 ALOGE("An exception was thrown by callback '%s'.", methodName); 51 LOGE_EX(env); 52 env->ExceptionClear(); 53 } 54} 55 56static int usb_device_added(const char *devAddress, void* clientData) { 57 struct usb_device *device = usb_device_open(devAddress); 58 if (!device) { 59 ALOGE("usb_device_open failed\n"); 60 return 0; 61 } 62 63 const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device); 64 int classID = deviceDesc->bDeviceClass; 65 int subClassID = deviceDesc->bDeviceSubClass; 66 67 // get the raw descriptors 68 int numBytes = usb_device_get_descriptors_length(device); 69 if (numBytes > 0) { 70 JNIEnv* env = AndroidRuntime::getJNIEnv(); 71 jobject thiz = (jobject)clientData; 72 jstring deviceAddress = env->NewStringUTF(devAddress); 73 74 jbyteArray descriptorsArray = env->NewByteArray(numBytes); 75 const jbyte* rawDescriptors = (const jbyte*)usb_device_get_raw_descriptors(device); 76 env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawDescriptors); 77 78 env->CallBooleanMethod(thiz, method_usbDeviceAdded, 79 deviceAddress, classID, subClassID, descriptorsArray); 80 81 env->DeleteLocalRef(descriptorsArray); 82 env->DeleteLocalRef(deviceAddress); 83 84 checkAndClearExceptionFromCallback(env, __FUNCTION__); 85 } else { 86 // TODO return an error code here? 87 ALOGE("error reading descriptors\n"); 88 } 89 90 usb_device_close(device); 91 92 return 0; 93} 94 95static int usb_device_removed(const char *devAddress, void* clientData) { 96 JNIEnv* env = AndroidRuntime::getJNIEnv(); 97 jobject thiz = (jobject)clientData; 98 99 jstring deviceAddress = env->NewStringUTF(devAddress); 100 env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceAddress); 101 env->DeleteLocalRef(deviceAddress); 102 checkAndClearExceptionFromCallback(env, __FUNCTION__); 103 return 0; 104} 105 106static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv* /* env */, jobject thiz) 107{ 108 struct usb_host_context* context = usb_host_init(); 109 if (!context) { 110 ALOGE("usb_host_init failed"); 111 return; 112 } 113 // this will never return so it is safe to pass thiz directly 114 usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz); 115} 116 117static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */, 118 jstring deviceAddress) 119{ 120 const char *deviceAddressStr = env->GetStringUTFChars(deviceAddress, NULL); 121 struct usb_device* device = usb_device_open(deviceAddressStr); 122 env->ReleaseStringUTFChars(deviceAddress, deviceAddressStr); 123 124 if (!device) 125 return NULL; 126 127 int fd = usb_device_get_fd(device); 128 if (fd < 0) { 129 usb_device_close(device); 130 return NULL; 131 } 132 int newFD = dup(fd); 133 usb_device_close(device); 134 135 jobject fileDescriptor = jniCreateFileDescriptor(env, newFD); 136 if (fileDescriptor == NULL) { 137 return NULL; 138 } 139 return env->NewObject(gParcelFileDescriptorOffsets.mClass, 140 gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); 141} 142 143static const JNINativeMethod method_table[] = { 144 { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus }, 145 { "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", 146 (void*)android_server_UsbHostManager_openDevice }, 147}; 148 149int register_android_server_UsbHostManager(JNIEnv *env) 150{ 151 jclass clazz = env->FindClass("com/android/server/usb/UsbHostManager"); 152 if (clazz == NULL) { 153 ALOGE("Can't find com/android/server/usb/UsbHostManager"); 154 return -1; 155 } 156 method_usbDeviceAdded = 157 env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;II[B)Z"); 158 if (method_usbDeviceAdded == NULL) { 159 ALOGE("Can't find beginUsbDeviceAdded"); 160 return -1; 161 } 162 method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved", 163 "(Ljava/lang/String;)V"); 164 if (method_usbDeviceRemoved == NULL) { 165 ALOGE("Can't find usbDeviceRemoved"); 166 return -1; 167 } 168 169 clazz = env->FindClass("android/os/ParcelFileDescriptor"); 170 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); 171 gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); 172 gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", 173 "(Ljava/io/FileDescriptor;)V"); 174 LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, 175 "Unable to find constructor for android.os.ParcelFileDescriptor"); 176 177 return jniRegisterNativeMethods(env, "com/android/server/usb/UsbHostManager", 178 method_table, NELEM(method_table)); 179} 180 181}; 182