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

Commit 28569ba9 authored by Jerry Zhang's avatar Jerry Zhang Committed by android-build-merger
Browse files

Refactored Mtp driver interface into multiple classes. am: 487be61f am: c17a7610

am: 14750418

Change-Id: I21ecd5d33412c45cff7780b937fc4377d3f7cb33
parents 89a987c8 14750418
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -19,26 +19,31 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:=                                       \
                  AsyncIO.cpp                           \
                  MtpDataPacket.cpp                     \
                  MtpDebug.cpp                          \
                  MtpDevHandle.cpp                      \
                  MtpDevice.cpp                         \
                  MtpEventPacket.cpp                    \
                  MtpDeviceInfo.cpp                     \
                  MtpEventPacket.cpp                    \
                  MtpFfsHandle.cpp                      \
                  MtpObjectInfo.cpp                     \
                  MtpPacket.cpp                         \
                  MtpProperty.cpp                       \
                  MtpRequestPacket.cpp                  \
                  MtpResponsePacket.cpp                 \
                  MtpServer.cpp                         \
                  MtpStorage.cpp                        \
                  MtpStorageInfo.cpp                    \
                  MtpStringBuffer.cpp                   \
                  MtpStorage.cpp                        \
                  MtpUtils.cpp                          \

LOCAL_MODULE:= libmtp

LOCAL_CFLAGS := -DMTP_DEVICE -DMTP_HOST -Wall -Wextra -Werror

LOCAL_SHARED_LIBRARIES := libutils libcutils liblog libusbhost libbinder
LOCAL_SHARED_LIBRARIES := libbase libutils libcutils liblog libusbhost libbinder

include $(BUILD_SHARED_LIBRARY)

include $(call all-makefiles-under,$(LOCAL_PATH))

media/mtp/AsyncIO.cpp

0 → 100644
+176 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.
 */

#include <android-base/logging.h>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>

#include "AsyncIO.h"

