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

Commit 383c8a28 authored by Febin Thattil's avatar Febin Thattil Committed by Android (Google) Code Review
Browse files

Merge "[AOA FFS Implementation] Added support for streaming APIs" into main

parents d740c6b1 84c001dc
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -47,6 +47,19 @@ interface IUsbManager
     */
    ParcelFileDescriptor openAccessory(in UsbAccessory accessory);

    /* Returns a file descriptor for reading from the USB accessory.
     * This file descriptor can be used with standard Java file operations.
     */
    ParcelFileDescriptor openAccessoryForInputStream(in UsbAccessory accessory);

    /* Returns a file descriptor for writing to the USB accessory.
     * This file descriptor can be used with standard Java file operations.
     */
    ParcelFileDescriptor openAccessoryForOutputStream(in UsbAccessory accessory);

    /* Returns the max packet size of the USB accessory.*/
    int getMaxPacketSize(in UsbAccessory accessory);

    /* Sets the default package for a USB device
     * (or clears it if the package name is null)
     */
+61 −33
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ import android.hardware.usb.gadget.UsbSpeed;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.system.ErrnoException;
import android.system.Os;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
@@ -60,6 +62,7 @@ import com.android.internal.annotations.GuardedBy;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InterruptedIOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -959,35 +962,9 @@ public class UsbManager {
            /* TODO(b/377850642) : Ensure the stream is closed even if client does not
            explicitly close the stream to avoid corrupt FDs*/
            super.close();
            if (!android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
                closeHandleForAccessory(mAccessory, true);
            }


        @Override
        public int read() throws IOException {
            final int result = super.read();
            checkError(result);
            return result;
        }

        @Override
        public int read(byte[] b) throws IOException {
            final int result = super.read(b);
            checkError(result);
            return result;
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            final int result = super.read(b, off, len);
            checkError(result);
            return result;
        }

        private void checkError(int result) throws IOException {
            if (result == -1 && mPfd.canDetectErrors()) {
                mPfd.checkError();
            }
        }
    }

