Skip to content

Commit ff9d4b9

Browse files
committed
fix: use sync usb transfers to avoid native crash
1 parent e60caf5 commit ff9d4b9

1 file changed

Lines changed: 31 additions & 56 deletions

File tree

app/src/main/java/to/bitkit/services/TrezorTransport.kt

Lines changed: 31 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import android.hardware.usb.UsbDeviceConnection
2424
import android.hardware.usb.UsbEndpoint
2525
import android.hardware.usb.UsbInterface
2626
import android.hardware.usb.UsbManager
27-
import android.hardware.usb.UsbRequest
2827
import android.os.Handler
2928
import android.os.Looper
3029
import android.os.ParcelUuid
@@ -45,7 +44,6 @@ import to.bitkit.ext.bluetoothManager
4544
import to.bitkit.ext.usbManager
4645
import to.bitkit.utils.Logger
4746
import java.io.File
48-
import java.nio.ByteBuffer
4947
import java.util.UUID
5048
import java.util.concurrent.ConcurrentHashMap
5149
import java.util.concurrent.CountDownLatch
@@ -702,39 +700,27 @@ class TrezorTransport @Inject constructor(
702700
error = "Device not open: $path",
703701
)
704702

705-
val buffer = ByteBuffer.allocate(USB_CHUNK_SIZE)
706-
val request = UsbRequest()
707-
try {
708-
if (!request.initialize(openDevice.connection, openDevice.readEndpoint)) {
709-
return TrezorTransportReadResult(
710-
success = false,
711-
data = byteArrayOf(),
712-
error = "Failed to initialize USB read request",
713-
)
714-
}
715-
if (!request.queue(buffer)) {
716-
return TrezorTransportReadResult(
717-
success = false,
718-
data = byteArrayOf(),
719-
error = "Failed to queue USB read request",
720-
)
721-
}
722-
openDevice.connection.requestWait(READ_TIMEOUT_MS.toLong())
723-
?: return TrezorTransportReadResult(
724-
success = false,
725-
data = byteArrayOf(),
726-
error = "USB read timed out",
727-
)
728-
729-
buffer.flip()
730-
val bytesRead = buffer.remaining()
731-
val data = ByteArray(bytesRead)
732-
buffer.get(data)
733-
Logger.debug("USB read '$bytesRead' bytes from '$path'", context = TAG)
734-
TrezorTransportReadResult(success = true, data = data, error = "")
735-
} finally {
736-
request.close()
703+
// Synchronous transfer on purpose: the async UsbRequest API requires
704+
// cancelling and reaping a timed-out request before closing it; closing
705+
// with the URB still queued frees memory the kernel later writes into
706+
// (native SIGSEGV in libusbhost once the device finally responds).
707+
val buffer = ByteArray(USB_CHUNK_SIZE)
708+
val bytesRead = openDevice.connection.bulkTransfer(
709+
openDevice.readEndpoint,
710+
buffer,
711+
buffer.size,
712+
READ_TIMEOUT_MS,
713+
)
714+
if (bytesRead < 0) {
715+
return TrezorTransportReadResult(
716+
success = false,
717+
data = byteArrayOf(),
718+
error = "USB read timed out",
719+
)
737720
}
721+
722+
Logger.debug("USB read '$bytesRead' bytes from '$path'", context = TAG)
723+
TrezorTransportReadResult(success = true, data = buffer.copyOf(bytesRead), error = "")
738724
} catch (e: Exception) {
739725
Logger.error("USB read failed", e, context = TAG)
740726
TrezorTransportReadResult(success = false, data = byteArrayOf(), error = e.message ?: "Unknown error")
@@ -747,29 +733,18 @@ class TrezorTransport @Inject constructor(
747733
val openDevice = usbConnections[path]
748734
?: return TrezorTransportWriteResult(success = false, error = "Device not open: $path")
749735

750-
val buffer = ByteBuffer.wrap(data)
751-
val request = UsbRequest()
752-
try {
753-
if (!request.initialize(openDevice.connection, openDevice.writeEndpoint)) {
754-
return TrezorTransportWriteResult(
755-
success = false,
756-
error = "Failed to initialize USB write request",
757-
)
758-
}
759-
if (!request.queue(buffer)) {
760-
return TrezorTransportWriteResult(
761-
success = false,
762-
error = "Failed to queue USB write request",
763-
)
764-
}
765-
openDevice.connection.requestWait(WRITE_TIMEOUT_MS.toLong())
766-
?: return TrezorTransportWriteResult(success = false, error = "USB write timed out")
767-
768-
Logger.debug("USB wrote '${data.size}' bytes to '$path'", context = TAG)
769-
TrezorTransportWriteResult(success = true, error = "")
770-
} finally {
771-
request.close()
736+
val bytesWritten = openDevice.connection.bulkTransfer(
737+
openDevice.writeEndpoint,
738+
data,
739+
data.size,
740+
WRITE_TIMEOUT_MS,
741+
)
742+
if (bytesWritten != data.size) {
743+
return TrezorTransportWriteResult(success = false, error = "USB write timed out")
772744
}
745+
746+
Logger.debug("USB wrote '${data.size}' bytes to '$path'", context = TAG)
747+
TrezorTransportWriteResult(success = true, error = "")
773748
} catch (e: Exception) {
774749
Logger.error("USB write failed", e, context = TAG)
775750
TrezorTransportWriteResult(success = false, error = e.message ?: "Unknown error")

0 commit comments

Comments
 (0)