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

Commit 927fefe8 authored by Philip P. Moltmann's avatar Philip P. Moltmann
Browse files

Add UsbDeviceConnection.requestWait with a timeout

Test: Test is submitted alongside this change
Change-Id: I1c46143030a2822ee76676ddc80d3b5c8c62ee80
Fixes: 31288102
parent 34a6b577
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -14778,6 +14778,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 boolean setConfiguration(android.hardware.usb.UsbConfiguration);
    method public boolean setInterface(android.hardware.usb.UsbInterface);
  }
+1 −0
Original line number Diff line number Diff line
@@ -15988,6 +15988,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 boolean resetDevice();
    method public boolean setConfiguration(android.hardware.usb.UsbConfiguration);
    method public boolean setInterface(android.hardware.usb.UsbInterface);
+1 −0
Original line number Diff line number Diff line
@@ -14795,6 +14795,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 boolean setConfiguration(android.hardware.usb.UsbConfiguration);
    method public boolean setInterface(android.hardware.usb.UsbInterface);
  }
+38 −2
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.ParcelFileDescriptor;

import com.android.internal.util.Preconditions;

import dalvik.system.CloseGuard;

import java.io.FileDescriptor;
@@ -273,7 +276,40 @@ public class UsbDeviceConnection {
     *                                  {@link UsbRequest#queue(ByteBuffer, int)}
     */
    public UsbRequest requestWait() {
        UsbRequest request = native_request_wait();
        // -1 is special value indicating infinite wait
        UsbRequest request = native_request_wait(-1);
        if (request != null) {
            request.dequeue();
        }
        return request;
    }

    /**
     * Waits for the result of a {@link android.hardware.usb.UsbRequest#queue} operation
     * <p>Note that this may return requests queued on multiple
     * {@link android.hardware.usb.UsbEndpoint}s. When multiple endpoints are in use,
     * {@link android.hardware.usb.UsbRequest#getEndpoint} and {@link
     * android.hardware.usb.UsbRequest#getClientData} can be useful in determining how to process
     * the result of this function.</p>
     * <p>Position and array offset of the request's buffer are ignored and assumed to be 0. The
     * position will be set to the number of bytes read/written.</p>
     * <p>Android processes {@link UsbRequest UsbRequests} asynchronously. Hence it is not
     * guaranteed that {@link #requestWait(int) requestWait(0)} returns a request that has been
     * queued right before even if the request could have been processed immediately.</p>
     *
     * @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
     *
     * @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)}
     */
    public UsbRequest requestWait(int timeout) {
        timeout = Preconditions.checkArgumentNonnegative(timeout);

        UsbRequest request = native_request_wait(timeout);
        if (request != null) {
            request.dequeue();
        }
@@ -318,7 +354,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();
    private native UsbRequest native_request_wait(int timeout);
    private native String native_get_serial();
    private native boolean native_reset_device();
}
+30 −5
Original line number Diff line number Diff line
@@ -24,12 +24,15 @@

#include <usbhost/usbhost.h>

#include <chrono>

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace android;
using namespace std::chrono;

static jfieldID field_context;

@@ -215,7 +218,7 @@ android_hardware_UsbDeviceConnection_bulk_request(JNIEnv *env, jobject thiz,
}

static jobject
android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz)
android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz, jint timeoutMillis)
{
    struct usb_device* device = get_device_from_object(env, thiz);
    if (!device) {
@@ -223,12 +226,34 @@ android_hardware_UsbDeviceConnection_request_wait(JNIEnv *env, jobject thiz)
        return NULL;
    }

    struct usb_request* request = usb_request_wait(device);
    if (request)
    struct usb_request* request;
    if (timeoutMillis == -1) {
        request = usb_request_wait(device, -1);
    } else {
        steady_clock::time_point currentTime = steady_clock::now();
        steady_clock::time_point endTime = currentTime + std::chrono::milliseconds(timeoutMillis);

        // Poll the existence of a request via usb_request_wait until we get a result, an unexpected
        // error or time out. As several threads can listen on the same fd, we might get wakeups
        // without data.
        while (1) {
            request = usb_request_wait(device, duration_cast<std::chrono::milliseconds>(endTime
                               - currentTime).count());

            int error = errno;
            currentTime = steady_clock::now();
            if (request != NULL || error != EAGAIN || currentTime >= endTime) {
                break;
            }
        };
    }

    if (request) {
        return (jobject)request->client_data;
    else
    } else {
        return NULL;
    }
}

static jstring
android_hardware_UsbDeviceConnection_get_serial(JNIEnv *env, jobject thiz)
@@ -272,7 +297,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",             "()Landroid/hardware/usb/UsbRequest;",
    {"native_request_wait",             "(I)Landroid/hardware/usb/UsbRequest;",
                                        (void *)android_hardware_UsbDeviceConnection_request_wait},
    { "native_get_serial",      "()Ljava/lang/String;",
                                        (void*)android_hardware_UsbDeviceConnection_get_serial },