am 0600fff9: DO NOT MERGE: MTP: Add support for dynamically adding and removing storage units

* commit '0600fff9149df3af01e90d4996b70dbc1ee7c135':
  DO NOT MERGE: MTP: Add support for dynamically adding and removing storage units
This commit is contained in:
Mike Lockwood
2011-02-26 13:21:23 -08:00
committed by Android Git Automerger
6 changed files with 106 additions and 32 deletions

View File

@@ -35,6 +35,7 @@
#include "private/android_filesystem_config.h" #include "private/android_filesystem_config.h"
#include "MtpServer.h" #include "MtpServer.h"
#include "MtpStorage.h"
using namespace android; using namespace android;
@@ -56,22 +57,24 @@ class MtpThread : public Thread {
private: private:
MtpDatabase* mDatabase; MtpDatabase* mDatabase;
MtpServer* mServer; MtpServer* mServer;
String8 mStoragePath; MtpStorage* mStorage;
uint64_t mReserveSpace;
Mutex mMutex; Mutex mMutex;
bool mUsePtp; bool mUsePtp;
int mFd; int mFd;
public: public:
MtpThread(MtpDatabase* database, const char* storagePath, uint64_t reserveSpace) MtpThread(MtpDatabase* database, MtpStorage* storage)
: mDatabase(database), : mDatabase(database),
mServer(NULL), mServer(NULL),
mStoragePath(storagePath), mStorage(storage),
mReserveSpace(reserveSpace),
mFd(-1) mFd(-1)
{ {
} }
virtual ~MtpThread() {
delete mStorage;
}
void setPtpMode(bool usePtp) { void setPtpMode(bool usePtp) {
mMutex.lock(); mMutex.lock();
mUsePtp = usePtp; mUsePtp = usePtp;
@@ -86,7 +89,7 @@ public:
(mUsePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP)); (mUsePtp ? MTP_INTERFACE_MODE_PTP : MTP_INTERFACE_MODE_MTP));
mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775); mServer = new MtpServer(mFd, mDatabase, AID_MEDIA_RW, 0664, 0775);
mServer->addStorage(mStoragePath, mReserveSpace); mServer->addStorage(mStorage);
mMutex.unlock(); mMutex.unlock();
mServer->run(); mServer->run();
@@ -137,7 +140,8 @@ android_mtp_MtpServer_setup(JNIEnv *env, jobject thiz, jobject javaDatabase,
const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL); const char *storagePathStr = env->GetStringUTFChars(storagePath, NULL);
// create the thread and assign it to the smart pointer // create the thread and assign it to the smart pointer
sThread = new MtpThread(database, storagePathStr, reserveSpace); MtpStorage* storage = new MtpStorage(MTP_FIRST_STORAGE_ID, storagePathStr, reserveSpace);
sThread = new MtpThread(database, storage);
env->ReleaseStringUTFChars(storagePath, storagePathStr); env->ReleaseStringUTFChars(storagePath, storagePathStr);
#endif #endif

View File

