com_android_server_UsbHostManager.cpp revision 9ee5e7e17f7d65620f21d1a42865981e7bc56593
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 "JNIHelp.h" 22#include "android_runtime/AndroidRuntime.h" 23#include "android_runtime/Log.h" 24#include "utils/Vector.h" 25 26#include <usbhost/usbhost.h> 27 28#include <stdio.h> 29#include <asm/byteorder.h> 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <fcntl.h> 33#include <sys/ioctl.h> 34 35namespace android 36{ 37 38static struct parcel_file_descriptor_offsets_t 39{ 40 jclass mClass; 41 jmethodID mConstructor; 42} gParcelFileDescriptorOffsets; 43 44static jmethodID method_beginUsbDeviceAdded; 45static jmethodID method_addUsbConfiguration; 46static jmethodID method_addUsbInterface; 47static jmethodID method_addUsbEndpoint; 48static jmethodID method_endUsbDeviceAdded; 49static jmethodID method_usbDeviceRemoved; 50 51static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { 52 if (env->ExceptionCheck()) { 53 ALOGE("An exception was thrown by callback '%s'.", methodName); 54 LOGE_EX(env); 55 env->ExceptionClear(); 56 } 57} 58 59static int usb_device_added(const char *devname, void* client_data) { 60 struct usb_descriptor_header* desc; 61 struct usb_descriptor_iter iter; 62 63 struct usb_device *device = usb_device_open(devname); 64 if (!device) { 65 ALOGE("usb_device_open failed\n"); 66 return 0; 67 } 68 69 JNIEnv* env = AndroidRuntime::getJNIEnv(); 70 jobject thiz = (jobject)client_data; 71 Vector<int> interfaceValues; 72 Vector<int> endpointValues; 73 const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device); 74 75 char *manufacturer = usb_device_get_manufacturer_name(device); 76 char *product = usb_device_get_product_name(device); 77 char *serial = usb_device_get_serial(device); 78 79 jstring deviceName = env->NewStringUTF(devname); 80 jstring manufacturerName = AndroidRuntime::NewStringLatin1(env, manufacturer); 81 jstring productName = AndroidRuntime::NewStringLatin1(env, product); 82 jstring serialNumber = AndroidRuntime::NewStringLatin1(env, serial); 83 84 jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded, 85 deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device), 86 deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol, 87 manufacturerName, productName, serialNumber); 88 89 env->DeleteLocalRef(serialNumber); 90 env->DeleteLocalRef(productName); 91 env->DeleteLocalRef(manufacturerName); 92 env->DeleteLocalRef(deviceName); 93 free(manufacturer); 94 free(product); 95 free(serial); 96 97 if (!result) goto fail; 98 99 usb_descriptor_iter_init(device, &iter); 100 101 while ((desc = usb_descriptor_iter_next(&iter)) != NULL) { 102 if (desc->bDescriptorType == USB_DT_CONFIG) { 103 struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc; 104 char *name = usb_device_get_string(device, config->iConfiguration); 105 jstring configName = AndroidRuntime::NewStringLatin1(env, name); 106 107 env->CallVoidMethod(thiz, method_addUsbConfiguration, 108 config->bConfigurationValue, configName, config->bmAttributes, 109 config->bMaxPower); 110 111 env->DeleteLocalRef(configName); 112 free(name); 113 } else if (desc->bDescriptorType == USB_DT_INTERFACE) { 114 struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc; 115 char *name = usb_device_get_string(device, interface->iInterface); 116 jstring interfaceName = AndroidRuntime::NewStringLatin1(env, name); 117 118 env->CallVoidMethod(thiz, method_addUsbInterface, 119 interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting, 120 interface->bInterfaceClass, interface->bInterfaceSubClass, 121 interface->bInterfaceProtocol); 122 123 env->DeleteLocalRef(interfaceName); 124 free(name); 125 } else if (desc->bDescriptorType == USB_DT_ENDPOINT) { 126 struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc; 127 128 env->CallVoidMethod(thiz, method_addUsbEndpoint, 129 endpoint->bEndpointAddress, endpoint->bmAttributes, 130 __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval); 131 } 132 } 133 134 env->CallVoidMethod(thiz, method_endUsbDeviceAdded); 135 136fail: 137 usb_device_close(device); 138 checkAndClearExceptionFromCallback(env, __FUNCTION__); 139 140 return 0; 141} 142 143static int usb_device_removed(const char *devname, void* client_data) { 144 JNIEnv* env = AndroidRuntime::getJNIEnv(); 145 jobject thiz = (jobject)client_data; 146 147 jstring deviceName = env->NewStringUTF(devname); 148 env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName); 149 env->DeleteLocalRef(deviceName); 150 checkAndClearExceptionFromCallback(env, __FUNCTION__); 151 return 0; 152} 153 154static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv *env, jobject thiz) 155{ 156 struct usb_host_context* context = usb_host_init(); 157 if (!context) { 158 ALOGE("usb_host_init failed"); 159 return; 160 } 161 // this will never return so it is safe to pass thiz directly 162 usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz); 163} 164 165static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject thiz, jstring deviceName) 166{ 167 const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL); 168 struct usb_device* device = usb_device_open(deviceNameStr); 169 env->ReleaseStringUTFChars(deviceName, deviceNameStr); 170 171 if (!device) 172 return NULL; 173 174 int fd = usb_device_get_fd(device); 175 if (fd < 0) { 176 usb_device_close(device); 177 return NULL; 178 } 179 int newFD = dup(fd); 180 usb_device_close(device); 181 182 jobject fileDescriptor = jniCreateFileDescriptor(env, newFD); 183 if (fileDescriptor == NULL) { 184 return NULL; 185 } 186 return env->NewObject(gParcelFileDescriptorOffsets.mClass, 187 gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); 188} 189 190static JNINativeMethod method_table[] = { 191 { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus }, 192 { "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", 193 (void*)android_server_UsbHostManager_openDevice }, 194}; 195 196int register_android_server_UsbHostManager(JNIEnv *env) 197{ 198 jclass clazz = env->FindClass("com/android/server/usb/UsbHostManager"); 199 if (clazz == NULL) { 200 ALOGE("Can't find com/android/server/usb/UsbHostManager"); 201 return -1; 202 } 203 method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded", 204 "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z"); 205 if (method_beginUsbDeviceAdded == NULL) { 206 ALOGE("Can't find beginUsbDeviceAdded"); 207 return -1; 208 } 209 method_addUsbConfiguration = env->GetMethodID(clazz, "addUsbConfiguration", 210 "(ILjava/lang/String;II)V"); 211 if (method_addUsbConfiguration == NULL) { 212 ALOGE("Can't find addUsbConfiguration"); 213 return -1; 214 } 215 method_addUsbInterface = env->GetMethodID(clazz, "addUsbInterface", 216 "(ILjava/lang/String;IIII)V"); 217 if (method_addUsbInterface == NULL) { 218 ALOGE("Can't find addUsbInterface"); 219 return -1; 220 } 221 method_addUsbEndpoint = env->GetMethodID(clazz, "addUsbEndpoint", "(IIII)V"); 222 if (method_addUsbEndpoint == NULL) { 223 ALOGE("Can't find addUsbEndpoint"); 224 return -1; 225 } 226 method_endUsbDeviceAdded = env->GetMethodID(clazz, "endUsbDeviceAdded", "()V"); 227 if (method_endUsbDeviceAdded == NULL) { 228 ALOGE("Can't find endUsbDeviceAdded"); 229 return -1; 230 } 231 method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved", 232 "(Ljava/lang/String;)V"); 233 if (method_usbDeviceRemoved == NULL) { 234 ALOGE("Can't find usbDeviceRemoved"); 235 return -1; 236 } 237 238 clazz = env->FindClass("android/os/ParcelFileDescriptor"); 239 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); 240 gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); 241 gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", 242 "(Ljava/io/FileDescriptor;)V"); 243 LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, 244 "Unable to find constructor for android.os.ParcelFileDescriptor"); 245 246 return jniRegisterNativeMethods(env, "com/android/server/usb/UsbHostManager", 247 method_table, NELEM(method_table)); 248} 249 250}; 251