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

Commit cadcdcdf authored by Febin Thattil's avatar Febin Thattil
Browse files

[AOA FFS Implementation] Verify FFS directory for AOA

This commit checks if the accessory directories exist and are mounted as FFS. If these conditions are met it will enable the AOA userspace implementation.

Bug: 407985367
Bug: 424156976
Flag: android.hardware.usb.flags.enable_aoa_userspace_implementation
Test: manual check the presence of folders
Test: Run CTS USB test cases with enable_aoa_userspace_implementation enabled
Change-Id: I34270582dd2d0c971a12c746ba563e8fb1c61861
parent c0727c8c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -60,6 +60,9 @@ interface IUsbManager
    /* Returns the max packet size of the USB accessory.*/
    int getMaxPacketSize(in UsbAccessory accessory);

    /* Returns true if accessory FFS is enabled. */
    boolean isAccessoryFfsEnabled();

    /* Sets the default package for a USB device
     * (or clears it if the package name is null)
     */
+29 −8
Original line number Diff line number Diff line
@@ -950,11 +950,21 @@ public class UsbManager {

        private final ParcelFileDescriptor mPfd;
        private final UsbAccessory mAccessory;
        private final boolean mIsAccessoryFfsEnabled;

        AccessoryAutoCloseInputStream(
                UsbAccessory accessory, ParcelFileDescriptor pfd, boolean isAccessoryFfsEnabled) {
            super(pfd.getFileDescriptor());
            this.mAccessory = accessory;
            this.mPfd = pfd;
            this.mIsAccessoryFfsEnabled = isAccessoryFfsEnabled;
        }

        AccessoryAutoCloseInputStream(UsbAccessory accessory, ParcelFileDescriptor pfd) {
            super(pfd.getFileDescriptor());
            this.mAccessory = accessory;
            this.mPfd = pfd;
            this.mIsAccessoryFfsEnabled = false;
        }

        @Override
@@ -962,7 +972,7 @@ 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()) {
            if (!mIsAccessoryFfsEnabled) {
                closeHandleForAccessory(mAccessory, true);
            }
        }