@@ -84,6 +84,8 @@ static const MtpOperationCode kSupportedOperationCodes[] = {
static const MtpEventCode kSupportedEventCodes[] = { static const MtpEventCode kSupportedEventCodes[] = {
MTP_EVENT_OBJECT_ADDED, MTP_EVENT_OBJECT_ADDED,
MTP_EVENT_OBJECT_REMOVED, MTP_EVENT_OBJECT_REMOVED,
MTP_EVENT_STORE_ADDED,
MTP_EVENT_STORE_REMOVED,
}; };
MtpServer::MtpServer(int fd, MtpDatabase* database, MtpServer::MtpServer(int fd, MtpDatabase* database,
@@ -104,11 +106,23 @@ MtpServer::MtpServer(int fd, MtpDatabase* database,
MtpServer::~MtpServer() { MtpServer::~MtpServer() {
} }
void MtpServer::addStorage(const char* filePath, uint64_t reserveSpace) { void MtpServer::addStorage(MtpStorage* storage) {
int index = mStorages.size() + 1; Mutex::Autolock autoLock(mMutex);
index |= index << 16; // set high and low part to our index
MtpStorage* storage = new MtpStorage(index, filePath, reserveSpace); mStorages.push(storage);
addStorage(storage); sendStoreAdded(storage->getStorageID());
}
void MtpServer::removeStorage(MtpStorage* storage) {
Mutex::Autolock autoLock(mMutex);
for (int i = 0; i < mStorages.size(); i++) {
if (mStorages[i] == storage) {
mStorages.removeAt(i);
sendStoreRemoved(storage->getStorageID());
break;
}
}
} }
MtpStorage* MtpServer::getStorage(MtpStorageID id) { MtpStorage* MtpServer::getStorage(MtpStorageID id) {
@@ -122,6 +136,12 @@ MtpStorage* MtpServer::getStorage(MtpStorageID id) {
return NULL; return NULL;
} }
bool MtpServer::hasStorage(MtpStorageID id) {
if (id == 0 || id == 0xFFFFFFFF)
return mStorages.size() > 0;
return (getStorage(id) != NULL);
}
void MtpServer::run() { void MtpServer::run() {
int fd = mFD; int fd = mFD;
@@ -203,28 +223,38 @@ void MtpServer::run() {
} }
void MtpServer::sendObjectAdded(MtpObjectHandle handle) { void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
if (mSessionOpen) { LOGV("sendObjectAdded %d\n", handle);
LOGV("sendObjectAdded %d\n", handle); sendEvent(MTP_EVENT_OBJECT_ADDED, handle);
mEvent.setEventCode(MTP_EVENT_OBJECT_ADDED);
mEvent.setTransactionID(mRequest.getTransactionID());
mEvent.setParameter(1, handle);
int ret = mEvent.write(mFD);
LOGV("mEvent.write returned %d\n", ret);
}
} }
void MtpServer::sendObjectRemoved(MtpObjectHandle handle) { void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
LOGV("sendObjectRemoved %d\n", handle);
sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
}
void MtpServer::sendStoreAdded(MtpStorageID id) {
LOGV("sendStoreAdded %08X\n", id);
sendEvent(MTP_EVENT_STORE_ADDED, id);
}
void MtpServer::sendStoreRemoved(MtpStorageID id) {
LOGV("sendStoreRemoved %08X\n", id);
sendEvent(MTP_EVENT_STORE_REMOVED, id);
}
void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
if (mSessionOpen) { if (mSessionOpen) {
LOGV("sendObjectRemoved %d\n", handle); mEvent.setEventCode(code);
mEvent.setEventCode(MTP_EVENT_OBJECT_REMOVED);
mEvent.setTransactionID(mRequest.getTransactionID()); mEvent.setTransactionID(mRequest.getTransactionID());
mEvent.setParameter(1, handle); mEvent.setParameter(1, param1);
int ret = mEvent.write(mFD); int ret = mEvent.write(mFD);
LOGV("mEvent.write returned %d\n", ret); LOGV("mEvent.write returned %d\n", ret);
} }
} }
bool MtpServer::handleRequest() { bool MtpServer::handleRequest() {
Mutex::Autolock autoLock(mMutex);
MtpOperationCode operation = mRequest.getOperationCode(); MtpOperationCode operation = mRequest.getOperationCode();
MtpResponseCode response; MtpResponseCode response;
@@ -438,6 +468,9 @@ MtpResponseCode MtpServer::doGetObjectHandles() {
MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
// 0x00000000 for all objects? // 0x00000000 for all objects?
if (!hasStorage(storageID))
return MTP_RESPONSE_INVALID_STORAGE_ID;
if (parent == 0xFFFFFFFF) if (parent == 0xFFFFFFFF)
parent = 0; parent = 0;
@@ -454,6 +487,8 @@ MtpResponseCode MtpServer::doGetNumObjects() {
MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats MtpObjectFormat format = mRequest.getParameter(2); // 0 for all formats
MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent MtpObjectHandle parent = mRequest.getParameter(3); // 0xFFFFFFFF for objects with no parent
// 0x00000000 for all objects? // 0x00000000 for all objects?
if (!hasStorage(storageID))
return MTP_RESPONSE_INVALID_STORAGE_ID;
if (parent == 0xFFFFFFFF) if (parent == 0xFFFFFFFF)
parent = 0; parent = 0;
@@ -470,7 +505,9 @@ MtpResponseCode MtpServer::doGetNumObjects() {
MtpResponseCode MtpServer::doGetObjectReferences() { MtpResponseCode MtpServer::doGetObjectReferences() {
if (!mSessionOpen) if (!mSessionOpen)
return MTP_RESPONSE_SESSION_NOT_OPEN; return MTP_RESPONSE_SESSION_NOT_OPEN;
MtpStorageID handle = mRequest.getParameter(1); if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1);
// FIXME - check for invalid object handle // FIXME - check for invalid object handle
MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle); MtpObjectHandleList* handles = mDatabase->getObjectReferences(handle);
@@ -486,7 +523,10 @@ MtpResponseCode MtpServer::doGetObjectReferences() {
MtpResponseCode MtpServer::doSetObjectReferences() { MtpResponseCode MtpServer::doSetObjectReferences() {
if (!mSessionOpen) if (!mSessionOpen)
return MTP_RESPONSE_SESSION_NOT_OPEN; return MTP_RESPONSE_SESSION_NOT_OPEN;
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpStorageID handle = mRequest.getParameter(1); MtpStorageID handle = mRequest.getParameter(1);
MtpObjectHandleList* references = mData.getAUInt32(); MtpObjectHandleList* references = mData.getAUInt32();
MtpResponseCode result = mDatabase->setObjectReferences(handle, references); MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
delete references; delete references;
@@ -494,6 +534,8 @@ MtpResponseCode MtpServer::doSetObjectReferences() {
} }
MtpResponseCode MtpServer::doGetObjectPropValue() { MtpResponseCode MtpServer::doGetObjectPropValue() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectHandle handle = mRequest.getParameter(1);
MtpObjectProperty property = mRequest.getParameter(2); MtpObjectProperty property = mRequest.getParameter(2);
LOGV("GetObjectPropValue %d %s\n", handle, LOGV("GetObjectPropValue %d %s\n", handle,
@@ -503,6 +545,8 @@ MtpResponseCode MtpServer::doGetObjectPropValue() {
} }
MtpResponseCode MtpServer::doSetObjectPropValue() { MtpResponseCode MtpServer::doSetObjectPropValue() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectHandle handle = mRequest.getParameter(1);
MtpObjectProperty property = mRequest.getParameter(2); MtpObjectProperty property = mRequest.getParameter(2);
LOGV("SetObjectPropValue %d %s\n", handle, LOGV("SetObjectPropValue %d %s\n", handle,
@@ -536,6 +580,8 @@ MtpResponseCode MtpServer::doResetDevicePropValue() {
} }
MtpResponseCode MtpServer::doGetObjectPropList() { MtpResponseCode MtpServer::doGetObjectPropList() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectHandle handle = mRequest.getParameter(1);
// use uint32_t so we can support 0xFFFFFFFF // use uint32_t so we can support 0xFFFFFFFF
@@ -551,11 +597,15 @@ MtpResponseCode MtpServer::doGetObjectPropList() {
} }
MtpResponseCode MtpServer::doGetObjectInfo() { MtpResponseCode MtpServer::doGetObjectInfo() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectHandle handle = mRequest.getParameter(1);
return mDatabase->getObjectInfo(handle, mData); return mDatabase->getObjectInfo(handle, mData);
} }
MtpResponseCode MtpServer::doGetObject() { MtpResponseCode MtpServer::doGetObject() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectHandle handle = mRequest.getParameter(1);
MtpString pathBuf; MtpString pathBuf;
int64_t fileLength; int64_t fileLength;
@@ -591,6 +641,8 @@ MtpResponseCode MtpServer::doGetObject() {
} }
MtpResponseCode MtpServer::doGetPartialObject() { MtpResponseCode MtpServer::doGetPartialObject() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectHandle handle = mRequest.getParameter(1);
uint32_t offset = mRequest.getParameter(2); uint32_t offset = mRequest.getParameter(2);
uint32_t length = mRequest.getParameter(3); uint32_t length = mRequest.getParameter(3);
@@ -687,6 +739,7 @@ MtpResponseCode MtpServer::doSendObjectInfo() {
if (mSendObjectFileSize > storage->getFreeSpace()) if (mSendObjectFileSize > storage->getFreeSpace())
return MTP_RESPONSE_STORAGE_FULL; return MTP_RESPONSE_STORAGE_FULL;
LOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path,
format, parent, storageID, mSendObjectFileSize, modifiedTime); format, parent, storageID, mSendObjectFileSize, modifiedTime);
if (handle == kInvalidObjectHandle) { if (handle == kInvalidObjectHandle) {
@@ -718,6 +771,8 @@ MtpResponseCode MtpServer::doSendObjectInfo() {
} }
MtpResponseCode MtpServer::doSendObject() { MtpResponseCode MtpServer::doSendObject() {
if (!hasStorage())
return MTP_RESPONSE_GENERAL_ERROR;
MtpResponseCode result = MTP_RESPONSE_OK; MtpResponseCode result = MTP_RESPONSE_OK;
mode_t mask; mode_t mask;
int ret; int ret;
@@ -834,6 +889,8 @@ static void deletePath(const char* path) {
} }
MtpResponseCode MtpServer::doDeleteObject() { MtpResponseCode MtpServer::doDeleteObject() {
if (!hasStorage())
return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
MtpObjectHandle handle = mRequest.getParameter(1); MtpObjectHandle handle = mRequest.getParameter(1);
MtpObjectFormat format = mRequest.getParameter(2); MtpObjectFormat format = mRequest.getParameter(2);
// FIXME - support deleting all objects if handle is 0xFFFFFFFF // FIXME - support deleting all objects if handle is 0xFFFFFFFF

View File

@@ -22,9 +22,10 @@
#include "MtpResponsePacket.h" #include "MtpResponsePacket.h"
#include "MtpEventPacket.h" #include "MtpEventPacket.h"
#include "mtp.h" #include "mtp.h"
#include "MtpUtils.h" #include "MtpUtils.h"
#include <utils/threads.h>
namespace android { namespace android {
class MtpDatabase; class MtpDatabase;
@@ -62,20 +63,29 @@ private:
MtpString mSendObjectFilePath; MtpString mSendObjectFilePath;
size_t mSendObjectFileSize; size_t mSendObjectFileSize;
Mutex mMutex;
public: public:
MtpServer(int fd, MtpDatabase* database, MtpServer(int fd, MtpDatabase* database,
int fileGroup, int filePerm, int directoryPerm); int fileGroup, int filePerm, int directoryPerm);
virtual ~MtpServer(); virtual ~MtpServer();
void addStorage(const char* filePath, uint64_t reserveSpace); void addStorage(MtpStorage* storage);
inline void addStorage(MtpStorage* storage) { mStorages.push(storage); } void removeStorage(MtpStorage* storage);
MtpStorage* getStorage(MtpStorageID id);
void run(); void run();
void sendObjectAdded(MtpObjectHandle handle); void sendObjectAdded(MtpObjectHandle handle);
void sendObjectRemoved(MtpObjectHandle handle); void sendObjectRemoved(MtpObjectHandle handle);
private: private:
MtpStorage* getStorage(MtpStorageID id);
inline bool hasStorage() { return mStorages.size() > 0; }
bool hasStorage(MtpStorageID id);
void sendStoreAdded(MtpStorageID id);
void sendStoreRemoved(MtpStorageID id);
void sendEvent(MtpEventCode code, uint32_t param1);
bool handleRequest(); bool handleRequest();
MtpResponseCode doGetDeviceInfo(); MtpResponseCode doGetDeviceInfo();

View File

@@ -59,7 +59,7 @@ int MtpStorage::getAccessCapability() const {
uint64_t MtpStorage::getMaxCapacity() { uint64_t MtpStorage::getMaxCapacity() {
if (mMaxCapacity == 0) { if (mMaxCapacity == 0) {
struct statfs stat; struct statfs stat;
if (statfs(mFilePath, &stat)) if (statfs(getPath(), &stat))
return -1; return -1;
mMaxCapacity = (uint64_t)stat.f_blocks * (uint64_t)stat.f_bsize; mMaxCapacity = (uint64_t)stat.f_blocks * (uint64_t)stat.f_bsize;
} }
@@ -68,7 +68,7 @@ uint64_t MtpStorage::getMaxCapacity() {
uint64_t MtpStorage::getFreeSpace() { uint64_t MtpStorage::getFreeSpace() {
struct statfs stat; struct statfs stat;
if (statfs(mFilePath, &stat)) if (statfs(getPath(), &stat))
return -1; return -1;
uint64_t freeSpace = (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize; uint64_t freeSpace = (uint64_t)stat.f_bavail * (uint64_t)stat.f_bsize;
return (freeSpace > mReserveSpace ? freeSpace - mReserveSpace : 0); return (freeSpace > mReserveSpace ? freeSpace - mReserveSpace : 0);

View File

@@ -17,6 +17,7 @@
#ifndef _MTP_STORAGE_H #ifndef _MTP_STORAGE_H
#define _MTP_STORAGE_H #define _MTP_STORAGE_H
#include "MtpTypes.h"
#include "mtp.h" #include "mtp.h"
namespace android { namespace android {
@@ -27,7 +28,7 @@ class MtpStorage {
private: private:
MtpStorageID mStorageID; MtpStorageID mStorageID;
const char* mFilePath; MtpString mFilePath;
uint64_t mMaxCapacity; uint64_t mMaxCapacity;
// amount of free space to leave unallocated // amount of free space to leave unallocated
uint64_t mReserveSpace; uint64_t mReserveSpace;
@@ -44,7 +45,7 @@ public:
uint64_t getMaxCapacity(); uint64_t getMaxCapacity();
uint64_t getFreeSpace(); uint64_t getFreeSpace();
const char* getDescription() const; const char* getDescription() const;
inline const char* getPath() const { return mFilePath; } inline const char* getPath() const { return (const char *)mFilePath; }
}; };
}; // namespace android }; // namespace android

View File

@@ -22,6 +22,8 @@
#define MTP_STANDARD_VERSION 100 #define MTP_STANDARD_VERSION 100
#define MTP_FIRST_STORAGE_ID 0x00010001
// Container Types // Container Types
#define MTP_CONTAINER_TYPE_UNDEFINED 0 #define MTP_CONTAINER_TYPE_UNDEFINED 0
#define MTP_CONTAINER_TYPE_COMMAND 1 #define MTP_CONTAINER_TYPE_COMMAND 1