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

BUG: 3402847

Change-Id: I46e90f546a8d72c273cd7f2de2d086bb6dbdc1b8
Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
Mike Lockwood
2011-02-18 09:07:14 -05:00
parent 69e19ae15b
commit 0600fff914
6 changed files with 106 additions and 32 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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