/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.hardware.usb;

import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.util.Log;

import com.android.internal.util.Preconditions;

import dalvik.system.CloseGuard;

import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.util.Objects;

/**
 * A class representing USB request packet.
 * This can be used for both reading and writing data to or from a
 * {@link android.hardware.usb.UsbDeviceConnection}.
 * UsbRequests can be used to transfer data on bulk and interrupt endpoints.
 * Requests on bulk endpoints can be sent synchronously via {@link UsbDeviceConnection#bulkTransfer}
 * or asynchronously via {@link #queue} and {@link UsbDeviceConnection#requestWait}.
 * Requests on interrupt endpoints are only send and received asynchronously.
 *
 * <p>Requests on endpoint zero are not supported by this class;
 * use {@link UsbDeviceConnection#controlTransfer} for endpoint zero requests instead.
 */
public class UsbRequest {

    private static final String TAG = "UsbRequest";

    // From drivers/usb/core/devio.c
    static final int MAX_USBFS_BUFFER_SIZE = 16384;

    // used by the JNI code
    @UnsupportedAppUsage
    private long mNativeContext;

    private UsbEndpoint mEndpoint;

    /** The buffer that is currently being read / written */
    @UnsupportedAppUsage
    private ByteBuffer mBuffer;

    /** The amount of data to read / write when using {@link #queue} */
    @UnsupportedAppUsage
    private int mLength;

    // for client use
    private Object mClientData;

    // Prevent the connection from being finalized
    private UsbDeviceConnection mConnection;

    /**
     * Whether this buffer was {@link #queue(ByteBuffer) queued using the new behavior} or
     * {@link #queue(ByteBuffer, int) queued using the deprecated behavior}.
     */
    private boolean mIsUsingNewQueue;

    /** Temporary buffer than might be used while buffer is enqueued */
    private ByteBuffer mTempBuffer;

    private final CloseGuard mCloseGuard = CloseGuard.get();

    /**
     * Lock for queue, enqueue and dequeue, so a queue operation can be finished by a dequeue
     * operation on a different thread.
     */
    private final Object mLock = new Object();

    public UsbRequest() {
    }

