Remove configure() from Mtp

Instead of configuring the server each
time the connection happens, UsbService
will now pass in the control fd with the
descriptors already written. Also, PTP
endpoints have been moved to their own
directory at /dev/usb-ffs/ptp rather than
using the same ones as mtp.

Bug: 72877174
Test: Verify PTP and MTP config changes work
Change-Id: I9a0336afd610aa397c9947568c308afb89b27c08
gugelfrei
Jerry Zhang 7 years ago
parent b95a598919
commit 63dac45aa8

@ -32,8 +32,7 @@ public:
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 int start(bool ptp) = 0;
virtual void close() = 0;

@ -14,6 +14,9 @@
* limitations under the License.
*/
#include <android-base/logging.h>
#include <sys/types.h>
#include "MtpDescriptors.h"
namespace android {
@ -257,4 +260,24 @@ const struct desc_v1 ptp_desc_v1 = {
.hs_descs = ptp_hs_descriptors,
};
bool writeDescriptors(int fd, bool ptp) {
ssize_t ret = TEMP_FAILURE_RETRY(write(fd,
&(ptp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
if (ret < 0) {
PLOG(ERROR) << fd << "Switching to V1 descriptor format";
ret = TEMP_FAILURE_RETRY(write(fd,
&(ptp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
if (ret < 0) {
PLOG(ERROR) << fd << "Writing descriptors failed";
return false;
}
}
ret = TEMP_FAILURE_RETRY(write(fd, &mtp_strings, sizeof(mtp_strings)));
if (ret < 0) {
PLOG(ERROR) << fd << "Writing strings failed";
return false;
}
return true;
}
}; // namespace android

@ -23,6 +23,16 @@
namespace android {
constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";
constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
constexpr char FFS_PTP_EP0[] = "/dev/usb-ffs/ptp/ep0";
constexpr char FFS_PTP_EP_IN[] = "/dev/usb-ffs/ptp/ep1";
constexpr char FFS_PTP_EP_OUT[] = "/dev/usb-ffs/ptp/ep2";
constexpr char FFS_PTP_EP_INTR[] = "/dev/usb-ffs/ptp/ep3";
constexpr int MAX_PACKET_SIZE_FS = 64;
constexpr int MAX_PACKET_SIZE_HS = 512;
constexpr int MAX_PACKET_SIZE_SS = 1024;
@ -91,6 +101,8 @@ extern const struct desc_v1 mtp_desc_v1;
extern const struct desc_v1 ptp_desc_v1;
extern const struct functionfs_strings mtp_strings;
bool writeDescriptors(int fd, bool ptp);
}; // namespace android
#endif // MTP_DESCRIPTORS_H

@ -60,7 +60,7 @@ int MtpDevHandle::sendEvent(mtp_event me) {
return ioctl(mFd, MTP_SEND_EVENT, reinterpret_cast<unsigned long>(&me));
}
int MtpDevHandle::start() {
int MtpDevHandle::start(bool /* ptp */) {
mFd.reset(TEMP_FAILURE_RETRY(open(mtp_dev_path, O_RDWR)));
if (mFd == -1) return -1;
return 0;
@ -70,9 +70,4 @@ void MtpDevHandle::close() {
mFd.reset();
}
int MtpDevHandle::configure(bool) {
// Nothing to do, driver can configure itself
return 0;
}
} // namespace android

@ -36,10 +36,8 @@ public:
int sendFile(mtp_file_range mfr);
int sendEvent(mtp_event me);
int start();
int start(bool ptp);
void close();
int configure(bool ptp);
};
} // namespace android

@ -61,7 +61,8 @@ constexpr size_t ENDPOINT_ALLOC_RETRIES = 10;
namespace android {
MtpFfsCompatHandle::MtpFfsCompatHandle() :
MtpFfsCompatHandle::MtpFfsCompatHandle(int controlFd) :
MtpFfsHandle(controlFd),
mMaxWrite(USB_FFS_MAX_WRITE),
mMaxRead(USB_FFS_MAX_READ) {}
@ -108,10 +109,8 @@ int MtpFfsCompatHandle::readHandle(int fd, void* data, size_t len) {
return ret;
}
int MtpFfsCompatHandle::start() {
mLock.lock();
if (!openEndpoints())
int MtpFfsCompatHandle::start(bool ptp) {
if (!openEndpoints(ptp))
return -1;
for (unsigned i = 0; i < NUM_IO_BUFS; i++) {

@ -42,9 +42,9 @@ public:
* Open ffs endpoints and allocate necessary kernel and user memory.
* Will sleep until endpoints are enabled, for up to 1 second.
*/
int start() override;
int start(bool ptp) override;
MtpFfsCompatHandle();
MtpFfsCompatHandle(int controlFd);
~MtpFfsCompatHandle();
};

@ -39,10 +39,6 @@
namespace {
constexpr char FFS_MTP_EP_IN[] = "/dev/usb-ffs/mtp/ep1";
constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
constexpr unsigned AIO_BUFS_MAX = 128;
constexpr unsigned AIO_BUF_LEN = 16384;
@ -73,7 +69,9 @@ int MtpFfsHandle::getPacketSize(int ffs_fd) {
}
}
MtpFfsHandle::MtpFfsHandle() {}
MtpFfsHandle::MtpFfsHandle(int controlFd) {
mControl.reset(controlFd);
}
MtpFfsHandle::~MtpFfsHandle() {}
@ -83,27 +81,27 @@ void MtpFfsHandle::closeEndpoints() {
mBulkOut.reset();
}
bool MtpFfsHandle::openEndpoints() {
bool MtpFfsHandle::openEndpoints(bool ptp) {
if (mBulkIn < 0) {
mBulkIn.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_IN, O_RDWR)));
mBulkIn.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN, O_RDWR)));
if (mBulkIn < 0) {
PLOG(ERROR) << FFS_MTP_EP_IN << ": cannot open bulk in ep";
PLOG(ERROR) << (ptp ? FFS_PTP_EP_IN : FFS_MTP_EP_IN) << ": cannot open bulk in ep";
return false;
}
}
if (mBulkOut < 0) {
mBulkOut.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_OUT, O_RDWR)));
mBulkOut.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT, O_RDWR)));
if (mBulkOut < 0) {
PLOG(ERROR) << FFS_MTP_EP_OUT << ": cannot open bulk out ep";
PLOG(ERROR) << (ptp ? FFS_PTP_EP_OUT : FFS_MTP_EP_OUT) << ": cannot open bulk out ep";
return false;
}
}
if (mIntr < 0) {
mIntr.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP_INTR, O_RDWR)));
mIntr.reset(TEMP_FAILURE_RETRY(open(ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR, O_RDWR)));
if (mIntr < 0) {
PLOG(ERROR) << FFS_MTP_EP_INTR << ": cannot open intr ep";
PLOG(ERROR) << (ptp ? FFS_PTP_EP_INTR : FFS_MTP_EP_INTR) << ": cannot open intr ep";
return false;
}
}
@ -121,39 +119,8 @@ void MtpFfsHandle::advise(int fd) {
PLOG(ERROR) << "Failed to fadvise";
}
bool MtpFfsHandle::initFunctionfs() {
if (mControl < 0) { // might have already done this before
mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
if (mControl < 0) {
PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
return false;
}
if (!writeDescriptors()) {
closeConfig();
return false;
}
}
return true;
}
bool MtpFfsHandle::writeDescriptors() {
ssize_t ret = TEMP_FAILURE_RETRY(::write(mControl,
&(mPtp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
if (ret < 0) {
PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
ret = TEMP_FAILURE_RETRY(::write(mControl,
&(mPtp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
if (ret < 0) {
PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
return false;
}
}
ret = TEMP_FAILURE_RETRY(::write(mControl, &mtp_strings, sizeof(mtp_strings)));
if (ret < 0) {
PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
return false;
}
return true;
bool MtpFfsHandle::writeDescriptors(bool ptp) {
return ::android::writeDescriptors(mControl, ptp);
}
void MtpFfsHandle::closeConfig() {
@ -197,11 +164,9 @@ int MtpFfsHandle::handleEvent() {
switch (event->type) {
case FUNCTIONFS_BIND:
case FUNCTIONFS_ENABLE:
case FUNCTIONFS_RESUME:
ret = 0;
errno = 0;
break;
case FUNCTIONFS_SUSPEND:
case FUNCTIONFS_UNBIND:
case FUNCTIONFS_DISABLE:
errno = ESHUTDOWN;
@ -211,6 +176,9 @@ int MtpFfsHandle::handleEvent() {
if (handleControlRequest(&event->u.setup) == -1)
ret = -1;
break;
case FUNCTIONFS_SUSPEND:
case FUNCTIONFS_RESUME:
break;
default:
LOG(ERROR) << "Mtp Event " << event->type << " (unknown)";
}
@ -277,10 +245,8 @@ int MtpFfsHandle::handleControlRequest(const struct usb_ctrlrequest *setup) {
return 0;
}
int MtpFfsHandle::start() {
mLock.lock();
if (!openEndpoints())
int MtpFfsHandle::start(bool ptp) {
if (!openEndpoints(ptp))
return -1;
for (unsigned i = 0; i < NUM_IO_BUFS; i++) {
@ -309,33 +275,10 @@ int MtpFfsHandle::start() {
return 0;
}
int MtpFfsHandle::configure(bool usePtp) {
// Wait till previous server invocation has closed
if (!mLock.try_lock_for(std::chrono::milliseconds(300))) {
LOG(ERROR) << "MtpServer was unable to get configure lock";
return -1;
}
int ret = 0;
// If ptp is changed, the configuration must be rewritten
if (mPtp != usePtp) {
closeEndpoints();
closeConfig();
}
mPtp = usePtp;
if (!initFunctionfs()) {
ret = -1;
}
mLock.unlock();
return ret;
}
void MtpFfsHandle::close() {
io_destroy(mCtx);
closeEndpoints();
mLock.unlock();
closeConfig();
}
int MtpFfsHandle::waitEvents(struct io_buffer *buf, int min_events, struct io_event *events,

@ -29,8 +29,6 @@
namespace android {
constexpr char FFS_MTP_EP0[] = "/dev/usb-ffs/mtp/ep0";
constexpr int NUM_IO_BUFS = 2;
struct io_buffer {
@ -42,14 +40,10 @@ struct io_buffer {
};
template <class T> class MtpFfsHandleTest;
template <class T> class MtpFfsHandleTest_testControl_Test;
class MtpFfsHandle : public IMtpHandle {
template <class T> friend class MtpFfsHandleTest;
template <class T> friend class MtpFfsHandleTest_testControl_Test;
protected:
bool initFunctionfs();
bool writeDescriptors();
void closeConfig();
void closeEndpoints();
void advise(int fd);
@ -58,15 +52,12 @@ protected:
int handleEvent();
void cancelTransaction();
void doSendEvent(mtp_event me);
bool openEndpoints();
bool openEndpoints(bool ptp);
static int getPacketSize(int ffs_fd);
bool mPtp;
bool mCanceled;
std::timed_mutex mLock; // protects configure() vs main loop
android::base::unique_fd mControl;
// "in" from the host's perspective => sink for mtp server
android::base::unique_fd mBulkIn;
@ -99,12 +90,12 @@ public:
int sendFile(mtp_file_range mfr) override;
int sendEvent(mtp_event me) override;
int start() override;
int start(bool ptp) override;
void close() override;
int configure(bool ptp) override;
bool writeDescriptors(bool ptp);
MtpFfsHandle();
MtpFfsHandle(int controlFd);
~MtpFfsHandle();
};

@ -33,6 +33,7 @@
#include "MtpDebug.h"
#include "IMtpDatabase.h"
#include "MtpDescriptors.h"
#include "MtpDevHandle.h"
#include "MtpFfsCompatHandle.h"
#include "MtpFfsHandle.h"
@ -100,7 +101,7 @@ static const MtpEventCode kSupportedEventCodes[] = {
MTP_EVENT_DEVICE_PROP_CHANGED,
};
MtpServer::MtpServer(IMtpDatabase* database, bool ptp,
MtpServer::MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
@ -118,28 +119,16 @@ MtpServer::MtpServer(IMtpDatabase* database, bool ptp,
mSendObjectFileSize(0),
mSendObjectModifiedTime(0)
{
}
MtpServer::~MtpServer() {
}
IMtpHandle* MtpServer::sHandle = nullptr;
int MtpServer::configure(bool usePtp) {
bool ffs_ok = access(FFS_MTP_EP0, W_OK) == 0;
if (sHandle == nullptr) {
if (ffs_ok) {
bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
sHandle = aio_compat ? new MtpFfsCompatHandle() : new MtpFfsHandle();
} else {
sHandle = new MtpDevHandle();
}
if (ffs_ok) {
bool aio_compat = android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false);
mHandle = aio_compat ? new MtpFfsCompatHandle(controlFd) : new MtpFfsHandle(controlFd);
} else {
mHandle = new MtpDevHandle();
}
}
int ret = sHandle->configure(usePtp);
if (ret) ALOGE("Failed to configure MTP driver!");
android::base::SetProperty("sys.usb.ffs.mtp.ready", "1");
return ret;
MtpServer::~MtpServer() {
}
void MtpServer::addStorage(MtpStorage* storage) {
@ -175,19 +164,14 @@ bool MtpServer::hasStorage(MtpStorageID id) {
}
void MtpServer::run() {
if (!sHandle) {
ALOGE("MtpServer was never configured!");
return;
}
if (sHandle->start()) {
if (mHandle->start(mPtp)) {
ALOGE("Failed to start usb driver!");
sHandle->close();
mHandle->close();
return;
}
while (1) {
int ret = mRequest.read(sHandle);
int ret = mRequest.read(mHandle);
if (ret < 0) {
ALOGE("request read returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
@ -206,7 +190,7 @@ void MtpServer::run() {
|| operation == MTP_OPERATION_SET_OBJECT_PROP_VALUE
|| operation == MTP_OPERATION_SET_DEVICE_PROP_VALUE);
if (dataIn) {
int ret = mData.read(sHandle);
int ret = mData.read(mHandle);
if (ret < 0) {
ALOGE("data read returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
@ -225,7 +209,7 @@ void MtpServer::run() {
mData.setOperationCode(operation);
mData.setTransactionID(transaction);
ALOGV("sending data:");
ret = mData.write(sHandle);
ret = mData.write(mHandle);
if (ret < 0) {
ALOGE("request write returned %d, errno: %d", ret, errno);
if (errno == ECANCELED) {
@ -238,7 +222,7 @@ void MtpServer::run() {
mResponse.setTransactionID(transaction);
ALOGV("sending response %04X", mResponse.getResponseCode());
ret = mResponse.write(sHandle);
ret = mResponse.write(mHandle);
const int savedErrno = errno;
if (ret < 0) {
ALOGE("request write returned %d, errno: %d", ret, errno);
@ -262,7 +246,7 @@ void MtpServer::run() {
}
mObjectEditList.clear();
sHandle->close();
mHandle->close();
}
void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
@ -295,7 +279,7 @@ void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
mEvent.setEventCode(code);
mEvent.setTransactionID(mRequest.getTransactionID());
mEvent.setParameter(1, param1);
if (mEvent.write(sHandle))
if (mEvent.write(mHandle))
ALOGE("Mtp send event failed: %s", strerror(errno));
}
}
@ -806,7 +790,7 @@ MtpResponseCode MtpServer::doGetObject() {
mfr.transaction_id = mRequest.getTransactionID();
// then transfer the file
int ret = sHandle->sendFile(mfr);
int ret = mHandle->sendFile(mfr);
if (ret < 0) {
ALOGE("Mtp send file got error %s", strerror(errno));
if (errno == ECANCELED) {
@ -839,7 +823,7 @@ MtpResponseCode MtpServer::doGetThumb() {
// send data
mData.setOperationCode(mRequest.getOperationCode());
mData.setTransactionID(mRequest.getTransactionID());
mData.writeData(sHandle, thumb, thumbSize);
mData.writeData(mHandle, thumb, thumbSize);
free(thumb);
return MTP_RESPONSE_OK;
} else {
@ -894,7 +878,7 @@ MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
mResponse.setParameter(1, length);
// transfer the file
int ret = sHandle->sendFile(mfr);
int ret = mHandle->sendFile(mfr);
ALOGV("MTP_SEND_FILE_WITH_HEADER returned %d\n", ret);
result = MTP_RESPONSE_OK;
if (ret < 0) {
@ -1176,7 +1160,7 @@ MtpResponseCode MtpServer::doSendObject() {
}
// read the header, and possibly some data
ret = mData.read(sHandle);
ret = mData.read(mHandle);
if (ret < MTP_CONTAINER_HEADER_SIZE) {
result = MTP_RESPONSE_GENERAL_ERROR;
goto done;
@ -1224,7 +1208,7 @@ MtpResponseCode MtpServer::doSendObject() {
mfr.transaction_id = 0;
// transfer the file
ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
if ((ret < 0) && (errno == ECANCELED)) {
isCanceled = true;
@ -1353,7 +1337,7 @@ MtpResponseCode MtpServer::doSendPartialObject() {
ALOGV("receiving partial %s %" PRIu64 " %" PRIu32, filePath, offset, length);
// read the header, and possibly some data
int ret = mData.read(sHandle);
int ret = mData.read(mHandle);
if (ret < MTP_CONTAINER_HEADER_SIZE)
return MTP_RESPONSE_GENERAL_ERROR;
int initialData = ret - MTP_CONTAINER_HEADER_SIZE;
@ -1376,7 +1360,7 @@ MtpResponseCode MtpServer::doSendPartialObject() {
mfr.transaction_id = 0;
// transfer the file
ret = sHandle->receiveFile(mfr, mfr.length == 0 &&
ret = mHandle->receiveFile(mfr, mfr.length == 0 &&
initialData == MTP_BUFFER_SIZE - MTP_CONTAINER_HEADER_SIZE);
if ((ret < 0) && (errno == ECANCELED)) {
isCanceled = true;

@ -65,7 +65,7 @@ private:
MtpStorageList mStorages;
static IMtpHandle* sHandle;
IMtpHandle* mHandle;
// handle for new object, set by SendObjectInfo and used by SendObject
MtpObjectHandle mSendObjectHandle;
@ -98,7 +98,7 @@ private:
Vector<ObjectEdit*> mObjectEditList;
public:
MtpServer(IMtpDatabase* database, bool ptp,
MtpServer(IMtpDatabase* database, int controlFd, bool ptp,
const MtpString& deviceInfoManufacturer,
const MtpString& deviceInfoModel,
const MtpString& deviceInfoDeviceVersion,
@ -111,7 +111,6 @@ public:
void addStorage(MtpStorage* storage);
void removeStorage(MtpStorage* storage);
static int configure(bool usePtp);
void run();
void sendObjectAdded(MtpObjectHandle handle);

@ -64,7 +64,7 @@ protected:
MtpFfsHandleTest() {
int fd[2];
handle = std::make_unique<T>();
handle = std::make_unique<T>(-1);
EXPECT_EQ(pipe(fd), 0);
control.reset(fd[0]);
@ -84,7 +84,7 @@ protected:
intr.reset(fd[0]);
handle->mIntr.reset(fd[1]);
EXPECT_EQ(handle->start(), 0);
EXPECT_EQ(handle->start(false), 0);
}
~MtpFfsHandleTest() {
@ -95,8 +95,8 @@ protected:
typedef ::testing::Types<MtpFfsHandle, MtpFfsCompatHandle> mtpHandles;
TYPED_TEST_CASE(MtpFfsHandleTest, mtpHandles);
TYPED_TEST(MtpFfsHandleTest, testControl) {
EXPECT_TRUE(this->handle->writeDescriptors());
TYPED_TEST(MtpFfsHandleTest, testMtpControl) {
EXPECT_TRUE(this->handle->writeDescriptors(false));
struct desc_v2 desc;
struct functionfs_strings strings;
EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
@ -105,6 +105,16 @@ TYPED_TEST(MtpFfsHandleTest, testControl) {
EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
}
TYPED_TEST(MtpFfsHandleTest, testPtpControl) {
EXPECT_TRUE(this->handle->writeDescriptors(true));
struct desc_v2 desc;
struct functionfs_strings strings;
EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
EXPECT_EQ(read(this->control, &strings, sizeof(strings)), (long)sizeof(strings));
EXPECT_TRUE(std::memcmp(&desc, &ptp_desc_v2, sizeof(desc)) == 0);
EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
}
TYPED_TEST(MtpFfsHandleTest, testRead) {
EXPECT_EQ(write(this->bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
char buf[TEST_PACKET_SIZE + 1];

Loading…
Cancel
Save