From: Marcus Comstedt Date: Sun, 27 Nov 2016 15:05:01 +0000 (+0100) Subject: sigrok-cross-android: Patch libusb to use Java helpers for enumeration X-Git-Url: https://sigrok.org/gitweb/?p=sigrok-util.git;a=commitdiff_plain;h=c8cf030a21c58846a0e5a1d5f276599c709bf737 sigrok-cross-android: Patch libusb to use Java helpers for enumeration In newer Android versions, the native enumeration code used by libusb does not work anymore due to the necessary virtual file system nodes not being available to user processes. Therefore, Java helper code is now needed for enumeration as well. This fixes parts of bug #701. --- diff --git a/cross-compile/android/libusb-1.0.patch b/cross-compile/android/libusb-1.0.patch index 4e5aeac..27070e6 100644 --- a/cross-compile/android/libusb-1.0.patch +++ b/cross-compile/android/libusb-1.0.patch @@ -16,10 +16,9 @@ diff -urp libusb-1.0.9.orig/libusb/io.c libusb-1.0.9/libusb/io.c /** * \page io Synchronous and asynchronous device I/O * -diff -urp libusbx-1.0.17.orig/libusb/os/linux_usbfs.c libusbx-1.0.17/libusb/os/linux_usbfs.c ---- libusbx-1.0.17.orig/libusb/os/linux_usbfs.c 2014-07-05 23:14:45.487803220 +0200 -+++ libusbx-1.0.17/libusb/os/linux_usbfs.c 2014-07-06 16:42:17.013481236 +0200 -@@ -37,11 +37,21 @@ +--- libusb-1.0.19.orig/libusb/os/linux_usbfs.c 2014-05-30 11:18:28.000000000 +0200 ++++ libusb-1.0.19/libusb/os/linux_usbfs.c 2016-11-26 15:38:21.199383120 +0100 +@@ -37,11 +37,31 @@ #include #include #include @@ -34,14 +33,24 @@ diff -urp libusbx-1.0.17.orig/libusb/os/linux_usbfs.c libusbx-1.0.17/libusb/os/l +#ifdef __ANDROID__ +static JavaVM *g_jvm = NULL; +static jclass usb_helper_class; ++static jclass usb_event_listener_class; +static jmethodID usb_helper_open_mid; ++static jmethodID usb_helper_start_event_monitor_mid; ++static jmethodID usb_helper_stop_event_monitor_mid; ++static jmethodID usb_helper_scan_devices_mid; ++static jmethodID usb_event_listener_init_mid; +static int usb_helper_open(const char *pathname, int flags); ++static int usb_helper_start_event_monitor(void); ++static int usb_helper_stop_event_monitor(void); ++static int usb_helper_scan_devices (struct libusb_context *ctx); ++static void usb_helper_hotplug_poll(void); ++static void usb_helper_on_usb_device_action(JNIEnv *env, jobject self, jstring name, jboolean removed); +#endif + /* sysfs vs usbfs: * opening a usbfs node causes the device to be resumed, so we attempt to * avoid this during enumeration. -@@ -192,6 +202,11 @@ +@@ -193,6 +213,11 @@ snprintf(path, PATH_MAX, "%s/%03d/%03d", usbfs_path, dev->bus_number, dev->device_address); @@ -53,7 +62,78 @@ diff -urp libusbx-1.0.17.orig/libusb/os/linux_usbfs.c libusbx-1.0.17/libusb/os/l fd = open(path, mode); if (fd != -1) return fd; /* Success */ -@@ -2603,3 +2618,79 @@ +@@ -369,6 +394,13 @@ + struct stat statbuf; + int r; + ++#ifdef __ANDROID__ ++ if (g_jvm) { ++ usbfs_path = "/dev/bus/usb"; ++ sysfs_can_relate_devices = 0; ++ sysfs_has_descriptors = 0; ++ } else ++#endif + usbfs_path = find_usbfs_path(); + if (!usbfs_path) { + usbi_err(ctx, "could not find usbfs"); +@@ -467,6 +499,10 @@ + + static int linux_start_event_monitor(void) + { ++#ifdef __ANDROID__ ++ if (g_jvm) ++ return usb_helper_start_event_monitor(); ++#endif + #if defined(USE_UDEV) + return linux_udev_start_event_monitor(); + #else +@@ -476,6 +512,10 @@ + + static int linux_stop_event_monitor(void) + { ++#ifdef __ANDROID__ ++ if (g_jvm) ++ return usb_helper_stop_event_monitor(); ++#endif + #if defined(USE_UDEV) + return linux_udev_stop_event_monitor(); + #else +@@ -489,6 +529,11 @@ + + usbi_mutex_static_lock(&linux_hotplug_lock); + ++#ifdef __ANDROID__ ++ if (g_jvm) ++ ret = usb_helper_scan_devices(ctx); ++ else ++#endif + #if defined(USE_UDEV) + ret = linux_udev_scan_devices(ctx); + #else +@@ -502,6 +547,11 @@ + + static void op_hotplug_poll(void) + { ++#ifdef __ANDROID__ ++ if (g_jvm) ++ usb_helper_hotplug_poll(); ++ else ++#endif + #if defined(USE_UDEV) + linux_udev_hotplug_poll(); + #else +@@ -994,6 +1044,10 @@ + /* XXX -- can we figure out the topology when using usbfs? */ + if (NULL == sysfs_dir || 0 == strncmp(sysfs_dir, "usb", 3)) { + /* either using usbfs or finding the parent of a root hub */ ++#ifdef __ANDROID__ ++ if (g_jvm) ++ dev->port_number = dev->device_address; ++#endif + return LIBUSB_SUCCESS; + } + +@@ -2693,3 +2747,262 @@ .transfer_priv_size = sizeof(struct linux_transfer_priv), .add_iso_packet_size = 0, }; @@ -61,6 +141,12 @@ diff -urp libusbx-1.0.17.orig/libusb/os/linux_usbfs.c libusbx-1.0.17/libusb/os/l +#ifdef __ANDROID__ +jint JNI_OnLoad(JavaVM *vm, void *reserved) +{ ++ static JNINativeMethod jni_method = { ++ "onUsbDeviceAction", ++ "(Ljava/lang/String;Z)V", ++ (void*)usb_helper_on_usb_device_action ++ }; ++ + JNIEnv* env; + g_jvm = vm; + if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_6) != JNI_OK) { @@ -68,15 +154,34 @@ diff -urp libusbx-1.0.17.orig/libusb/os/linux_usbfs.c libusbx-1.0.17/libusb/os/l + } + + jclass helper = (*env)->FindClass(env, "org/sigrok/androidutils/UsbHelper"); ++ jclass event_listener = (*env)->FindClass(env, "org/sigrok/androidutils/UsbEventListenerStub"); + -+ if (helper) { ++ if (helper && event_listener) { + + usb_helper_class = (jclass)(*env)->NewGlobalRef(env, helper); + + usb_helper_open_mid = (*env)->GetStaticMethodID(env, helper, "open", + "(Ljava/lang/String;I)I"); ++ usb_helper_start_event_monitor_mid = (*env)->GetStaticMethodID(env, helper, "startEventMonitor", ++ "(Lorg/sigrok/androidutils/UsbEventListener;)V"); ++ usb_helper_stop_event_monitor_mid = (*env)->GetStaticMethodID(env, helper, "stopEventMonitor", ++ "()V"); ++ usb_helper_scan_devices_mid = (*env)->GetStaticMethodID(env, helper, "scanDevices", ++ "()[Ljava/lang/String;"); + (*env)->DeleteLocalRef(env, helper); + ++ usb_event_listener_class = (jclass)(*env)->NewGlobalRef(env, event_listener); ++ usb_event_listener_init_mid = (*env)->GetMethodID(env, event_listener, "", ++ "()V"); ++ if ((*env)->RegisterNatives(env, event_listener, &jni_method, 1) < 0) { ++ if ((*env)->ExceptionCheck(env)) { ++ (*env)->ExceptionClear(env); ++ } ++ g_jvm = NULL; ++ } ++ ++ (*env)->DeleteLocalRef(env, event_listener); ++ + } else { + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); @@ -95,9 +200,15 @@ diff -urp libusbx-1.0.17.orig/libusb/os/linux_usbfs.c libusbx-1.0.17/libusb/os/l + } + + jclass helper = usb_helper_class; ++ jclass event_listener = usb_event_listener_class; + usb_helper_class = NULL; ++ usb_event_listener_class = NULL; + if (helper) + (*env)->DeleteGlobalRef(env, helper); ++ if (event_listener) { ++ (*env)->UnregisterNatives(env, event_listener); ++ (*env)->DeleteGlobalRef(env, event_listener); ++ } + g_jvm = NULL; +} + @@ -130,6 +241,158 @@ diff -urp libusbx-1.0.17.orig/libusb/os/linux_usbfs.c libusbx-1.0.17/libusb/os/l + (*g_jvm)->DetachCurrentThread(g_jvm); + } + ++ if (res >= 0) { ++ /* Rewind so that descriptors can be read */ ++ lseek(res, SEEK_SET, 0); ++ } ++ ++ return res; ++} ++ ++static int usb_helper_start_event_monitor(void) ++{ ++ JNIEnv* env; ++ jint st; ++ int do_detach = 0; ++ int res = 0; ++ jobject usb_event_listener; ++ ++ if (g_jvm == NULL) { ++ return LIBUSB_ERROR_OTHER; ++ } ++ st = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); ++ ++ if (st == JNI_EDETACHED) { ++ st = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); ++ do_detach = 1; ++ } ++ ++ if (st != JNI_OK) { ++ return LIBUSB_ERROR_OTHER; ++ } ++ ++ usb_event_listener = (*env)->NewObject(env, usb_event_listener_class, usb_event_listener_init_mid); ++ if (usb_event_listener == NULL) ++ res = LIBUSB_ERROR_OTHER; ++ else { ++ (*env)->CallStaticVoidMethod(env, usb_helper_class, usb_helper_start_event_monitor_mid, usb_event_listener); ++ (*env)->DeleteLocalRef(env, usb_event_listener); ++ } ++ ++ if (do_detach) { ++ (*g_jvm)->DetachCurrentThread(g_jvm); ++ } ++ ++ return res; ++} ++ ++static int usb_helper_stop_event_monitor(void) ++{ ++ JNIEnv* env; ++ jint st; ++ int do_detach = 0; ++ ++ if (g_jvm == NULL) { ++ return LIBUSB_ERROR_OTHER; ++ } ++ st = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); ++ ++ if (st == JNI_EDETACHED) { ++ st = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); ++ do_detach = 1; ++ } ++ ++ if (st != JNI_OK) { ++ return LIBUSB_ERROR_OTHER; ++ } ++ ++ (*env)->CallStaticVoidMethod(env, usb_helper_class, usb_helper_stop_event_monitor_mid); ++ ++ if (do_detach) { ++ (*g_jvm)->DetachCurrentThread(g_jvm); ++ } ++ ++ return 0; ++} ++ ++static int usb_helper_scan_devices (struct libusb_context *ctx) ++{ ++ JNIEnv* env; ++ int res = 0; ++ jint st; ++ int do_detach = 0; ++ ++ if (g_jvm == NULL) { ++ return LIBUSB_ERROR_OTHER; ++ } ++ st = (*g_jvm)->GetEnv(g_jvm, (void **)&env, JNI_VERSION_1_6); ++ ++ if (st == JNI_EDETACHED) { ++ st = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); ++ do_detach = 1; ++ } ++ ++ if (st != JNI_OK) { ++ return LIBUSB_ERROR_OTHER; ++ } ++ ++ jobject arr = (*env)->CallStaticObjectMethod(env, usb_helper_class, usb_helper_scan_devices_mid); ++ ++ if (arr == NULL) ++ res = LIBUSB_ERROR_OTHER; ++ else { ++ jsize i, len = (*env)->GetArrayLength(env, arr); ++ for (i=0; iGetObjectArrayElement(env, arr, i); ++ if (str) { ++ const char *ustr = (*env)->GetStringUTFChars(env, str, NULL); ++ if (ustr) { ++ unsigned busnum, devaddr; ++ if (2 != sscanf(ustr, "/dev/bus/usb/%u/%u", ++ &busnum, &devaddr) || ++ linux_enumerate_device(ctx, busnum, devaddr, NULL)) { ++ usbi_dbg("failed to enumerate device %s", ustr); ++ } ++ (*env)->ReleaseStringUTFChars(env, str, ustr); ++ } else ++ res = LIBUSB_ERROR_OTHER; ++ (*env)->DeleteLocalRef(env, str); ++ } else ++ res = LIBUSB_ERROR_OTHER; ++ if (res) ++ break; ++ } ++ (*env)->DeleteLocalRef(env, arr); ++ } ++ ++ if (do_detach) { ++ (*g_jvm)->DetachCurrentThread(g_jvm); ++ } ++ + return res; +} ++ ++static void usb_helper_hotplug_poll(void) ++{ ++} ++ ++static void usb_helper_on_usb_device_action(JNIEnv *env, jobject self, jstring name, jboolean removed) ++{ ++ usbi_mutex_static_lock(&linux_hotplug_lock); ++ if (name) { ++ const char *ustr = (*env)->GetStringUTFChars(env, name, NULL); ++ if (ustr) { ++ unsigned busnum, devaddr; ++ if (2 == sscanf(ustr, "/dev/bus/usb/%u/%u", ++ &busnum, &devaddr)) { ++ if (removed) ++ linux_device_disconnected(busnum, devaddr, NULL); ++ else ++ linux_hotplug_enumerate(busnum, devaddr, NULL); ++ } ++ (*env)->ReleaseStringUTFChars(env, name, ustr); ++ } ++ } ++ usbi_mutex_static_unlock(&linux_hotplug_lock); ++} +#endif