@@ -977,13 +987,18 @@ public class UsbManager {
        private final UsbAccessory mAccessory;
        private final int mMaxPacketSize;
        private final ParcelFileDescriptor mPfd;
        private final boolean mIsAccessoryFfsEnabled;

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

        AccessoryAutoCloseOutputStream(UsbAccessory accessory, ParcelFileDescriptor pfd) {
@@ -991,13 +1006,14 @@ public class UsbManager {
            mMaxPacketSize = -1;
            mAccessory = accessory;
            mPfd = pfd;
            mIsAccessoryFfsEnabled = false;
        }

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

            if (!android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
            if (!mIsAccessoryFfsEnabled) {
                return;
            }
            // Check if a ZLP is needed for this specific write operation
@@ -1011,7 +1027,7 @@ 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()) {
            if (!mIsAccessoryFfsEnabled) {
                closeHandleForAccessory(mAccessory, false);
            }
        }
@@ -1197,9 +1213,12 @@ public class UsbManager {
    @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
    public @NonNull InputStream openAccessoryInputStream(@NonNull UsbAccessory accessory) {
        try {
            if (android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
            boolean isAccessoryFfsEnabled = mService.isAccessoryFfsEnabled();
            if (isAccessoryFfsEnabled) {
                return new AccessoryAutoCloseInputStream(
                        accessory, mService.openAccessoryForInputStream(accessory));
                        accessory,
                        mService.openAccessoryForInputStream(accessory),
                        isAccessoryFfsEnabled);
            }
            return new AccessoryAutoCloseInputStream(
                    accessory, openHandleForAccessory(accessory, true).getPfd());
@@ -1221,11 +1240,13 @@ public class UsbManager {
    @RequiresFeature(PackageManager.FEATURE_USB_ACCESSORY)
    public @NonNull OutputStream openAccessoryOutputStream(@NonNull UsbAccessory accessory) {
        try {
            if (android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
            boolean isAccessoryFfsEnabled = mService.isAccessoryFfsEnabled();
            if (isAccessoryFfsEnabled) {
                return new AccessoryAutoCloseOutputStream(
                        accessory,
                        mService.openAccessoryForOutputStream(accessory),
                        mService.getMaxPacketSize(accessory));
                        mService.getMaxPacketSize(accessory),
                        isAccessoryFfsEnabled);
            }
            return new AccessoryAutoCloseOutputStream(accessory,
                    openHandleForAccessory(accessory, false).getPfd());
+61 −1
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@
#include <asyncio/AsyncIO.h>
#include <core_jni_helpers.h>
#include <fcntl.h>
#include <fstream>
#include <linux/aio_abi.h>

#include <linux/uhid.h>
#include <linux/usb/f_accessory.h>
#include <nativehelper/JNIPlatformHelp.h>
@@ -33,7 +36,6 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <map>
#include <thread>

@@ -1504,6 +1506,62 @@ static jboolean android_server_UsbDeviceManager_openAccessoryControl(JNIEnv * /*
    return JNI_TRUE;
}

// Function to check if a given path is a functionfs mount point
bool is_path_mounted_as_functionfs(std::string path) {

    std::ifstream mounts_file("/proc/mounts");
    if (!mounts_file.is_open()) {
        ALOGE("Could not open /proc/mounts");
        return false;
    }

    std::string line;
    while (std::getline(mounts_file, line)) {
        std::stringstream ss(line);
        std::string device, mount_point, fs_type;

        ss >> device >> mount_point >> fs_type;

        if (mount_point == path && fs_type == "functionfs") {
            return true;
        }
    }

    return false;
}

std::string get_parent_directory(std::string path) {
    std::string parent_dir = path;
    size_t pos = path.find_last_of('/');
    if (pos != std::string::npos) {
        parent_dir = path.substr(0, pos);
    }
    return parent_dir;
}

static jboolean android_server_UsbDeviceManager_checkAccessoryFfsDirectories(JNIEnv * /* env */,
                                                                             jobject /* thiz */) {
    if (access(FFS_VENDOR_CTRL_REQUEST_EP0, F_OK) != 0) {
        ALOGE("Cannot access %s", FFS_VENDOR_CTRL_REQUEST_EP0);
        return JNI_FALSE;
    }

    if (!is_path_mounted_as_functionfs(get_parent_directory(FFS_VENDOR_CTRL_REQUEST_EP0))) {
        return JNI_FALSE;
    }

    if (access(FFS_ACCESSORY_EP0, F_OK) != 0) {
        ALOGE("Cannot access %s", FFS_ACCESSORY_EP0);
        return JNI_FALSE;
    }

    if (!is_path_mounted_as_functionfs(get_parent_directory(FFS_ACCESSORY_EP0))) {
        return JNI_FALSE;
    }

    return JNI_TRUE;
}

static jstring android_server_UsbDeviceManager_waitAndGetProperty(JNIEnv *env, jobject thiz,
                                                                  jstring jPropName) {
    ScopedUtfChars propName(env, jPropName);
@@ -1527,6 +1585,8 @@ static const JNINativeMethod method_table[] = {
         (void *)android_server_UsbDeviceManager_openAccessoryForInputStream},
        {"nativeOpenAccessoryForOutputStream", "()Landroid/os/ParcelFileDescriptor;",
         (void *)android_server_UsbDeviceManager_openAccessoryForOutputStream},
        {"nativeCheckAccessoryFfsDirectories", "()Z",
         (void *)android_server_UsbDeviceManager_checkAccessoryFfsDirectories},
        {"nativeIsStartRequested", "()Z", (void *)android_server_UsbDeviceManager_isStartRequested},
        {"nativeOpenControl", "(Ljava/lang/String;)Ljava/io/FileDescriptor;",
         (void *)android_server_UsbDeviceManager_openControl},
+19 −4
Original line number Diff line number Diff line
@@ -241,6 +241,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
    private final boolean mEnableUdcSysfsUsbStateUpdate;
    private String mUdcName = "";

    private boolean mEnableAoaUserspaceImplementation = false;

    /**
     * Counter for tracking UsbOperation operations.
     */
@@ -361,7 +363,12 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
        }
        mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);

        if (android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
      // TODO: b/440091110 - Add check for device property.
        mEnableAoaUserspaceImplementation =
                android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()
                        && nativeCheckAccessoryFfsDirectories();

        if (mEnableAoaUserspaceImplementation) {
            if (!nativeOpenAccessoryControl()) {
                Slog.e(TAG, "Failed to open control for accessory");
            }
@@ -476,9 +483,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
            mUEventObserver.startObserving(USB_STATE_MATCH);
        }

        if (android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
        if (mEnableAoaUserspaceImplementation) {
            nativeStartVendorControlRequestMonitor();
        }

        sEventLogger = new EventLogger(DUMPSYS_LOG_BUFFER, "UsbDeviceManager activity");
    }

@@ -541,7 +549,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser

        int operationId = sUsbOperationCount.incrementAndGet();

        if (android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
        if (mEnableAoaUserspaceImplementation) {
            mAccessoryStrings = nativeGetAccessoryStringsFromFfs();
        } else {
            mAccessoryStrings = nativeGetAccessoryStrings();
@@ -2667,6 +2675,10 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
        return nativeGetMaxPacketSize();
    }

    public boolean isAccessoryFfsEnabled() {
        return mEnableAoaUserspaceImplementation;
    }

    public long getCurrentFunctions() {
        return mHandler.getEnabledFunctions();
    }
@@ -2802,7 +2814,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
    /** Update accessory control state (Called by native code). */
    @Keep
    private void updateAccessoryState(String state) {
        if (!android.hardware.usb.flags.Flags.enableAoaUserspaceImplementation()) {
        if (!mEnableAoaUserspaceImplementation) {
            Slog.w(TAG, "Accessory state update from userspace is not supported!");
            return;
        }
@@ -2850,4 +2862,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
    private native boolean nativeStartVendorControlRequestMonitor();

    private native boolean nativeOpenAccessoryControl();

    private native boolean nativeCheckAccessoryFfsDirectories();

}
+16 −0
Original line number Diff line number Diff line
@@ -533,6 +533,22 @@ public class UsbService extends IUsbManager.Stub {
        }
    }

    /* Checks if accessory FFS is enabled */
    @Override
    public boolean isAccessoryFfsEnabled() {
        Preconditions.checkNotNull(mDeviceManager, "DeviceManager must not be null");

        final long ident = clearCallingIdentity();
        try {
            synchronized (mLock) {
                return mDeviceManager.isAccessoryFfsEnabled();
            }

        } finally {
            restoreCallingIdentity(ident);
        }
    }

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