jiegec / usbip

A Rust library to run a USB/IP server
MIT License
278 stars 26 forks source link

add support for android no-rusb-open workaround #48

Open brandonros opened 8 months ago

brandonros commented 8 months ago

Let me know your thoughts.

use std::ffi::c_int;

use rusb::{GlobalContext, DeviceHandle, UsbContext};

pub fn libusb_init_from_fd(fd: i32) -> Option<DeviceHandle<GlobalContext>> {
    log::info!("libusb_init_from_fd fd = {fd}");
    // android workaround
    #[cfg(target_os = "android")]
    let _ = rusb::disable_device_discovery();
    // fd -> device_handle
    let global_context = GlobalContext::default();
    let libusb_context = global_context.as_raw();
    let mut fd_handle = std::ptr::null_mut();
    let ret_val = unsafe { libusb1_sys::libusb_wrap_sys_device(libusb_context, fd as *mut c_int, &mut fd_handle) };
    if ret_val != 0 {
        log::error!("libusb_wrap_sys_device failed ret_val = {ret_val}");
        return None;
    }
    let handle_ptr = std::ptr::NonNull::new(fd_handle).unwrap();
    let device_handle = unsafe { DeviceHandle::from_libusb(global_context, handle_ptr) };
    // return
    Some(device_handle)
}

#[no_mangle]
unsafe extern "C" fn libusb_init_from_fd_wrapper(fd: i32) {
    log::info!("libusb_init_from_fd_wrapper fd = {fd}");
    // do custom android libusb init
    let device_handle = usb::libusb_init_from_fd(fd).unwrap();
    // create tokio runtime
    let runtime = tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .unwrap();
    // spawn usbip server on thread
    let _handle = std::thread::spawn(move || {
        let server = Arc::new(usbip::UsbIpServer::new_from_device_handle(device_handle));
        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 3240);
        let _ = runtime.block_on(usbip::server(addr, server));
    });
}

Rust library that provides JNI for Java to call:

#[no_mangle]
pub extern "C" fn Java_com_redacted_redacted_RemoterWrapperLib_StartUsbIpHost(_env: JNIEnv, _obj: JObject) {
    // load library which has extra libusb_init_from_fd_wrapper export added to it
    let driver_filename = DRIVER_FILENAME.get().unwrap();
    let library = Library::load(&driver_filename).unwrap();
    // call libusb_init_from_fd_wrapper
    let fd = USB_DEVICE_FD.get().unwrap();
    let libusb_init_from_fd_wrapper: LibusbInitFromFdWrapperFn = unsafe { library.sym("libusb_init_from_fd_wrapper\0").unwrap() };
    unsafe {
        libusb_init_from_fd_wrapper(*fd);
    }
}