From 94292c981d2909577ec0d7719eed75a934280c81 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Sat, 27 Nov 2021 14:11:01 +0100 Subject: [PATCH 1/6] UsbAPI: print more information when listing devices termux-usb -l now returns something like: [ { "device_name": "/dev/bus/usb/001/004", "device_id": 1004, "vendor_id": "0x0a12", "product_id": "0x0001", "device_class": "224 - Wireless controller device", "device_sub_class": 1, "manufacturer_name": null, "device_protocol": 1, "product_name": "CSR8510 A10", "serial_number": null, "configurations": 1, "descriptor_type": 0, "access_granted": false }, { "device_name": "/dev/bus/usb/001/003", "device_id": 1003, "vendor_id": "0x0bda", "product_id": "0x8153", "device_class": "0 - Usb class is determined on a per-interface basis", "device_sub_class": 0, "manufacturer_name": "Realtek", "device_protocol": 0, "product_name": "USB 10/100/1000 LAN", "serial_number": "000000100000", "configurations": 2, "descriptor_type": 0, "access_granted": false } ] --- .../main/java/com/termux/api/apis/UsbAPI.java | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/termux/api/apis/UsbAPI.java b/app/src/main/java/com/termux/api/apis/UsbAPI.java index 667ba1793..b99001d12 100644 --- a/app/src/main/java/com/termux/api/apis/UsbAPI.java +++ b/app/src/main/java/com/termux/api/apis/UsbAPI.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; @@ -84,13 +85,65 @@ public void writeResult(PrintWriter out) { private static void listDevices(final Context context, JsonWriter out) throws IOException { final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); HashMap deviceList = usbManager.getDeviceList(); - Iterator deviceIterator = deviceList.keySet().iterator(); out.beginArray(); - while (deviceIterator.hasNext()) { - out.value(deviceIterator.next()); + for (UsbDevice device : deviceList.values()) { + out.beginObject(); + out.name("device_name").value(device.getDeviceName()); + out.name("device_id").value(device.getDeviceId()); + out.name("vendor_id").value(String.format("0x%04x", device.getVendorId())); + out.name("product_id").value(String.format("0x%04x", device.getProductId())); + out.name("device_class").value(device.getDeviceClass()+" - "+translateDeviceClass(device.getDeviceClass())); + out.name("device_sub_class").value(device.getDeviceSubclass()); + out.name("manufacturer_name").value(device.getManufacturerName()); + out.name("device_protocol").value(device.getDeviceProtocol()); + out.name("product_name").value(device.getProductName()); + out.name("serial_number").value(device.getSerialNumber()); + out.name("configurations").value(device.getConfigurationCount()); + out.name("descriptor_type").value(device.describeContents()); + out.name("access_granted").value(usbManager.hasPermission(device)); + out.endObject(); } out.endArray(); } + private static String translateDeviceClass(int usbClass){ + switch(usbClass){ + case UsbConstants.USB_CLASS_APP_SPEC: + return "App specific USB class"; + case UsbConstants.USB_CLASS_AUDIO: + return "Audio device"; + case UsbConstants.USB_CLASS_CDC_DATA: + return "CDC device (communications device class)"; + case UsbConstants.USB_CLASS_COMM: + return "Communication device"; + case UsbConstants.USB_CLASS_CONTENT_SEC: + return "Content security device"; + case UsbConstants.USB_CLASS_CSCID: + return "Content smart card device"; + case UsbConstants.USB_CLASS_HID: + return "Human interface device (for example a keyboard)"; + case UsbConstants.USB_CLASS_HUB: + return "USB hub"; + case UsbConstants.USB_CLASS_MASS_STORAGE: + return "Mass storage device"; + case UsbConstants.USB_CLASS_MISC: + return "Wireless miscellaneous devices"; + case UsbConstants.USB_CLASS_PER_INTERFACE: + return "Usb class is determined on a per-interface basis"; + case UsbConstants.USB_CLASS_PHYSICA: + return "Physical device"; + case UsbConstants.USB_CLASS_PRINTER: + return "Printer"; + case UsbConstants.USB_CLASS_STILL_IMAGE: + return "Still image devices (digital cameras)"; + case UsbConstants.USB_CLASS_VENDOR_SPEC: + return "Vendor specific USB class"; + case UsbConstants.USB_CLASS_VIDEO: + return "Video device"; + case UsbConstants.USB_CLASS_WIRELESS_CONTROLLER: + return "Wireless controller device"; + default: return "Unknown USB class!"; + } + } private static UsbDevice getDevice(final TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { String deviceName = intent.getStringExtra("device"); From f6c414653163b491298e3a7117c38cd442af5026 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Sat, 27 Nov 2021 15:46:35 +0100 Subject: [PATCH 2/6] ResultReturner,usbAPI: minor spacing fixes Lets be consistent in how we put spaces. --- app/src/main/java/com/termux/api/apis/UsbAPI.java | 5 +---- .../java/com/termux/api/util/ResultReturner.java | 12 ++++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/termux/api/apis/UsbAPI.java b/app/src/main/java/com/termux/api/apis/UsbAPI.java index b99001d12..695443f70 100644 --- a/app/src/main/java/com/termux/api/apis/UsbAPI.java +++ b/app/src/main/java/com/termux/api/apis/UsbAPI.java @@ -73,13 +73,11 @@ public void writeResult(PrintWriter out) { } else out.append("No permission\n"); } }); - break; default: ResultReturner.returnData(apiReceiver, intent, out -> out.append("Invalid action\n")); } } - } private static void listDevices(final Context context, JsonWriter out) throws IOException { @@ -184,7 +182,6 @@ public void onReceive(final Context usbContext, final Intent usbIntent) { if (looper != null) looper.quit(); } } - } } }; @@ -201,7 +198,7 @@ public void onReceive(final Context usbContext, final Intent usbIntent) { private static boolean getPermission(final @NonNull UsbDevice device, final Context context, final Intent intent) { boolean request = intent.getBooleanExtra("request", false); - if(request) { + if (request) { return requestPermission(device, context); } else { return hasPermission(device, context); diff --git a/app/src/main/java/com/termux/api/util/ResultReturner.java b/app/src/main/java/com/termux/api/util/ResultReturner.java index 4ae93f097..8600950cd 100644 --- a/app/src/main/java/com/termux/api/util/ResultReturner.java +++ b/app/src/main/java/com/termux/api/util/ResultReturner.java @@ -57,19 +57,19 @@ public void setInput(InputStream inputStream) throws Exception { this.in = inputStream; } } - + /** * Possible subclass of {@link ResultWriter} when the output is binary data instead of text. */ public static abstract class BinaryOutput implements ResultWriter { private OutputStream out; - + public void setOutput(OutputStream outputStream) { this.out = outputStream; } - + public abstract void writeResult(OutputStream out) throws Exception; - + /** * writeResult with a PrintWriter is marked as final and overwritten, so you don't accidentally use it */ @@ -178,7 +178,7 @@ public static void returnData(Object context, final Intent intent, final ResultW } else { resultWriter.writeResult(writer); } - if(resultWriter instanceof WithAncillaryFd) { + if (resultWriter instanceof WithAncillaryFd) { int fd = ((WithAncillaryFd) resultWriter).getFd(); if (fd >= 0) { pfds[0] = ParcelFileDescriptor.adoptFd(fd); @@ -188,7 +188,7 @@ public static void returnData(Object context, final Intent intent, final ResultW } } - if(pfds[0] != null) { + if (pfds[0] != null) { pfds[0].close(); } From 49967b06eb06e69d8d82669c1e7e21212923bd63 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Sun, 28 Nov 2021 10:40:36 +0100 Subject: [PATCH 3/6] UsbAPI: add option to open device based on vendor and productId So we can either pass `--es device /dev/bus/usb/001/003`, or `--es vendorId 0x0403 --es productId 0x6001`. --- .../main/java/com/termux/api/apis/UsbAPI.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/termux/api/apis/UsbAPI.java b/app/src/main/java/com/termux/api/apis/UsbAPI.java index 695443f70..6e4705c37 100644 --- a/app/src/main/java/com/termux/api/apis/UsbAPI.java +++ b/app/src/main/java/com/termux/api/apis/UsbAPI.java @@ -11,6 +11,7 @@ import android.hardware.usb.UsbManager; import android.os.Looper; import android.util.JsonWriter; +import android.util.Log; import android.util.SparseArray; import com.termux.api.TermuxApiReceiver; @@ -145,11 +146,33 @@ private static String translateDeviceClass(int usbClass){ private static UsbDevice getDevice(final TermuxApiReceiver apiReceiver, final Context context, final Intent intent) { String deviceName = intent.getStringExtra("device"); + String vendorId = intent.getStringExtra("vendorId"); + String productId = intent.getStringExtra("productId"); + if (deviceName == null && (vendorId == null || productId == null)) { + Log.e(LOG_TAG, "Missing usb device info in open()"); + ResultReturner.returnData(apiReceiver, intent, out -> out.append("Need either usbfs path or vendorId+productId\n")); + return null; + } + final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); HashMap deviceList = usbManager.getDeviceList(); - UsbDevice device = deviceList.get(deviceName); + UsbDevice device = null; + if (deviceName != null) { + device = deviceList.get(deviceName); + } else { + for (UsbDevice dev : deviceList.values()) { + Log.d(LOG_TAG, "Comparing "+dev.getDeviceName()+" with given vendorId and productId"); + if (String.format("0x%04x", dev.getVendorId()).equalsIgnoreCase(vendorId) && + String.format("0x%04x", dev.getProductId()).equalsIgnoreCase(productId)) { + device = dev; + break; + } + } + } if (device == null) { ResultReturner.returnData(apiReceiver, intent, out -> out.append("No such device\n")); + } else { + Log.i(LOG_TAG, "Found matching device at "+device.getDeviceName()); } return device; } From c4f86bdffe4d24e3a637e52521c51a01bd518a91 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Wed, 8 Dec 2021 21:28:42 +0100 Subject: [PATCH 4/6] UsbAPI: fix indentation --- .../main/java/com/termux/api/apis/UsbAPI.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/termux/api/apis/UsbAPI.java b/app/src/main/java/com/termux/api/apis/UsbAPI.java index 6e4705c37..ddc889920 100644 --- a/app/src/main/java/com/termux/api/apis/UsbAPI.java +++ b/app/src/main/java/com/termux/api/apis/UsbAPI.java @@ -61,19 +61,19 @@ public void writeJson(JsonWriter out) throws Exception { device = getDevice(apiReceiver, context, intent); if (device == null) return; ResultReturner.returnData(apiReceiver, intent, new ResultReturner.WithAncillaryFd() { - @Override - public void writeResult(PrintWriter out) { - if (getPermission(device, context, intent)) { - int result = open(device, context); - if (result < 0) { - out.append("Failed to open device\n"); - } else { - this.setFd(result); - out.append("@"); // has to be non-empty - } - } else out.append("No permission\n"); + @Override + public void writeResult(PrintWriter out) { + if (getPermission(device, context, intent)) { + int result = open(device, context); + if (result < 0) { + out.append("Failed to open device\n"); + } else { + this.setFd(result); + out.append("@"); // has to be non-empty } - }); + } else out.append("No permission\n"); + } + }); break; default: ResultReturner.returnData(apiReceiver, intent, out -> out.append("Invalid action\n")); From 53f8205520b03bc59903106c161948bf210cabe6 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Mon, 3 Jan 2022 09:48:07 +0100 Subject: [PATCH 5/6] UsbAPI: strip null chars from manufacturer and product name Apparently some devices have fixed length fields, are extra nulls at the end. This makes parsing the output slightly more annoying in termux so strip them on the java side. Before termux-usb -l could return something like: [ { "device_name": "/dev/bus/usb/002/006", "device_id": 2006, "vendor_id": "0x316d", "product_id": "0x4c4b", "device_class": "0 - Usb class is determined on a per-interface basis", "device_sub_class": 0, "manufacturer_name": "Purism, SPC\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", "device_protocol": 0, "product_name": "Librem Key\u0000\u0000\u0000\u0000\u0000\u0000\u0000", "serial_number": "00000000000000000000AB62", "configurations": 1, "descriptor_type": 0, "access_granted": false } ] and now we remove all \u0000. --- app/src/main/java/com/termux/api/apis/UsbAPI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/termux/api/apis/UsbAPI.java b/app/src/main/java/com/termux/api/apis/UsbAPI.java index ddc889920..5b86caa07 100644 --- a/app/src/main/java/com/termux/api/apis/UsbAPI.java +++ b/app/src/main/java/com/termux/api/apis/UsbAPI.java @@ -93,9 +93,9 @@ private static void listDevices(final Context context, JsonWriter out) throws IO out.name("product_id").value(String.format("0x%04x", device.getProductId())); out.name("device_class").value(device.getDeviceClass()+" - "+translateDeviceClass(device.getDeviceClass())); out.name("device_sub_class").value(device.getDeviceSubclass()); - out.name("manufacturer_name").value(device.getManufacturerName()); + out.name("manufacturer_name").value(device.getManufacturerName().replace("\u0000", "")); out.name("device_protocol").value(device.getDeviceProtocol()); - out.name("product_name").value(device.getProductName()); + out.name("product_name").value(device.getProductName().replace("\u0000", "")); out.name("serial_number").value(device.getSerialNumber()); out.name("configurations").value(device.getConfigurationCount()); out.name("descriptor_type").value(device.describeContents()); From 09999fb2b61d88ccadd23b9149dd84b7105baac4 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Mon, 3 Jan 2022 15:48:45 +0100 Subject: [PATCH 6/6] UsbAPI: sort cases alphabetically --- .../main/java/com/termux/api/apis/UsbAPI.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/termux/api/apis/UsbAPI.java b/app/src/main/java/com/termux/api/apis/UsbAPI.java index 5b86caa07..42a6293bc 100644 --- a/app/src/main/java/com/termux/api/apis/UsbAPI.java +++ b/app/src/main/java/com/termux/api/apis/UsbAPI.java @@ -49,14 +49,6 @@ public void writeJson(JsonWriter out) throws Exception { } }); break; - case "permission": - device = getDevice(apiReceiver, context, intent); - if (device == null) return; - ResultReturner.returnData(apiReceiver, intent, out -> { - boolean result = getPermission(device, context, intent); - out.append(result ? "yes\n" : "no\n"); - }); - break; case "open": device = getDevice(apiReceiver, context, intent); if (device == null) return; @@ -75,6 +67,14 @@ public void writeResult(PrintWriter out) { } }); break; + case "permission": + device = getDevice(apiReceiver, context, intent); + if (device == null) return; + ResultReturner.returnData(apiReceiver, intent, out -> { + boolean result = getPermission(device, context, intent); + out.append(result ? "yes\n" : "no\n"); + }); + break; default: ResultReturner.returnData(apiReceiver, intent, out -> out.append("Invalid action\n")); }