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

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

[AOA FFS Implementation] Add Vendor Control Request Monitor

Adds a thread which will monitor a given FunctionFS endpoint for control
requests, and explicitly handle vendor control requests which are
received over USB. This thread provides generic vendor control request
handling. This CL only adds the class, it will be used in a later CL
(ag/33856076) and the usage of the thread will be flagged.

Bug: 407985367
Bug: 416246384
Flag: android.hardware.usb.flags.enable_aoa_userspace_implementation
Test: No breakage
Change-Id: I76edd0d126b155c19c29828c12162df1eb8a1d45
parent 8058a411
Loading
Loading
Loading
Loading
+186 −1
Original line number Diff line number Diff line
@@ -32,12 +32,12 @@

#include "MtpDescriptors.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
#include "jni.h"
#include "utils/Log.h"

#define DRIVER_NAME "/dev/usb_accessory"
#define EPOLL_MAX_EVENTS 4
#define FFS_NUM_EVENTS 5
#define USB_STATE_MAX_LEN 20

namespace android
@@ -177,6 +177,191 @@ public:
};
static std::unique_ptr<NativeGadgetMonitorThread> sGadgetMonitorThread;

/*
 * NativeVendorControlRequestMonitorThread starts a new thread to monitor vendor
 * control requests. It issues state changes for accessory mode as required.
 */
class NativeVendorControlRequestMonitorThread {
    android::base::unique_fd mMonitorFd;
    int mShutdownPipefd[2];
    std::thread mThread;
    jobject mCallbackObj;

    void handleControlRequest(int fd, const struct usb_ctrlrequest *setup) {
        JNIEnv *env = AndroidRuntime::getJNIEnv();

        uint8_t type = setup->bRequestType;
        uint8_t code = setup->bRequest;
        uint16_t length = setup->wLength;
        uint16_t index = setup->wIndex;
        uint16_t value = setup->wValue;
        std::vector<char> buf;
        buf.resize(length + 1);
        std::string accessoryControlState;

        if ((type & USB_TYPE_MASK) == USB_TYPE_VENDOR) {
            switch (code) {
                // TODO(b/421809234): - Add support for accessory mode requests.
                // TODO(b/421807206): - Add support for accessory HID requests.

                default:
                    ALOGE("Unrecognized USB vendor request! %d", (int)code);
                    goto fail;
            }
        } else {
            ALOGE("Unrecognized USB request type %d", (int)type);
            goto fail;
        }

        if (type & USB_DIR_IN) {
            if (::write(fd, buf.data(), length) != length) {
                ALOGE("Usb error ctrlreq write data");
                goto fail;
            }
        }

        return;
    fail:
        // stall control endpoint by applying opposite i/o
        if (type & USB_DIR_IN) {
            if (::read(fd, buf.data(), 0) != -1 || errno != EL2HLT) {
                ALOGE("Couldn't halt ep0 on in request");
            }
        } else {
            if (::write(fd, buf.data(), 0) != -1 || errno != EL2HLT) {
                ALOGE("Couldn't halt ep0 on out request");
            }
        }
    }

    void teardown() {
        // Add teardown for vendor control requests being handled.

        ALOGI("Vendor control request monitor teardown");
    }

    int setupEpoll(android::base::unique_fd &epollFd) {
        struct epoll_event ev;

        ev.data.fd = mMonitorFd.get();
        ev.events = EPOLLIN;
        if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, mMonitorFd.get(), &ev) != 0) {
            ALOGE("epoll_ctl failed for ctrl request monitor fd; %s", strerror(errno));
            return errno;
        }

        ev.data.fd = mShutdownPipefd[0];
        ev.events = EPOLLIN;
        if (epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, mShutdownPipefd[0], &ev) != 0) {
            ALOGE("epoll_ctl failed for ctrl request pipe fd; %s", strerror(errno));
            return errno;
        }

        return 0;
    }

    void monitorLoop() {
        android::base::unique_fd epollFd(epoll_create(EPOLL_MAX_EVENTS));
        std::vector<struct usb_functionfs_event> ffs_events(FFS_NUM_EVENTS);

        ALOGI("Monitoring vendor control requests...");

        if (epollFd.get() == -1) {
            ALOGE("Vendor control request monitor epoll_create failed; %s", strerror(errno));
            return;
        }

        if (setupEpoll(epollFd) != 0) {
            ALOGE("Vendor control request monitor setupEpoll failed!");
            return;
        }

        JNIEnv *env = nullptr;
        JavaVMAttachArgs aargs = {JNI_VERSION_1_4, "NativeVendorControlRequestMonitorThread",
                                  nullptr};
        if (gvm->AttachCurrentThread(&env, &aargs) != JNI_OK || env == nullptr) {
            ALOGE("Couldn't attach thread");
            return;
        }

        struct epoll_event events[EPOLL_MAX_EVENTS];
        int nevents = 0;
        while (true) {
            nevents = epoll_wait(epollFd.get(), events, EPOLL_MAX_EVENTS, -1);

            if (nevents < 0) {
                if (errno != EINTR)
                    ALOGE("Vendor control request monitor epoll_wait failed; %s", strerror(errno));
                continue;
            }

            for (int i = 0; i < nevents; ++i) {
                int fd = events[i].data.fd;
                if (fd == mShutdownPipefd[0]) {
                    ALOGE("Vendor control request monitor loop exiting...");
                    goto exit;
                } else if (fd == mMonitorFd.get()) {
                    if (events[i].events & EPOLLIN) {
                        struct usb_functionfs_event *event = ffs_events.data();
                        int nbytes = TEMP_FAILURE_RETRY(
                                ::read(fd, event,
                                       ffs_events.size() * sizeof(usb_functionfs_event)));
                        if (nbytes == -1) {
                            ALOGE("error reading Usb control events");
                            continue;
                        }
                        for (size_t n = nbytes / sizeof(*event); n; --n, ++event) {
                            switch (event->type) {
                                case FUNCTIONFS_SETUP:
                                    handleControlRequest(fd, &event->u.setup);
                                    break;
                                case FUNCTIONFS_UNBIND:
                                    teardown();
                                    break;
                                default:
                                    continue;
                            }
                        }
                    }
                }
            }
        }

    exit:
        auto res = gvm->DetachCurrentThread();
        ALOGE("Detaching thread");
        ALOGE_IF(res != JNI_OK, "Couldn't detach thread");
        return;
    }

    void stop() {
        if (mThread.joinable()) {
            int c = 'q';
            write(mShutdownPipefd[1], &c, 1);
            mThread.join();
        }
    }

    DISALLOW_COPY_AND_ASSIGN(NativeVendorControlRequestMonitorThread);

public:
    explicit NativeVendorControlRequestMonitorThread(jobject obj,
                                                     android::base::unique_fd monitorFd)
          : mMonitorFd(std::move(monitorFd)){
        mCallbackObj = AndroidRuntime::getJNIEnv()->NewGlobalRef(obj);
        pipe(mShutdownPipefd);
        mThread = std::thread(&NativeVendorControlRequestMonitorThread::monitorLoop, this);
    }

    ~NativeVendorControlRequestMonitorThread() {
        stop();
        close(mShutdownPipefd[0]);
        close(mShutdownPipefd[1]);
        AndroidRuntime::getJNIEnv()->DeleteGlobalRef(mCallbackObj);
    }
};
static std::unique_ptr<NativeVendorControlRequestMonitorThread> sVendorControlRequestMonitorThread;

static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strArray, int index)
{
    char buffer[256];