    /**
     * Initializes the request so it can read or write data on the given endpoint.
     * Whether the request allows reading or writing depends on the direction of the endpoint.
     *
     * @param endpoint the endpoint to be used for this request.
     * @return true if the request was successfully opened.
     */
    public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) {
        mEndpoint = endpoint;
        mConnection = Objects.requireNonNull(connection, "connection");

        boolean wasInitialized = native_init(connection, endpoint.getAddress(),
                endpoint.getAttributes(), endpoint.getMaxPacketSize(), endpoint.getInterval());

        if (wasInitialized) {
            mCloseGuard.open("close");
        }

        return wasInitialized;
    }

    /**
     * Releases all resources related to this request.
     */
    public void close() {
        if (mNativeContext != 0) {
            mEndpoint = null;
            mConnection = null;
            native_close();
            mCloseGuard.close();
        }
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (mCloseGuard != null) {
                mCloseGuard.warnIfOpen();
            }

            close();
        } finally {
            super.finalize();
        }
    }

    /**
     * Returns the endpoint for the request, or null if the request is not opened.
     *
     * @return the request's endpoint
     */
    public UsbEndpoint getEndpoint() {
        return mEndpoint;
    }

    /**
     * Returns the client data for the request.
     * This can be used in conjunction with {@link #setClientData}
     * to associate another object with this request, which can be useful for
     * maintaining state between calls to {@link #queue} and
     * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
     *
     * @return the client data for the request
     */
    public Object getClientData() {
        return mClientData;
    }

    /**
     * Sets the client data for the request.
     * This can be used in conjunction with {@link #getClientData}
     * to associate another object with this request, which can be useful for
     * maintaining state between calls to {@link #queue} and
     * {@link android.hardware.usb.UsbDeviceConnection#requestWait}
     *
     * @param data the client data for the request
     */
    public void setClientData(Object data) {
        mClientData = data;
    }

    /**
     * Queues the request to send or receive data on its endpoint.
     * <p>For OUT endpoints, the given buffer data will be sent on the endpoint. For IN endpoints,
     * the endpoint will attempt to read the given number of bytes into the specified buffer. If the
     * queueing operation is successful, return true. The result will be returned via
     * {@link UsbDeviceConnection#requestWait}</p>
     *
     * @param buffer the buffer containing the bytes to write, or location to store the results of a
     *               read. Position and array offset will be ignored and assumed to be 0. Limit and
     *               capacity will be ignored. Once the request
     *               {@link UsbDeviceConnection#requestWait() is processed} the position will be set
     *               to the number of bytes read/written.
     * @param length number of bytes to read or write. Before {@value Build.VERSION_CODES#P}, a
     *               value larger than 16384 bytes would be truncated down to 16384. In API
     *               {@value Build.VERSION_CODES#P} and after, any value of length is valid.
     *
     * @return true if the queueing operation succeeded
     *
     * @deprecated Use {@link #queue(ByteBuffer)} instead.
     */
    @Deprecated
    public boolean queue(ByteBuffer buffer, int length) {
        boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
        boolean result;

        if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
                && length > MAX_USBFS_BUFFER_SIZE) {
            length = MAX_USBFS_BUFFER_SIZE;
        }

        synchronized (mLock) {
            // save our buffer for when the request has completed
            mBuffer = buffer;
            mLength = length;

            // Note: On a buffer slice we lost the capacity information about the underlying buffer,
            // hence we cannot check if the access would be a data leak/memory corruption.

            if (buffer.isDirect()) {
                result = native_queue_direct(buffer, length, out);
            } else if (buffer.hasArray()) {
                result = native_queue_array(buffer.array(), length, out);
            } else {
                throw new IllegalArgumentException("buffer is not direct and has no array");
            }
            if (!result) {
                mBuffer = null;
                mLength = 0;
            }
        }

        return result;
    }

    /**
     * Queues the request to send or receive data on its endpoint.
     *
     * <p>For OUT endpoints, the remaining bytes of the buffer will be sent on the endpoint. For IN
     * endpoints, the endpoint will attempt to fill the remaining bytes of the buffer. If the
     * queueing operation is successful, return true. The result will be returned via
     * {@link UsbDeviceConnection#requestWait}</p>
     *
     * @param buffer the buffer containing the bytes to send, or the buffer to fill. The state
     *               of the buffer is undefined until the request is returned by
     *               {@link UsbDeviceConnection#requestWait}. If the request failed the buffer
     *               will be unchanged; if the request succeeded the position of the buffer is
     *               incremented by the number of bytes sent/received. Before
     *               {@value Build.VERSION_CODES#P}, a buffer of length larger than 16384 bytes
     *               would throw IllegalArgumentException. In API {@value Build.VERSION_CODES#P}
     *               and after, any size buffer is valid.
     *
     * @return true if the queueing operation succeeded
     */
    public boolean queue(@Nullable ByteBuffer buffer) {
        // Request need to be initialized
        Preconditions.checkState(mNativeContext != 0, "request is not initialized");

        // Request can not be currently queued
        Preconditions.checkState(!mIsUsingNewQueue, "this request is currently queued");

        boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
        boolean wasQueued;

        synchronized (mLock) {
            mBuffer = buffer;

            if (buffer == null) {
                // Null buffers enqueue empty USB requests which is supported
                mIsUsingNewQueue = true;
                wasQueued = native_queue(null, 0, 0);
            } else {
                if (mConnection.getContext().getApplicationInfo().targetSdkVersion
                        < Build.VERSION_CODES.P) {
                    // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
                    Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
                            "number of remaining bytes");
                }

                // Can not receive into read-only buffers.
                Preconditions.checkArgument(!(buffer.isReadOnly() && !isSend), "buffer can not be "
                        + "read-only when receiving data");

                if (!buffer.isDirect()) {
                    mTempBuffer = ByteBuffer.allocateDirect(mBuffer.remaining());

                    if (isSend) {
                        // Copy buffer into temporary buffer
                        mBuffer.mark();
                        mTempBuffer.put(mBuffer);
                        mTempBuffer.flip();
                        mBuffer.reset();
                    }

                    // Send/Receive into the temp buffer instead
                    buffer = mTempBuffer;
                }

                mIsUsingNewQueue = true;
                wasQueued = native_queue(buffer, buffer.position(), buffer.remaining());
            }
        }

        if (!wasQueued) {
            mIsUsingNewQueue = false;
            mTempBuffer = null;
            mBuffer = null;
        }

        return wasQueued;
    }

    /* package */ void dequeue(boolean useBufferOverflowInsteadOfIllegalArg) {
        boolean isSend = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
        int bytesTransferred;

        synchronized (mLock) {
            if (mIsUsingNewQueue) {
                bytesTransferred = native_dequeue_direct();
                mIsUsingNewQueue = false;

                if (mBuffer == null) {
                    // Nothing to do
                } else if (mTempBuffer == null) {
                    mBuffer.position(mBuffer.position() + bytesTransferred);
                } else {
                    mTempBuffer.limit(bytesTransferred);

                    // The user might have modified mBuffer which might make put/position fail.
                    // Changing the buffer while a request is in flight is not supported. Still,
                    // make sure to free mTempBuffer correctly.
                    try {
                        if (isSend) {
                            mBuffer.position(mBuffer.position() + bytesTransferred);
                        } else {
                            // Copy temp buffer back into original buffer
                            mBuffer.put(mTempBuffer);
                        }
                    } finally {
                        mTempBuffer = null;
                    }
                }
            } else {
                if (mBuffer.isDirect()) {
                    bytesTransferred = native_dequeue_direct();
                } else {
                    bytesTransferred = native_dequeue_array(mBuffer.array(), mLength, isSend);
                }
                if (bytesTransferred >= 0) {
                    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;
                        }
                    }
                }
            }

            mBuffer = null;
            mLength = 0;
        }
    }

    /**
     * Cancels a pending queue operation.
     *
     * @return true if cancelling succeeded
     */
    public boolean cancel() {
        if (mConnection == null) {
            return false;
        }

        return mConnection.cancelRequest(this);
    }

    /**
     * Cancels a pending queue operation (for use when the UsbDeviceConnection associated
     * with this request is synchronized). This ensures we don't have a race where the
     * device is closed and then the request is canceled which would lead to a
     * use-after-free because the cancel operation uses the device connection
     * information freed in the when UsbDeviceConnection is closed.<br/>
     *
     * This method assumes the connected is not closed while this method is executed.
     *
     * @return true if cancelling succeeded.
     */
    /* package */ boolean cancelIfOpen() {
        if (mNativeContext == 0 || (mConnection != null && !mConnection.isOpen())) {
            Log.w(TAG,
                    "Detected attempt to cancel a request on a connection which isn't open");
            return false;
        }
        return native_cancel();
    }

    private native boolean native_init(UsbDeviceConnection connection, int ep_address,
            int ep_attributes, int ep_max_packet_size, int ep_interval);
    private native void native_close();
    private native boolean native_queue(ByteBuffer buffer, int offset, int length);
    private native boolean native_queue_array(byte[] buffer, int length, boolean out);
    private native int native_dequeue_array(byte[] buffer, int length, boolean out);
    private native boolean native_queue_direct(ByteBuffer buffer, int length, boolean out);
    private native int native_dequeue_direct();
    private native boolean native_cancel();
}