namespace {

void read_func(struct aiocb *aiocbp) {
    aiocbp->ret = TEMP_FAILURE_RETRY(pread(aiocbp->aio_fildes,
                aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
    if (aiocbp->ret == -1) aiocbp->error = errno;
}

void write_func(struct aiocb *aiocbp) {
    aiocbp->ret = TEMP_FAILURE_RETRY(pwrite(aiocbp->aio_fildes,
                aiocbp->aio_buf, aiocbp->aio_nbytes, aiocbp->aio_offset));
    if (aiocbp->ret == -1) aiocbp->error = errno;
}

void splice_read_func(struct aiocb *aiocbp) {
    aiocbp->ret = TEMP_FAILURE_RETRY(splice(aiocbp->aio_fildes,
                (off64_t*) &aiocbp->aio_offset, aiocbp->aio_sink,
                NULL, aiocbp->aio_nbytes, 0));
    if (aiocbp->ret == -1) aiocbp->error = errno;
}

void splice_write_func(struct aiocb *aiocbp) {
    aiocbp->ret = TEMP_FAILURE_RETRY(splice(aiocbp->aio_fildes, NULL,
                aiocbp->aio_sink, (off64_t*) &aiocbp->aio_offset,
                aiocbp->aio_nbytes, 0));
    if (aiocbp->ret == -1) aiocbp->error = errno;
}

std::queue<std::unique_ptr<struct aiocb>> queue;
std::mutex queue_lock;
std::condition_variable queue_cond;
std::condition_variable write_cond;
int done = 1;
void splice_write_pool_func(int) {
    while(1) {
        std::unique_lock<std::mutex> lk(queue_lock);
        queue_cond.wait(lk, []{return !queue.empty() || done;});
        if (queue.empty() && done) {
            return;
        }
        std::unique_ptr<struct aiocb> aiocbp = std::move(queue.front());
        queue.pop();
        lk.unlock();
        write_cond.notify_one();
        splice_write_func(aiocbp.get());
        close(aiocbp->aio_fildes);
    }
}

void write_pool_func(int) {
    while(1) {
        std::unique_lock<std::mutex> lk(queue_lock);
        queue_cond.wait(lk, []{return !queue.empty() || done;});
        if (queue.empty() && done) {
            return;
        }
        std::unique_ptr<struct aiocb> aiocbp = std::move(queue.front());
        queue.pop();
        lk.unlock();
        write_cond.notify_one();
        aiocbp->ret = TEMP_FAILURE_RETRY(pwrite(aiocbp->aio_fildes,
                    aiocbp->aio_pool_buf.get(), aiocbp->aio_nbytes, aiocbp->aio_offset));
        if (aiocbp->ret == -1) aiocbp->error = errno;
    }
}

constexpr int NUM_THREADS = 1;
constexpr int MAX_QUEUE_SIZE = 10;
std::thread pool[NUM_THREADS];

} // end anonymous namespace

void aio_pool_init(void(f)(int)) {
    CHECK(done == 1);
    done = 0;
    for (int i = 0; i < NUM_THREADS; i++) {
        pool[i] = std::thread(f, i);
    }
}

void aio_pool_splice_init() {
    aio_pool_init(splice_write_pool_func);
}

void aio_pool_write_init() {
    aio_pool_init(write_pool_func);
}

void aio_pool_end() {
    done = 1;
    for (int i = 0; i < NUM_THREADS; i++) {
        std::unique_lock<std::mutex> lk(queue_lock);
        lk.unlock();
        queue_cond.notify_one();
    }

    for (int i = 0; i < NUM_THREADS; i++) {
        pool[i].join();
    }
}

// used for both writes and splices depending on which init was used before.
int aio_pool_write(struct aiocb *aiocbp) {
    std::unique_lock<std::mutex> lk(queue_lock);
    write_cond.wait(lk, []{return queue.size() < MAX_QUEUE_SIZE;});
    queue.push(std::unique_ptr<struct aiocb>(aiocbp));
    lk.unlock();
    queue_cond.notify_one();
    return 0;
}

int aio_read(struct aiocb *aiocbp) {
    aiocbp->thread = std::thread(read_func, aiocbp);
    return 0;
}

int aio_write(struct aiocb *aiocbp) {
    aiocbp->thread = std::thread(write_func, aiocbp);
    return 0;
}

int aio_splice_read(struct aiocb *aiocbp) {
    aiocbp->thread = std::thread(splice_read_func, aiocbp);
    return 0;
}

int aio_splice_write(struct aiocb *aiocbp) {
    aiocbp->thread = std::thread(splice_write_func, aiocbp);
    return 0;
}

int aio_error(const struct aiocb *aiocbp) {
    return aiocbp->error;
}

ssize_t aio_return(struct aiocb *aiocbp) {
    return aiocbp->ret;
}

int aio_suspend(struct aiocb *aiocbp[], int n,
        const struct timespec *) {
    for (int i = 0; i < n; i++) {
        aiocbp[i]->thread.join();
    }
    return 0;
}

int aio_cancel(int, struct aiocb *) {
    // Not implemented
    return -1;
}

media/mtp/AsyncIO.h

0 → 100644
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.
 */

#ifndef _ASYNCIO_H
#define _ASYNCIO_H

#include <fcntl.h>
#include <linux/aio_abi.h>
#include <memory>
#include <signal.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <time.h>
#include <thread>
#include <unistd.h>

/**
 * Provides a subset of POSIX aio operations, as well
 * as similar operations with splice and threadpools.
 */

struct aiocb {
    int aio_fildes;     // Assumed to be the source for splices
    void *aio_buf;      // Unused for splices

    // Used for threadpool operations only, freed automatically
    std::unique_ptr<char[]> aio_pool_buf;

    off_t aio_offset;
    size_t aio_nbytes;

    int aio_sink;       // Unused for non splice r/w

    // Used internally
    std::thread thread;
    ssize_t ret;
    int error;
};

// Submit a request for IO to be completed
int aio_read(struct aiocb *);
int aio_write(struct aiocb *);
int aio_splice_read(struct aiocb *);
int aio_splice_write(struct aiocb *);

// Suspend current thread until given IO is complete, at which point
// its return value and any errors can be accessed
int aio_suspend(struct aiocb *[], int, const struct timespec *);
int aio_error(const struct aiocb *);
ssize_t aio_return(struct aiocb *);
int aio_cancel(int, struct aiocb *);

// Initialize a threadpool to perform IO. Only one pool can be
// running at a time.
void aio_pool_write_init();
void aio_pool_splice_init();
// Suspend current thread until all queued work is complete, then ends the threadpool
void aio_pool_end();
// Submit IO work for the threadpool to complete. Memory associated with the work is
// freed automatically when the work is complete.
int aio_pool_write(struct aiocb *);

#endif // ASYNCIO_H

media/mtp/IMtpHandle.h

0 → 100644
+47 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.
 */
#ifndef _IMTP_HANDLE_H
#define _IMTP_HANDLE_H

#include <linux/usb/f_mtp.h>

constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";

class IMtpHandle {
public:
    // Return number of bytes read/written, or -1 and errno is set
    virtual int read(void *data, int len) = 0;
    virtual int write(const void *data, int len) = 0;

    // Return 0 if send/receive is successful, or -1 and errno is set
    virtual int receiveFile(mtp_file_range mfr) = 0;
    virtual int sendFile(mtp_file_range mfr) = 0;
    virtual int sendEvent(mtp_event me) = 0;

    // Return 0 if operation is successful, or -1 else
    virtual int start() = 0;
    virtual int configure(bool ptp) = 0;

    virtual void close() = 0;

    virtual ~IMtpHandle() {}
};

IMtpHandle *get_ffs_handle();
IMtpHandle *get_mtp_handle();

#endif // _IMTP_HANDLE_H
+8 −7
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#include "MtpDataPacket.h"
#include "MtpStringBuffer.h"
#include "IMtpHandle.h"

namespace android {

@@ -418,8 +419,8 @@ void MtpDataPacket::putString(const uint16_t* string) {
}

#ifdef MTP_DEVICE
int MtpDataPacket::read(int fd) {
    int ret = ::read(fd, mBuffer, MTP_BUFFER_SIZE);
int MtpDataPacket::read(IMtpHandle *h) {
    int ret = h->read(mBuffer, MTP_BUFFER_SIZE);
    if (ret < MTP_CONTAINER_HEADER_SIZE)
        return -1;
    mPacketSize = ret;
@@ -427,20 +428,20 @@ int MtpDataPacket::read(int fd) {
    return ret;
}

int MtpDataPacket::write(int fd) {
int MtpDataPacket::write(IMtpHandle *h) {
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
    int ret = ::write(fd, mBuffer, mPacketSize);
    int ret = h->write(mBuffer, mPacketSize);
    return (ret < 0 ? ret : 0);
}

int MtpDataPacket::writeData(int fd, void* data, uint32_t length) {
int MtpDataPacket::writeData(IMtpHandle *h, void* data, uint32_t length) {
    allocate(length + MTP_CONTAINER_HEADER_SIZE);
    memcpy(mBuffer + MTP_CONTAINER_HEADER_SIZE, data, length);
    length += MTP_CONTAINER_HEADER_SIZE;
    MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, length);
    MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
    int ret = ::write(fd, mBuffer, length);
    int ret = h->write(mBuffer, length);
    return (ret < 0 ? ret : 0);
}

Loading