From 9b6dd2b2c15113bf9c30a1915f3354c52cb60c33 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Thu, 6 Apr 2017 15:34:04 -0700 Subject: [PATCH] Change requestWait API according to request Test: USB Device CTSVerifier test Change-Id: Ib55bed248d7b37c6f5f4a7be7ec2d90a7ac396c7 Fixes: 36555805 --- api/current.txt | 2 +- api/system-current.txt | 2 +- api/test-current.txt | 2 +- .../hardware/usb/UsbDeviceConnection.java | 47 +++++++++++++------ .../java/android/hardware/usb/UsbRequest.java | 17 ++++++- .../android_hardware_UsbDeviceConnection.cpp | 15 ++++-- 6 files changed, 62 insertions(+), 23 deletions(-) diff --git a/api/current.txt b/api/current.txt index fe35f617680a6..b557a0392412e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -15950,7 +15950,7 @@ package android.hardware.usb { method public java.lang.String getSerial(); method public boolean releaseInterface(android.hardware.usb.UsbInterface); method public android.hardware.usb.UsbRequest requestWait(); - method public android.hardware.usb.UsbRequest requestWait(int); + method public android.hardware.usb.UsbRequest requestWait(long) throws java.util.concurrent.TimeoutException; method public boolean setConfiguration(android.hardware.usb.UsbConfiguration); method public boolean setInterface(android.hardware.usb.UsbInterface); } diff --git a/api/system-current.txt b/api/system-current.txt index 16e6f5b1e34db..8df092a6fa4eb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -17439,7 +17439,7 @@ package android.hardware.usb { method public java.lang.String getSerial(); method public boolean releaseInterface(android.hardware.usb.UsbInterface); method public android.hardware.usb.UsbRequest requestWait(); - method public android.hardware.usb.UsbRequest requestWait(int); + method public android.hardware.usb.UsbRequest requestWait(long) throws java.util.concurrent.TimeoutException; method public boolean resetDevice(); method public boolean setConfiguration(android.hardware.usb.UsbConfiguration); method public boolean setInterface(android.hardware.usb.UsbInterface); diff --git a/api/test-current.txt b/api/test-current.txt index 38897c86dbfcc..55a65238b125b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -16005,7 +16005,7 @@ package android.hardware.usb { method public java.lang.String getSerial(); method public boolean releaseInterface(android.hardware.usb.UsbInterface); method public android.hardware.usb.UsbRequest requestWait(); - method public android.hardware.usb.UsbRequest requestWait(int); + method public android.hardware.usb.UsbRequest requestWait(long) throws java.util.concurrent.TimeoutException; method public boolean setConfiguration(android.hardware.usb.UsbConfiguration); method public boolean setInterface(android.hardware.usb.UsbInterface); } diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index ffd6ec32fccce..7a0272df40d9c 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; +import android.os.Build; import android.os.ParcelFileDescriptor; import com.android.internal.util.Preconditions; @@ -27,7 +28,9 @@ import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.FileDescriptor; +import java.nio.BufferOverflowException; import java.nio.ByteBuffer; +import java.util.concurrent.TimeoutException; /** * This class is used for sending and receiving data and control messages to a USB device. @@ -268,16 +271,29 @@ public class UsbDeviceConnection { * * @return a completed USB request, or null if an error occurred * - * @throws IllegalArgumentException if the number of bytes read or written is more than the - * limit of the request's buffer. The number of bytes is - * determined by the {@code length} parameter of + * @throws IllegalArgumentException Before API {@value Build.VERSION_CODES#O}: if the number of + * bytes read or written is more than the limit of the + * request's buffer. The number of bytes is determined by the + * {@code length} parameter of * {@link UsbRequest#queue(ByteBuffer, int)} + * @throws BufferOverflowException In API {@value Build.VERSION_CODES#O} and after: if the + * number of bytes read or written is more than the limit of the + * request's buffer. The number of bytes is determined by the + * {@code length} parameter of + * {@link UsbRequest#queue(ByteBuffer, int)} */ public UsbRequest requestWait() { - // -1 is special value indicating infinite wait - UsbRequest request = native_request_wait(-1); + UsbRequest request = null; + try { + // -1 is special value indicating infinite wait + request = native_request_wait(-1); + } catch (TimeoutException e) { + // Does not happen, infinite timeout + } + if (request != null) { - request.dequeue(); + request.dequeue( + mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O); } return request; } @@ -290,24 +306,25 @@ public class UsbDeviceConnection { * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process * the result of this function.

*

Android processes {@link UsbRequest UsbRequests} asynchronously. Hence it is not - * guaranteed that {@link #requestWait(int) requestWait(0)} returns a request that has been + * guaranteed that {@link #requestWait(long) requestWait(0)} returns a request that has been * queued right before even if the request could have been processed immediately.

* * @param timeout timeout in milliseconds. If 0 this method does not wait. * - * @return a completed USB request, or {@code null} if an error or time out occurred + * @return a completed USB request, or {@code null} if an error occurred * - * @throws IllegalArgumentException if the number of bytes read or written is more than the - * limit of the request's buffer. The number of bytes is - * determined by the {@code length} parameter of - * {@link UsbRequest#queue(ByteBuffer, int)} + * @throws BufferOverflowException if the number of bytes read or written is more than the + * limit of the request's buffer. The number of bytes is + * determined by the {@code length} parameter of + * {@link UsbRequest#queue(ByteBuffer, int)} + * @throws TimeoutException if no request was received in {@code timeout} milliseconds. */ - public UsbRequest requestWait(int timeout) { + public UsbRequest requestWait(long timeout) throws TimeoutException { timeout = Preconditions.checkArgumentNonnegative(timeout, "timeout"); UsbRequest request = native_request_wait(timeout); if (request != null) { - request.dequeue(); + request.dequeue(true); } return request; } @@ -350,7 +367,7 @@ public class UsbDeviceConnection { int index, byte[] buffer, int offset, int length, int timeout); private native int native_bulk_request(int endpoint, byte[] buffer, int offset, int length, int timeout); - private native UsbRequest native_request_wait(int timeout); + private native UsbRequest native_request_wait(long timeout) throws TimeoutException; private native String native_get_serial(); private native boolean native_reset_device(); } diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java index 239a2df5e1c30..90990b798d3e9 100644 --- a/core/java/android/hardware/usb/UsbRequest.java +++ b/core/java/android/hardware/usb/UsbRequest.java @@ -17,11 +17,13 @@ package android.hardware.usb; import android.annotation.Nullable; +import android.util.Log; import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; +import java.nio.BufferOverflowException; import java.nio.ByteBuffer; /** @@ -276,7 +278,7 @@ public class UsbRequest { return wasQueued; } - /* package */ void dequeue() { + /* package */ void dequeue(boolean useBufferOverflowInsteadOfIllegalArg) { boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT); int bytesTransferred; @@ -313,7 +315,18 @@ public class UsbRequest { bytesTransferred = native_dequeue_array(mBuffer.array(), mLength, isSend); } if (bytesTransferred >= 0) { - mBuffer.position(Math.min(bytesTransferred, mLength)); + int bytesToStore = Math.min(bytesTransferred, mLength); + try { + mBuffer.position(bytesToStore); + } catch (IllegalArgumentException e) { + if (useBufferOverflowInsteadOfIllegalArg) { + Log.e(TAG, "Buffer " + mBuffer + " does not have enough space to read " + + bytesToStore + " bytes", e); + throw new BufferOverflowException(); + } else { + throw e; + } + } } } diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp index 6814506ad7974..ba08bce7d17b7 100644 --- a/core/jni/android_hardware_UsbDeviceConnection.cpp +++ b/core/jni/android_hardware_UsbDeviceConnection.cpp @@ -220,7 +220,7 @@ android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz, } static jobject -android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz, jint timeoutMillis) +android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz, jlong timeoutMillis) { struct usb_device* device = get_device_from_object(env, thiz); if (!device) { @@ -243,8 +243,17 @@ android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz, jin - currentTime).count()); int error = errno; + if (request != NULL) { + break; + } + currentTime = steady_clock::now(); - if (request != NULL || error != EAGAIN || currentTime >= endTime) { + if (currentTime >= endTime) { + jniThrowException(env, "java/util/concurrent/TimeoutException", ""); + break; + } + + if (error != EAGAIN) { break; } }; @@ -300,7 +309,7 @@ static const JNINativeMethod method_table[] = { (void *)android_hardware_UsbDeviceConnection_control_request}, {"native_bulk_request", "(I[BIII)I", (void *)android_hardware_UsbDeviceConnection_bulk_request}, - {"native_request_wait", "(I)Landroid/hardware/usb/UsbRequest;", + {"native_request_wait", "(J)Landroid/hardware/usb/UsbRequest;", (void *)android_hardware_UsbDeviceConnection_request_wait}, { "native_get_serial", "()Ljava/lang/String;", (void*)android_hardware_UsbDeviceConnection_get_serial },