Skip to content

Commit 8b9ad7e

Browse files
committed
improved error handling for read() with concurrent close() (#569)
- isOpen() returns false during concurrent close() - less tracing in SerialInputOutputManager
1 parent 1245293 commit 8b9ad7e

File tree

6 files changed

+26
-15
lines changed

6 files changed

+26
-15
lines changed

usbSerialForAndroid/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ android {
1313

1414
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1515
testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ...
16-
'rfc2217_server_host': '192.168.0.147',
16+
'rfc2217_server_host': '192.168.0.78',
1717
'rfc2217_server_nonstandard_baudrates': 'true', // true false false
1818
]
1919
}

usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,10 @@ public void run() {
320320
try {
321321
closer.wait = false;
322322
usb.serialPort.read(new byte[256], 2000);
323+
323324
fail("closed expected");
324325
} catch(IOException ex) {
326+
assertFalse(usb.serialPort.isOpen());
325327
assertEquals("Connection closed", ex.getMessage());
326328
}
327329
th.join();
@@ -333,6 +335,7 @@ public void run() {
333335
usb.serialPort.read(new byte[256], 0);
334336
fail("closed expected");
335337
} catch(IOException ex) {
338+
assertFalse(usb.serialPort.isOpen());
336339
assertEquals("Connection closed", ex.getMessage());
337340
}
338341
th.join();

usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ public void close() throws IOException {
139139
if (mConnection == null) {
140140
throw new IOException("Already closed");
141141
}
142+
UsbDeviceConnection connection = mConnection;
143+
mConnection = null;
142144
try {
143145
mUsbRequest.cancel();
144146
} catch(Exception ignored) {}
@@ -147,20 +149,22 @@ public void close() throws IOException {
147149
closeInt();
148150
} catch(Exception ignored) {}
149151
try {
150-
mConnection.close();
152+
connection.close();
151153
} catch(Exception ignored) {}
152-
mConnection = null;
153154
}
154155

155156
protected abstract void closeInt();
156157

157158
/**
158159
* use simple USB request supported by all devices to test if connection is still valid
159160
*/
160-
protected void testConnection() throws IOException {
161-
if(mConnection == null || mUsbRequest == null) {
161+
protected void testConnection(boolean full) throws IOException {
162+
if(mConnection == null) {
162163
throw new IOException("Connection closed");
163164
}
165+
if(!full) {
166+
return;
167+
}
164168
byte[] buf = new byte[2];
165169
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
166170
if(len < 0)
@@ -169,7 +173,7 @@ protected void testConnection() throws IOException {
169173

170174
@Override
171175
public int read(final byte[] dest, final int timeout) throws IOException {
172-
if(dest.length <= 0) {
176+
if(dest.length == 0) {
173177
throw new IllegalArgumentException("Read buffer too small");
174178
}
175179
return read(dest, dest.length, timeout);
@@ -179,7 +183,7 @@ public int read(final byte[] dest, final int timeout) throws IOException {
179183
public int read(final byte[] dest, final int length, final int timeout) throws IOException {return read(dest, length, timeout, true);}
180184

181185
protected int read(final byte[] dest, int length, final int timeout, boolean testConnection) throws IOException {
182-
if(mConnection == null || mUsbRequest == null) {
186+
if(mConnection == null) {
183187
throw new IOException("Connection closed");
184188
}
185189
if(length <= 0) {
@@ -201,8 +205,8 @@ protected int read(final byte[] dest, int length, final int timeout, boolean tes
201205
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
202206
// Android error propagation is improvable:
203207
// nread == -1 can be: timeout, connection lost, buffer to small, ???
204-
if(nread == -1 && testConnection && MonotonicClock.millis() < endTime)
205-
testConnection();
208+
if(nread == -1 && testConnection)
209+
testConnection(MonotonicClock.millis() < endTime);
206210

207211
} else {
208212
final ByteBuffer buf = ByteBuffer.wrap(dest, 0, length);
@@ -217,7 +221,7 @@ protected int read(final byte[] dest, int length, final int timeout, boolean tes
217221
// Android error propagation is improvable:
218222
// response != null & nread == 0 can be: connection lost, buffer to small, ???
219223
if(nread == 0) {
220-
testConnection();
224+
testConnection(true);
221225
}
222226
}
223227
return Math.max(nread, 0);

usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ public int read(final byte[] dest, int length, final int timeout) throws IOExcep
165165
do {
166166
nread = super.read(dest, length, Math.max(1, (int)(endTime - MonotonicClock.millis())), false);
167167
} while (nread == READ_HEADER_LENGTH && MonotonicClock.millis() < endTime);
168-
if(nread <= 0 && MonotonicClock.millis() < endTime)
169-
testConnection();
168+
if(nread <= 0)
169+
testConnection(MonotonicClock.millis() < endTime);
170170
} else {
171171
do {
172172
nread = super.read(dest, length, timeout);

usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,8 @@ private void readStatusThreadFunction() {
205205
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
206206
long endTime = MonotonicClock.millis() + 500;
207207
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, buffer, STATUS_BUFFER_SIZE, 500);
208-
if(readBytesCount == -1 && MonotonicClock.millis() < endTime)
209-
testConnection();
208+
if(readBytesCount == -1)
209+
testConnection(MonotonicClock.millis() < endTime);
210210
if (readBytesCount > 0) {
211211
if (readBytesCount != STATUS_BUFFER_SIZE) {
212212
throw new IOException("Invalid status notification, expected " + STATUS_BUFFER_SIZE + " bytes, got " + readBytesCount);

usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,11 @@ public void run() {
203203
step();
204204
}
205205
} catch (Exception e) {
206-
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
206+
if(mSerialPort.isOpen()) {
207+
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
208+
} else {
209+
Log.i(TAG, "Socket closed");
210+
}
207211
final Listener listener = getListener();
208212
if (listener != null) {
209213
listener.onRunError(e);

0 commit comments

Comments
 (0)