@@ -998,10 +975,35 @@ public class UsbManager {
     */
    private class AccessoryAutoCloseOutputStream extends FileOutputStream {
        private final UsbAccessory mAccessory;
        private final int mMaxPacketSize;
        private final ParcelFileDescriptor mPfd;

        AccessoryAutoCloseOutputStream(
                UsbAccessory accessory, ParcelFileDescriptor pfd, int maxPacketSize) {
            super(pfd.getFileDescriptor());
            mMaxPacketSize = maxPacketSize;
            mAccessory = accessory;
            mPfd = pfd;
        }

        AccessoryAutoCloseOutputStream(UsbAccessory accessory, ParcelFileDescriptor pfd) {
            super(pfd.getFileDescriptor());
            mMaxPacketSize = -1;
            mAccessory = accessory;
            mPfd = pfd;
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            super.write(b, off, len);

            if (!android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
                return;
            }
            // Check if a ZLP is needed for this specific write operation
            if (len > 0 && (len % mMaxPacketSize == 0)) {
                sendZlp();
            }
        }

        @Override
@@ -1009,10 +1011,26 @@ public class UsbManager {
            /* TODO(b/377850642) : Ensure the stream is closed even if client does not
            explicitly close the stream to avoid corrupt FDs*/
            super.close();
            if (!android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
                closeHandleForAccessory(mAccessory, false);
            }
        }

        /** Sends a Zero-Length Packet. This is done by writing a 0-byte array. */
        private void sendZlp() {
            byte[] emptyBuffer = new byte[0]; // Or any buffer, as count will be 0
            // This should make a write(2) syscall with count = 0
            try {
                // TODO: febinthattil - Try this with native code
                Os.write(mPfd.getFileDescriptor(), emptyBuffer, 0, 0);
            } catch (ErrnoException e) {
                Log.e(TAG, "ZLP failed to send.", e);
            } catch (InterruptedIOException e) {
                Log.e(TAG, "ZLP failed to send.", e);
            }
        }
    }

    /**
     * Holds file descriptor and marks whether input and output streams have been opened for it.
     */
@@ -1179,8 +1197,12 @@ public class UsbManager {
    @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
    public @NonNull InputStream openAccessoryInputStream(@NonNull UsbAccessory accessory) {
        try {
            return new AccessoryAutoCloseInputStream(accessory,
                    openHandleForAccessory(accessory, true).getPfd());
            if (android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
                return new AccessoryAutoCloseInputStream(
                        accessory, mService.openAccessoryForInputStream(accessory));
            }
            return new AccessoryAutoCloseInputStream(
                    accessory, openHandleForAccessory(accessory, true).getPfd());

        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -1199,6 +1221,12 @@ public class UsbManager {
    @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
    public @NonNull OutputStream openAccessoryOutputStream(@NonNull UsbAccessory accessory) {
        try {
            if (android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
                return new AccessoryAutoCloseOutputStream(
                        accessory,
                        mService.openAccessoryForOutputStream(accessory),
                        mService.getMaxPacketSize(accessory));
            }
            return new AccessoryAutoCloseOutputStream(accessory,
                    openHandleForAccessory(accessory, false).getPfd());
        } catch (RemoteException e) {
+61 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@
#define FFS_VENDOR_CTRL_REQUEST_EP0 "/dev/usb-ffs/ctrl/ep0"

#define FFS_ACCESSORY_EP0 "/dev/usb-ffs/aoa/ep0"
#define FFS_ACCESSORY_EP1 "/dev/usb-ffs/aoa/ep1"
#define FFS_ACCESSORY_EP2 "/dev/usb-ffs/aoa/ep2"

namespace {
struct func_desc {
@@ -669,6 +671,11 @@ public:
        return mAccessoryFields.maxPacketSize;
    }

    void setMaxPacketSize(int maxPacketSize) {
        std::lock_guard<std::mutex> lock(mAccessoryFieldsMutex);
        mAccessoryFields.maxPacketSize = maxPacketSize;
    }

    ~NativeVendorControlRequestMonitorThread() {
        stop();
        close(mShutdownPipefd[0]);
@@ -705,6 +712,16 @@ static void set_accessory_string_from_ffs(JNIEnv *env, jobjectArray strArray, in
    }
}

static int get_max_packet_size(int ffs_fd) {
    struct usb_endpoint_descriptor desc{};
    if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
        ALOGE("Could not get FFS bulk-in descriptor");
        return 512;
    } else {
        return desc.wMaxPacketSize;
    }
}

static jobjectArray android_server_UsbDeviceManager_getAccessoryStrings(JNIEnv *env,
                                                                        jobject /* thiz */)
{
@@ -743,6 +760,11 @@ static jobjectArray android_server_UsbDeviceManager_getAccessoryStringsFromFfs(J
    return strArray;
}

static jint android_server_UsbDeviceManager_getMaxPacketSize(JNIEnv * /* env */,
                                                             jobject /* thiz */) {
    return static_cast<jint>(sVendorControlRequestMonitorThread->getMaxPacketSize());
}

static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobject /* thiz */)
{
    int fd = open(DRIVER_NAME, O_RDWR);
@@ -759,6 +781,40 @@ static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobjec
        gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
}

static jobject android_server_UsbDeviceManager_openAccessoryForInputStream(JNIEnv *env,
                                                                           jobject /* thiz */) {
    int readFd = open(FFS_ACCESSORY_EP1, O_RDONLY);
    if (readFd < 0) {
        ALOGE("could not open %s", FFS_ACCESSORY_EP1);
        return nullptr;
    }
    jobject readFileDescriptor = jniCreateFileDescriptor(env, readFd);
    if (readFileDescriptor == nullptr) {
        close(readFd);
        return nullptr;
    }
    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
                          gParcelFileDescriptorOffsets.mConstructor, readFileDescriptor);
}

static jobject android_server_UsbDeviceManager_openAccessoryForOutputStream(JNIEnv *env,
                                                                            jobject /* thiz */) {
    int writeFd = open(FFS_ACCESSORY_EP2, O_WRONLY);

    if (writeFd < 0) {
        ALOGE("could not open %s", FFS_ACCESSORY_EP2);
        return nullptr;
    }
    sVendorControlRequestMonitorThread->setMaxPacketSize(get_max_packet_size(writeFd));
    jobject writeFileDescriptor = jniCreateFileDescriptor(env, writeFd);
    if (writeFileDescriptor == nullptr) {
        close(writeFd);
        return nullptr;
    }
    return env->NewObject(gParcelFileDescriptorOffsets.mClass,
                          gParcelFileDescriptorOffsets.mConstructor, writeFileDescriptor);
}

static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv* /* env */,
                                                                 jobject /* thiz */)
{
@@ -896,8 +952,13 @@ static const JNINativeMethod method_table[] = {
         (void *)android_server_UsbDeviceManager_getAccessoryStrings},
        {"nativeGetAccessoryStringsFromFfs", "()[Ljava/lang/String;",
         (void *)android_server_UsbDeviceManager_getAccessoryStringsFromFfs},
        {"nativeGetMaxPacketSize", "()I", (void *)android_server_UsbDeviceManager_getMaxPacketSize},
        {"nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;",
         (void *)android_server_UsbDeviceManager_openAccessory},
        {"nativeOpenAccessoryForInputStream", "()Landroid/os/ParcelFileDescriptor;",
         (void *)android_server_UsbDeviceManager_openAccessoryForInputStream},
        {"nativeOpenAccessoryForOutputStream", "()Landroid/os/ParcelFileDescriptor;",
         (void *)android_server_UsbDeviceManager_openAccessoryForOutputStream},
        {"nativeIsStartRequested", "()Z", (void *)android_server_UsbDeviceManager_isStartRequested},
        {"nativeOpenControl", "(Ljava/lang/String;)Ljava/io/FileDescriptor;",
         (void *)android_server_UsbDeviceManager_openControl},
+66 −0
Original line number Diff line number Diff line
@@ -2607,6 +2607,66 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
        return nativeOpenAccessory();
    }

    /**
     * opens the currently attached USB accessory to read from.
     *
     * @param accessory accessory to be opened.
     * @param permissions UsbUserPermissionManager to check permissions.
     * @param pid Pid of the caller
     * @param uid Uid of the caller
     */
    public ParcelFileDescriptor openAccessoryForInputStream(
            UsbAccessory accessory, UsbUserPermissionManager permissions, int pid, int uid) {
        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
        if (currentAccessory == null) {
            throw new IllegalArgumentException("no accessory attached");
        }
        if (!currentAccessory.equals(accessory)) {
            String error =
                    accessory.toString() + " does not match current accessory " + currentAccessory;
            throw new IllegalArgumentException(error);
        }
        permissions.checkPermission(accessory, pid, uid);
        return nativeOpenAccessoryForInputStream();
    }

    /**
     * opens the currently attached USB accessory to write to.
     *
     * @param accessory accessory to be opened.
     * @param permissions UsbUserPermissionManager to check permissions.
     * @param pid Pid of the caller
     * @param uid Uid of the caller
     */
    public ParcelFileDescriptor openAccessoryForOutputStream(
            UsbAccessory accessory, UsbUserPermissionManager permissions, int pid, int uid) {
        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
        if (currentAccessory == null) {
            throw new IllegalArgumentException("no accessory attached");
        }
        if (!currentAccessory.equals(accessory)) {
            String error =
                    accessory.toString() + " does not match current accessory " + currentAccessory;
            throw new IllegalArgumentException(error);
        }
        permissions.checkPermission(accessory, pid, uid);
        return nativeOpenAccessoryForOutputStream();
    }

    public int getMaxPacketSize(UsbAccessory accessory) {
        UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
        if (currentAccessory == null) {
            throw new IllegalArgumentException("no accessory attached");
        }
        if (!currentAccessory.equals(accessory)) {
            String error =
                    accessory.toString() + " does not match current accessory " + currentAccessory;
            throw new IllegalArgumentException(error);
        }

        return nativeGetMaxPacketSize();
    }

    public long getCurrentFunctions() {
        return mHandler.getEnabledFunctions();
    }
@@ -2769,8 +2829,14 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser

    private native String[] nativeGetAccessoryStringsFromFfs();

    private native int nativeGetMaxPacketSize();

    private native ParcelFileDescriptor nativeOpenAccessory();

    private native ParcelFileDescriptor nativeOpenAccessoryForInputStream();

    private native ParcelFileDescriptor nativeOpenAccessoryForOutputStream();

    private native String nativeWaitAndGetProperty(String propName);

    private native FileDescriptor nativeOpenControl(String usbFunction);
+82 −0
Original line number Diff line number Diff line
@@ -404,6 +404,88 @@ public class UsbService extends IUsbManager.Stub {
        return null;
    }

    /* opens the currently attached USB accessory to read from (device mode) */
    @Override
    public ParcelFileDescriptor openAccessoryForInputStream(UsbAccessory accessory) {
        if (mDeviceManager != null) {
            int uid = Binder.getCallingUid();
            int pid = Binder.getCallingPid();
            int user = UserHandle.getUserId(uid);

            final long ident = clearCallingIdentity();
            try {
                synchronized (mLock) {
                    if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
                        return mDeviceManager.openAccessoryForInputStream(
                                accessory, getPermissionsForUser(user), pid, uid);
                    } else {
                        Slog.w(TAG, "Cannot open " + accessory + " for user " + user
                                        + " as user is not active.");
                    }
                }
            } finally {
                restoreCallingIdentity(ident);
            }
        }

        return null;
    }

    /* opens the currently attached USB accessory to write to (device mode) */
    @Override
    public ParcelFileDescriptor openAccessoryForOutputStream(UsbAccessory accessory) {
        if (mDeviceManager != null) {
            int uid = Binder.getCallingUid();
            int pid = Binder.getCallingPid();
            int user = UserHandle.getUserId(uid);

            final long ident = clearCallingIdentity();
            try {
                synchronized (mLock) {
                    if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
                        return mDeviceManager.openAccessoryForOutputStream(
                                accessory, getPermissionsForUser(user), pid, uid);
                    } else {
                        Slog.w(
                                TAG,
                                "Cannot open " + accessory + " for user " + user
                                        + " as user is not active.");
                    }
                }
            } finally {
                restoreCallingIdentity(ident);
            }
        }

        return null;
    }

    /* Gets the currently attached USB accessory max packet size (device mode) */
    @Override
    public int getMaxPacketSize(UsbAccessory accessory) {
        Preconditions.checkNotNull(mDeviceManager, "DeviceManager must not be null");
        int uid = Binder.getCallingUid();
        int user = UserHandle.getUserId(uid);

        final long ident = clearCallingIdentity();
        try {
            synchronized (mLock) {
                int maxPacketSize = -1;
                if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
                    maxPacketSize = mDeviceManager.getMaxPacketSize(accessory);
                } else {
                    Slog.w(
                            TAG,
                            "Cannot open " + accessory + " for user " + user
                                    + " as user is not active.");
                }
                return maxPacketSize;
            }
        } finally {
            restoreCallingIdentity(ident);
        }
    }

    @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_MTP)
    /* Returns a dup of the control file descriptor for the given function. */
    @Override