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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user