From 20dd5e0a6a8e2f78edb6de011861318b9bf8d5e1 Mon Sep 17 00:00:00 2001 From: Ivan Kol Date: Sat, 11 Apr 2026 20:21:18 +0300 Subject: [PATCH 1/2] Fixed AndroidPort: SerialPort.class.getDeclaredConstructor() requires 9 parameters instead of 8 In SerialPort: Skip "su/chmod" when androidPort is already set (USB serial path handles open itself) Added constructor SerialPort() with 8 parameters for backward-compatibility. Changed tag to 8 for successful compilation with recent JDK --- pom.xml | 2 +- src/main/java/com/fazecast/jSerialComm/SerialPort.java | 7 ++++++- .../com/fazecast/jSerialComm/android/AndroidPort.java | 8 +++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 608b6b13..ce68f93b 100644 --- a/pom.xml +++ b/pom.xml @@ -66,7 +66,7 @@ default-compile - 6 + 8 false module-info.java diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPort.java b/src/main/java/com/fazecast/jSerialComm/SerialPort.java index 1daf5f0e..1f374690 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPort.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPort.java @@ -608,7 +608,8 @@ public final boolean openPort(int safetySleepTime, int deviceSendQueueSize, int try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); } // If this is an Android root application, we must explicitly allow serial port access to the library - File portFile = isAndroidDelete ? new File(comPort) : null; + // Skip su/chmod when androidPort is already set (USB serial path handles open itself) + File portFile = (isAndroidDelete && androidPort == null) ? new File(comPort) : null; if (portFile != null && (!portFile.canRead() || !portFile.canWrite())) { Process process = null; @@ -1130,6 +1131,10 @@ public final boolean setDTRandRTS(boolean dtr, boolean rts) // SerialPort Constructors private SerialPort() {} + private SerialPort(String port, String friendly, String description, String location, String serial, String manufacture, int vid, int pid) + { + this(port, friendly, description, location, serial, manufacture, "", vid, pid); + } private SerialPort(String port, String friendly, String description, String location, String serial, String manufacture, String driver, int vid, int pid) { comPort = port; diff --git a/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java b/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java index 93ab4d2b..4cf2f96e 100644 --- a/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java +++ b/src/main/java/com/fazecast/jSerialComm/android/AndroidPort.java @@ -147,15 +147,17 @@ public static SerialPort[] getCommPortsNative() AndroidPort androidPort = null; Constructor serialPortConstructor = - SerialPort.class.getDeclaredConstructor(String.class, String.class, String.class, String.class, String.class, int.class, int.class); + SerialPort.class.getDeclaredConstructor(String.class, String.class, String.class, String.class, String.class, String.class, String.class, int.class, int.class); serialPortConstructor.setAccessible(true); SerialPort serialPort = serialPortConstructor.newInstance( "COM" + (ports.size() + 1), - device.getDeviceName(), device.getProductName(), + device.getProductName(), + device.getDeviceName(), device.getSerialNumber(), - device.getSerialNumber(), + device.getManufacturerName(), + "", device.getVendorId(), device.getProductId() ); From 8503d4fea38610b999a6b80adfbd21a4bae85e3b Mon Sep 17 00:00:00 2001 From: Ivan Kol Date: Mon, 17 Aug 2026 14:25:12 +0300 Subject: [PATCH 2/2] SerialPort: robust Android detection via java.vm.name Dalvik; add android.override escape hatch to skip native lib loading - isAndroid detection now also checks java.vm.name='Dalvik' so OEM Android devices where java.vm.vendor doesn't contain 'android' still take the Android library path. - Added jSerialComm.android.override system property: when set to 'true' before class load, the entire native library loading block is skipped. Android host apps that manage USB Host access themselves (e.g. via setAndroidContext + reflection) can set this property to avoid the boot-time UnsatisfiedLinkError caused by version-mismatched or inaccessible system libjSerialComm.so files on Android POS terminals. --- .../com/fazecast/jSerialComm/SerialPort.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPort.java b/src/main/java/com/fazecast/jSerialComm/SerialPort.java index 1f374690..60e0a150 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPort.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPort.java @@ -123,7 +123,14 @@ public class SerialPort cleanUpDirectory(new File(userHomeDirectory, "..")); // Determine Operating System and architecture - if (System.getProperty("java.vm.vendor", "").toLowerCase().contains("android")) + // Check multiple Java system properties for Android detection to handle OEM builds where + // java.vm.vendor does not contain "android" (e.g. some MediaTek/Qualcomm Android POS devices). + // java.vm.name is "Dalvik" on all standard Android runtimes regardless of OEM customization. + final boolean isAndroidRuntime = + System.getProperty("java.vm.vendor", "").toLowerCase().contains("android") || + System.getProperty("java.vm.name", "").toLowerCase().contains("dalvik") || + System.getProperty("java.vendor", "").toLowerCase().contains("android"); + if (isAndroidRuntime) { isAndroidDelete = true; libraryPath = "Android"; @@ -185,8 +192,15 @@ else if (arch.contains("86") || arch.contains("amd")) System.exit(-1); } - // Load platform-specific binaries for non-Android systems - if (!isAndroid) + // Load platform-specific binaries for non-Android systems. + // When running inside an Android app that manages USB Host access itself, the host + // sets jSerialComm.android.override=true before this class is loaded so that native + // library loading (which would fail on Android due to path and version constraints) + // is skipped entirely. The host app then calls setAndroidContext() and sets + // isAndroid=true via reflection to activate the USB Host API path. + final boolean androidOverride = isAndroidRuntime && + System.getProperty("jSerialComm.android.override", "false").equalsIgnoreCase("true"); + if (!isAndroid && !androidOverride) { // Attempt to load from a manually-specified user location boolean libraryLoaded = false;