Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00867227 authored by Tom Mulcahy's avatar Tom Mulcahy Committed by Cherrypicker Worker
Browse files

usb: Use Get/SetByteArrayRegion in bulkTransfer

This change fixes https://issuetracker.google.com/issues/335003907

This change replaces
GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical with
GetByteArrayRegion/SetByteArrayRegion.

This change is needed because the critical API variants are not
appropriate for this context. See the JNI docs:

After calling GetPrimitiveArrayCritical, the native code should not run
for an extended period of time before it calls
ReleasePrimitiveArrayCritical.

In bulkTransfer, we call usb_device_bulk_transfer between
GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical.
usb_device_bulk_transfer is a blocking call so this can lead to GC
hangs.

Instead, we allocate a new buffer with malloc and then call
GetByteArrayRegion/SetByteArrayRegion before/after
usb_device_bulk_transfer, depending on the direction of the endpoint.

Test: I ran UsbTests. I also sent a "TEST UNIT READY" to a USB drive and
verified the response.
(cherry picked from https://android-review.googlesource.com/q/commit:59548b0121d4492e4b55eceafa150b6af1a41a76)
Merged-In: I5c82aac3fe99e1f11044f20091bf3a940bc8f6a7
Change-Id: I5c82aac3fe99e1f11044f20091bf3a940bc8f6a7
parent a7cbd3c8
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -190,17 +190,21 @@ android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
        return -1;
    }

    jbyte* bufferBytes = NULL;
    if (buffer) {
        bufferBytes = (jbyte*)env->GetPrimitiveArrayCritical(buffer, NULL);
    bool is_dir_in = (endpoint & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
    jbyte *bufferBytes = (jbyte *)malloc(length);

    if (!is_dir_in && buffer) {
        env->GetByteArrayRegion(buffer, start, length, bufferBytes);
    }

    jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes + start, length, timeout);
    jint result = usb_device_bulk_transfer(device, endpoint, bufferBytes, length, timeout);

    if (bufferBytes) {
        env->ReleasePrimitiveArrayCritical(buffer, bufferBytes, 0);
    if (is_dir_in && buffer) {
        env->SetByteArrayRegion(buffer, start, length, bufferBytes);
    }

    free(bufferBytes);

    return result;
}