From 9311b3a1aab18b0176e40dc6f5682995e9094ebb Mon Sep 17 00:00:00 2001 From: kai-morich Date: Fri, 18 Oct 2024 10:25:35 +0200 Subject: [PATCH] catch all Throwables from SerialInputOutputManager.Listener methods (#601) to avoid breaking Interface changes, Error from onNewData() is wrapped into Exception when calling onRunError() --- .../util/SerialInputOutputManager.java | 12 ++++- .../src/test/java/android/util/Log.java | 5 ++ .../util/SerialInputOutputManagerTest.java | 54 +++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java index f6ee3ca5..92a12756 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java @@ -203,7 +203,7 @@ public void run() { } step(); } - } catch (Exception e) { + } catch (Throwable e) { if(mSerialPort.isOpen()) { Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e); } else { @@ -211,7 +211,15 @@ public void run() { } final Listener listener = getListener(); if (listener != null) { - listener.onRunError(e); + try { + if (e instanceof Exception) { + listener.onRunError((Exception) e); + } else { + listener.onRunError(new Exception(e)); + } + } catch (Throwable t) { + Log.w(TAG, "Exception in onRunError: " + t.getMessage(), t); + } } } finally { synchronized (this) { diff --git a/usbSerialForAndroid/src/test/java/android/util/Log.java b/usbSerialForAndroid/src/test/java/android/util/Log.java index c7c87dad..b55d3a03 100644 --- a/usbSerialForAndroid/src/test/java/android/util/Log.java +++ b/usbSerialForAndroid/src/test/java/android/util/Log.java @@ -17,6 +17,11 @@ public static int w(String tag, String msg) { return 0; } + public static int w(String tag, String msg, Throwable tr) { + System.out.println("WARN: " + tag + ": " + msg + " / " + tr.getMessage()); + return 0; + } + public static int e(String tag, String msg) { System.out.println("ERROR: " + tag + ": " + msg); return 0; diff --git a/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java b/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java new file mode 100644 index 00000000..206aadc3 --- /dev/null +++ b/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java @@ -0,0 +1,54 @@ +package com.hoho.android.usbserial.util; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.hardware.usb.UsbEndpoint; +import android.os.Process; + +import com.hoho.android.usbserial.driver.CommonUsbSerialPort; + +import org.junit.Test; + +public class SerialInputOutputManagerTest { + + + // catch all Throwables in onNewData() and onRunError() + @Test + public void throwable() throws Exception { + + class ExceptionListener implements SerialInputOutputManager.Listener { + public Exception e; + @Override public void onNewData(byte[] data) { throw new RuntimeException("exception1"); } + @Override public void onRunError(Exception e) { this.e = e; throw new RuntimeException("exception2"); } + } + class ErrorListener implements SerialInputOutputManager.Listener { + public Exception e; + @Override public void onNewData(byte[] data) { throw new UnknownError("error1"); } + @Override public void onRunError(Exception e) { this.e = e; throw new UnknownError("error2");} + } + + UsbEndpoint readEndpoint = mock(UsbEndpoint.class); + when(readEndpoint.getMaxPacketSize()).thenReturn(16); + CommonUsbSerialPort port = mock(CommonUsbSerialPort.class); + when(port.getReadEndpoint()).thenReturn(readEndpoint); + when(port.read(new byte[16], 0)).thenReturn(1); + SerialInputOutputManager manager = new SerialInputOutputManager(port); + manager.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); + + ExceptionListener exceptionListener = new ExceptionListener(); + manager.setListener(exceptionListener); + manager.run(); + assertEquals(RuntimeException.class, exceptionListener.e.getClass()); + assertEquals("exception1", exceptionListener.e.getMessage()); + + ErrorListener errorListener = new ErrorListener(); + manager.setListener(errorListener); + manager.run(); + assertEquals(Exception.class, errorListener.e.getClass()); + assertEquals("java.lang.UnknownError: error1", errorListener.e.getMessage()); + assertEquals(UnknownError.class, errorListener.e.getCause().getClass()); + assertEquals("error1", errorListener.e.getCause().getMessage()); + } +}