blob: 11f508bbf79dc60c9812291ba42659b177b656f0 [file] [log] [blame]
Mike Lockwoode7d511e2010-12-30 13:39:37 -05001/*
Mike Lockwood9182d3c2011-02-15 09:50:22 -05002 * Copyright (C) 2010 The Android Open Source Project
Mike Lockwoode7d511e2010-12-30 13:39:37 -05003 *
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
Mike Lockwood46d0adf2011-05-26 10:27:39 -040017#define LOG_TAG "UsbHostManagerJNI"
Mike Lockwoode7d511e2010-12-30 13:39:37 -050018#include "utils/Log.h"
19
20#include "jni.h"
Steven Moreland2279b252017-07-19 09:50:45 -070021#include <nativehelper/JNIHelp.h>
Mike Lockwoode7d511e2010-12-30 13:39:37 -050022#include "android_runtime/AndroidRuntime.h"
Ruben Brunk87eac992013-09-09 17:44:59 -070023#include "android_runtime/Log.h"
Mike Lockwoode7d511e2010-12-30 13:39:37 -050024
Mike Lockwoode7d511e2010-12-30 13:39:37 -050025#include <stdio.h>
26#include <asm/byteorder.h>
Mike Lockwood9182d3c2011-02-15 09:50:22 -050027#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <sys/ioctl.h>
Mike Lockwoode7d511e2010-12-30 13:39:37 -050031
Paul McLean513160f2017-10-19 14:08:12 -060032#include <usbhost/usbhost.h>
33
34#define MAX_DESCRIPTORS_LENGTH 4096
35
Mike Lockwoode7d511e2010-12-30 13:39:37 -050036namespace android
37{
38
Mike Lockwoode7d511e2010-12-30 13:39:37 -050039static struct parcel_file_descriptor_offsets_t
40{
41 jclass mClass;
42 jmethodID mConstructor;
43} gParcelFileDescriptorOffsets;
44
Paul McLean513160f2017-10-19 14:08:12 -060045static jmethodID method_usbDeviceAdded;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050046static jmethodID method_usbDeviceRemoved;
47
48static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
49 if (env->ExceptionCheck()) {
Steve Block3762c312012-01-06 19:20:56 +000050 ALOGE("An exception was thrown by callback '%s'.", methodName);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050051 LOGE_EX(env);
52 env->ExceptionClear();
53 }
54}
55
Paul McLean513160f2017-10-19 14:08:12 -060056static int usb_device_added(const char *devAddress, void* clientData) {
57 struct usb_device *device = usb_device_open(devAddress);
Mike Lockwoode7d511e2010-12-30 13:39:37 -050058 if (!device) {
Steve Block3762c312012-01-06 19:20:56 +000059 ALOGE("usb_device_open failed\n");
Mike Lockwoode7d511e2010-12-30 13:39:37 -050060 return 0;
61 }
62
Mike Lockwoode7d511e2010-12-30 13:39:37 -050063 const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
Paul McLean513160f2017-10-19 14:08:12 -060064 int classID = deviceDesc->bDeviceClass;
65 int subClassID = deviceDesc->bDeviceSubClass;
Mike Lockwoode7d511e2010-12-30 13:39:37 -050066
Paul McLean513160f2017-10-19 14:08:12 -060067 // get the raw descriptors
68 int fd = usb_device_get_fd(device);
69 if (fd < 0) {
70 ALOGE("usb_device_get_fd failed\n");
71 usb_device_close(device);
72 // TODO return an error code here?
73 return 0;
Mike Lockwood7531aa22014-01-13 10:31:01 -080074 }
75
Paul McLean513160f2017-10-19 14:08:12 -060076 // from android_hardware_UsbDeviceConnection_get_desc()
77 jbyte rawdescriptors[MAX_DESCRIPTORS_LENGTH];
78 lseek(fd, 0, SEEK_SET);
79 int numBytes = read(fd, rawdescriptors, sizeof(rawdescriptors));
Mike Lockwood7531aa22014-01-13 10:31:01 -080080
Mike Lockwood7531aa22014-01-13 10:31:01 -080081 usb_device_close(device);
Paul McLean513160f2017-10-19 14:08:12 -060082
83 if (numBytes > 0) {
84 JNIEnv* env = AndroidRuntime::getJNIEnv();
85 jobject thiz = (jobject)clientData;
86 jstring deviceAddress = env->NewStringUTF(devAddress);
87
88 jbyteArray descriptorsArray = env->NewByteArray(numBytes);
89 env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawdescriptors);
90
91 env->CallBooleanMethod(thiz, method_usbDeviceAdded,
92 deviceAddress, classID, subClassID, descriptorsArray);
93
94 env->DeleteLocalRef(descriptorsArray);
95 env->DeleteLocalRef(deviceAddress);
96
97 checkAndClearExceptionFromCallback(env, __FUNCTION__);
98 } else {
99 // TODO return an error code here?
100 ALOGE("error reading descriptors\n");
101 }
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500102
103 return 0;
104}
105
Paul McLean513160f2017-10-19 14:08:12 -0600106static int usb_device_removed(const char *devAddress, void* clientData) {
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500107 JNIEnv* env = AndroidRuntime::getJNIEnv();
Paul McLean513160f2017-10-19 14:08:12 -0600108 jobject thiz = (jobject)clientData;
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500109
Paul McLean513160f2017-10-19 14:08:12 -0600110 jstring deviceAddress = env->NewStringUTF(devAddress);
111 env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceAddress);
112 env->DeleteLocalRef(deviceAddress);
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500113 checkAndClearExceptionFromCallback(env, __FUNCTION__);
114 return 0;
115}
116
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700117static void android_server_UsbHostManager_monitorUsbHostBus(JNIEnv* /* env */, jobject thiz)
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500118{
119 struct usb_host_context* context = usb_host_init();
120 if (!context) {
Steve Block3762c312012-01-06 19:20:56 +0000121 ALOGE("usb_host_init failed");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500122 return;
123 }
124 // this will never return so it is safe to pass thiz directly
125 usb_host_run(context, usb_device_added, usb_device_removed, NULL, (void *)thiz);
126}
127
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700128static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,
Paul McLean513160f2017-10-19 14:08:12 -0600129 jstring deviceAddress)
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500130{
Paul McLean513160f2017-10-19 14:08:12 -0600131 const char *deviceAddressStr = env->GetStringUTFChars(deviceAddress, NULL);
132 struct usb_device* device = usb_device_open(deviceAddressStr);
133 env->ReleaseStringUTFChars(deviceAddress, deviceAddressStr);
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500134
135 if (!device)
136 return NULL;
137
138 int fd = usb_device_get_fd(device);
Henrik Baard9bd36ef2013-07-09 15:14:23 +0200139 if (fd < 0) {
140 usb_device_close(device);
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500141 return NULL;
Henrik Baard9bd36ef2013-07-09 15:14:23 +0200142 }
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500143 int newFD = dup(fd);
144 usb_device_close(device);
145
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700146 jobject fileDescriptor = jniCreateFileDescriptor(env, newFD);
147 if (fileDescriptor == NULL) {
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500148 return NULL;
149 }
150 return env->NewObject(gParcelFileDescriptorOffsets.mClass,
151 gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
152}
153
Daniel Micay76f6a862015-09-19 17:31:01 -0400154static const JNINativeMethod method_table[] = {
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400155 { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus },
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500156 { "nativeOpenDevice", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400157 (void*)android_server_UsbHostManager_openDevice },
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500158};
159
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400160int register_android_server_UsbHostManager(JNIEnv *env)
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500161{
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400162 jclass clazz = env->FindClass("com/android/server/usb/UsbHostManager");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500163 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000164 ALOGE("Can't find com/android/server/usb/UsbHostManager");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500165 return -1;
166 }
Paul McLean513160f2017-10-19 14:08:12 -0600167 method_usbDeviceAdded =
168 env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;II[B)Z");
169 if (method_usbDeviceAdded == NULL) {
Mike Lockwood7531aa22014-01-13 10:31:01 -0800170 ALOGE("Can't find beginUsbDeviceAdded");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500171 return -1;
172 }
Mike Lockwood7531aa22014-01-13 10:31:01 -0800173 method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved",
174 "(Ljava/lang/String;)V");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500175 if (method_usbDeviceRemoved == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000176 ALOGE("Can't find usbDeviceRemoved");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500177 return -1;
178 }
179
Brian Carlstrom46e18c112011-04-05 22:44:45 -0700180 clazz = env->FindClass("android/os/ParcelFileDescriptor");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500181 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
182 gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
Mike Lockwood7531aa22014-01-13 10:31:01 -0800183 gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>",
184 "(Ljava/io/FileDescriptor;)V");
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500185 LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
186 "Unable to find constructor for android.os.ParcelFileDescriptor");
187
Mike Lockwood46d0adf2011-05-26 10:27:39 -0400188 return jniRegisterNativeMethods(env, "com/android/server/usb/UsbHostManager",
Mike Lockwoode7d511e2010-12-30 13:39:37 -0500189 method_table, NELEM(method_table));
190}
191
192};