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