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 },