summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gui/action.cpp1
-rw-r--r--gui/partitionlist.cpp1
-rwxr-xr-xmtp/MtpDatabase.h1
-rw-r--r--mtp/MtpMessage.hpp33
-rwxr-xr-xmtp/MtpServer.cpp29
-rwxr-xr-xmtp/MtpStorage.cpp58
-rwxr-xr-xmtp/MtpStorage.h1
-rwxr-xr-xmtp/btree.cpp1
-rwxr-xr-xmtp/mtp_MtpDatabase.cpp7
-rwxr-xr-xmtp/mtp_MtpDatabase.hpp1
-rwxr-xr-xmtp/mtp_MtpServer.cpp52
-rwxr-xr-xmtp/mtp_MtpServer.hpp5
-rw-r--r--mtp/tw_sys_atomics.h67
-rwxr-xr-xmtp/twrpMtp.cpp7
-rwxr-xr-xmtp/twrpMtp.hpp3
-rw-r--r--partition.cpp26
-rw-r--r--partitionmanager.cpp163
-rw-r--r--partitions.hpp8
18 files changed, 420 insertions, 44 deletions
diff --git a/gui/action.cpp b/gui/action.cpp
index 27fd7a5d7..ff2c2e00f 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -462,6 +462,7 @@ int GUIAction::doAction(Action action, int isThreaded /* = 0 */)
gui_print("Simulating actions...\n");
} else if (!simulate) {
PartitionManager.Mount_By_Path(arg, true);
+ PartitionManager.Add_MTP_Storage(arg);
} else
gui_print("Simulating actions...\n");
return 0;
diff --git a/gui/partitionlist.cpp b/gui/partitionlist.cpp
index 2d464e1b6..9cc6a777b 100644
--- a/gui/partitionlist.cpp
+++ b/gui/partitionlist.cpp
@@ -749,6 +749,7 @@ int GUIPartitionList::NotifyTouch(TOUCH_STATE state, int x, int y)
if (!mList.at(actualSelection).selected) {
if (PartitionManager.Mount_By_Path(mList.at(actualSelection).Mount_Point, true)) {
mList.at(actualSelection).selected = 1;
+ PartitionManager.Add_MTP_Storage(mList.at(actualSelection).Mount_Point);
mUpdate = 1;
}
} else {
diff --git a/mtp/MtpDatabase.h b/mtp/MtpDatabase.h
index c25e9b24c..a0ff8dace 100755
--- a/mtp/MtpDatabase.h
+++ b/mtp/MtpDatabase.h
@@ -61,6 +61,7 @@ public:
virtual MtpDevicePropertyList* getSupportedDeviceProperties() = 0;
virtual void createDB(MtpStorage* storage, MtpStorageID storageID) = 0;
+ virtual void destroyDB(MtpStorageID storageID) = 0;
virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
MtpObjectProperty property,
diff --git a/mtp/MtpMessage.hpp b/mtp/MtpMessage.hpp
new file mode 100644
index 000000000..272da1743
--- /dev/null
+++ b/mtp/MtpMessage.hpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 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.
+ *
+ * Copyright (C) 2014 TeamWin - bigbiff and Dees_Troy mtp database conversion to C++
+ */
+
+#ifndef _MTPMESSAGE_HPP
+#define _MTPMESSAGE_HPP
+
+#define MTP_MESSAGE_ADD_STORAGE 1
+#define MTP_MESSAGE_REMOVE_STORAGE 2
+
+struct mtpmsg {
+ int message_type; // 1 is add, 2 is remove, see above
+ unsigned int storage_id;
+ const char* display;
+ const char* path;
+ uint64_t maxFileSize;
+};
+
+#endif //_MTPMESSAGE_HPP
diff --git a/mtp/MtpServer.cpp b/mtp/MtpServer.cpp
index f4af2b948..f99554b03 100755
--- a/mtp/MtpServer.cpp
+++ b/mtp/MtpServer.cpp
@@ -116,9 +116,13 @@ MtpServer::~MtpServer() {
}
void MtpServer::addStorage(MtpStorage* storage) {
+ android::Mutex::Autolock autoLock(mMutex);
MTPD("addStorage(): storage: %x\n", storage);
+ if (getStorage(storage->getStorageID()) != NULL) {
+ MTPE("MtpServer::addStorage Storage for storage ID %i already exists.\n", storage->getStorageID());
+ return;
+ }
mDatabase->createDB(storage, storage->getStorageID());
- android::Mutex::Autolock autoLock(mMutex);
mStorages.push(storage);
sendStoreAdded(storage->getStorageID());
}
@@ -128,11 +132,31 @@ void MtpServer::removeStorage(MtpStorage* storage) {
for (size_t i = 0; i < mStorages.size(); i++) {
if (mStorages[i] == storage) {
+ MTPD("MtpServer::removeStorage calling sendStoreRemoved\n");
+ // First lock the mutex so that the inotify thread and main
+ // thread do not do anything while we remove the storage
+ // item, and to make sure we don't remove the item while an
+ // operation is in progress
+ mDatabase->lockMutex();
+ // Grab the storage ID before we delete the item from the
+ // database
+ MtpStorageID storageID = storage->getStorageID();
+ // Remove the item from the mStorages from the vector. At
+ // this point the main thread will no longer be able to find
+ // this storage item anymore.
mStorages.removeAt(i);
- sendStoreRemoved(storage->getStorageID());
+ // Destroy the storage item, free up all the memory, kill
+ // the inotify thread.
+ mDatabase->destroyDB(storageID);
+ // Tell the host OS that the storage item is gone.
+ sendStoreRemoved(storageID);
+ // Unlock any remaining mutexes on other storage devices.
+ // If no storage devices exist anymore this will do nothing.
+ mDatabase->unlockMutex();
break;
}
}
+ MTPD("MtpServer::removeStorage DONE\n");
}
MtpStorage* MtpServer::getStorage(MtpStorageID id) {
@@ -275,6 +299,7 @@ void MtpServer::sendStoreAdded(MtpStorageID id) {
void MtpServer::sendStoreRemoved(MtpStorageID id) {
MTPD("sendStoreRemoved %08X\n", id);
sendEvent(MTP_EVENT_STORE_REMOVED, id);
+ MTPD("MtpServer::sendStoreRemoved done\n");
}
void MtpServer::sendEvent(MtpEventCode code, uint32_t param1) {
diff --git a/mtp/MtpStorage.cpp b/mtp/MtpStorage.cpp
index 319be094b..ab4f8e044 100755
--- a/mtp/MtpStorage.cpp
+++ b/mtp/MtpStorage.cpp
@@ -36,6 +36,7 @@
#include <signal.h>
#include <sys/inotify.h>
#include <fcntl.h>
+#include "tw_sys_atomics.h"
#define WATCH_FLAGS ( IN_CREATE | IN_DELETE | IN_MOVE | IN_MODIFY )
@@ -54,6 +55,8 @@ MtpStorage::MtpStorage(MtpStorageID id, const char* filePath,
MTPI("MtpStorage id: %d path: %s\n", id, filePath);
inotify_thread = 0;
inotify_fd = -1;
+ // Threading has not started yet so we should be safe to set these directly instead of using atomics
+ inotify_thread_kill = 0;
sendEvents = false;
handleCurrentlySending = 0;
use_mutex = true;
@@ -63,25 +66,32 @@ MtpStorage::MtpStorage(MtpStorageID id, const char* filePath,
}
if (pthread_mutex_init(&inMutex, NULL) != 0) {
MTPE("Failed to init inMutex\n");
+ pthread_mutex_destroy(&mtpMutex);
use_mutex = false;
}
-
}
MtpStorage::~MtpStorage() {
if (inotify_thread) {
- // TODO: what does this do? manpage says it does not kill the thread
- pthread_kill(inotify_thread, 0);
+ __tw_atomic_cmpxchg(0, 1, &inotify_thread_kill);
+ //inotify_thread_kill = 1;
+ MTPD("joining inotify_thread after sending the kill notification.\n");
+ pthread_join(inotify_thread, NULL); // There's not much we can do if there's an error here
+ inotify_thread = 0;
+ MTPD("~MtpStorage removing inotify watches and closing inotify_fd\n");
for (std::map<int, Tree*>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
inotify_rm_watch(inotify_fd, i->first);
}
close(inotify_fd);
+ inotifymap.clear();
}
- for (iter i = mtpmap.begin(); i != mtpmap.end(); i++) {
- delete i->second;
- }
+ // Deleting the root tree causes a cascade in btree.cpp that ends up
+ // deleting all of the trees and nodes.
+ delete mtpmap[0];
+ mtpmap.clear();
if (use_mutex) {
use_mutex = false;
+ MTPD("~MtpStorage destroying mutexes\n");
pthread_mutex_destroy(&mtpMutex);
pthread_mutex_destroy(&inMutex);
}
@@ -566,9 +576,22 @@ int MtpStorage::getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty
pthread_t MtpStorage::inotify(void) {
pthread_t thread;
+ pthread_attr_t tattr;
+
+ if (pthread_attr_init(&tattr)) {
+ MTPE("Unable to pthread_attr_init\n");
+ return 0;
+ }
+ if (pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE)) {
+ MTPE("Error setting pthread_attr_setdetachstate\n");
+ return 0;
+ }
ThreadPtr inotifyptr = &MtpStorage::inotify_t;
PThreadPtr p = *(PThreadPtr*)&inotifyptr;
- pthread_create(&thread, NULL, p, this);
+ pthread_create(&thread, &tattr, p, this);
+ if (pthread_attr_destroy(&tattr)) {
+ MTPE("Failed to pthread_attr_destroy\n");
+ }
return thread;
}
@@ -669,10 +692,20 @@ int MtpStorage::inotify_t(void) {
#define EVENT_SIZE ( sizeof(struct inotify_event) )
#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16) )
char buf[EVENT_BUF_LEN];
+ fd_set fdset;
+ struct timeval seltmout;
+ int sel_ret;
MTPD("inotify thread starting.\n");
- while (true) {
+ while (__tw_atomic_cmpxchg(0, inotify_thread_kill, &inotify_thread_kill) == 0) {
+ FD_ZERO(&fdset);
+ FD_SET(inotify_fd, &fdset);
+ seltmout.tv_sec = 0;
+ seltmout.tv_usec = 25000;
+ sel_ret = select(inotify_fd + 1, &fdset, NULL, NULL, &seltmout);
+ if (sel_ret == 0)
+ continue;
int i = 0;
int len = read(inotify_fd, buf, EVENT_BUF_LEN);
@@ -682,7 +715,7 @@ int MtpStorage::inotify_t(void) {
MTPE("inotify_t Can't read inotify events\n");
}
- while (i < len) {
+ while (i < len && __tw_atomic_cmpxchg(0, inotify_thread_kill, &inotify_thread_kill) == 0) {
struct inotify_event *event = (struct inotify_event *) &buf[i];
if (event->len) {
MTPD("inotify event: wd: %i, mask: %x, name: %s\n", event->wd, event->mask, event->name);
@@ -693,11 +726,12 @@ int MtpStorage::inotify_t(void) {
i += EVENT_SIZE + event->len;
}
}
-
- for (std::map<int, Tree*>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
+ MTPD("inotify_thread_kill received!\n");
+ // This cleanup is handled in the destructor.
+ /*for (std::map<int, Tree*>::iterator i = inotifymap.begin(); i != inotifymap.end(); i++) {
inotify_rm_watch(inotify_fd, i->first);
}
- close(inotify_fd);
+ close(inotify_fd);*/
return 0;
}
diff --git a/mtp/MtpStorage.h b/mtp/MtpStorage.h
index 418e3db8c..cdbb73b50 100755
--- a/mtp/MtpStorage.h
+++ b/mtp/MtpStorage.h
@@ -113,6 +113,7 @@ private:
bool use_mutex;
pthread_mutex_t inMutex; // inotify mutex
pthread_mutex_t mtpMutex; // main mtp mutex
+ int inotify_thread_kill;
};
#endif // _MTP_STORAGE_H
diff --git a/mtp/btree.cpp b/mtp/btree.cpp
index 3a5648db0..e53afab98 100755
--- a/mtp/btree.cpp
+++ b/mtp/btree.cpp
@@ -28,6 +28,7 @@ Tree::Tree(MtpObjectHandle handle, MtpObjectHandle parent, const std::string& na
Tree::~Tree() {
for (std::map<MtpObjectHandle, Node*>::iterator it = entries.begin(); it != entries.end(); ++it)
delete it->second;
+ entries.clear();
}
int Tree::getCount(void) {
diff --git a/mtp/mtp_MtpDatabase.cpp b/mtp/mtp_MtpDatabase.cpp
index 05bb5d9fb..17053f1de 100755
--- a/mtp/mtp_MtpDatabase.cpp
+++ b/mtp/mtp_MtpDatabase.cpp
@@ -233,10 +233,17 @@ void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
}
void MyMtpDatabase::createDB(MtpStorage* storage, MtpStorageID storageID) {
+ MTPD("MyMtpDatabase::createDB called\n");
storagemap[storageID] = storage;
storage->createDB();
}
+void MyMtpDatabase::destroyDB(MtpStorageID storageID) {
+ MtpStorage* storage = storagemap[storageID];
+ storagemap.erase(storageID);
+ delete storage;
+}
+
MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
MtpObjectFormat format,
MtpObjectHandle parent) {
diff --git a/mtp/mtp_MtpDatabase.hpp b/mtp/mtp_MtpDatabase.hpp
index cc8097be2..49e59135a 100755
--- a/mtp/mtp_MtpDatabase.hpp
+++ b/mtp/mtp_MtpDatabase.hpp
@@ -64,6 +64,7 @@ public:
virtual ~MyMtpDatabase();
void createDB(MtpStorage* storage, MtpStorageID storageID);
+ void destroyDB(MtpStorageID storageID);
virtual MtpObjectHandle beginSendObject(const char* path,
MtpObjectFormat format,
MtpObjectHandle parent,
diff --git a/mtp/mtp_MtpServer.cpp b/mtp/mtp_MtpServer.cpp
index 17facdd70..f49270fdf 100755
--- a/mtp/mtp_MtpServer.cpp
+++ b/mtp/mtp_MtpServer.cpp
@@ -25,11 +25,13 @@
#include <fcntl.h>
#include <vector>
#include <utils/threads.h>
+#include <pthread.h>
#include "mtp_MtpServer.hpp"
#include "MtpServer.h"
#include "MtpStorage.h"
#include "MtpDebug.h"
+#include "MtpMessage.hpp"
#include <string>
@@ -37,6 +39,11 @@ void twmtp_MtpServer::start()
{
if (setup() == 0) {
add_storage();
+ MTPD("Starting add / remove mtppipe monitor thread\n");
+ pthread_t thread;
+ ThreadPtr mtpptr = &twmtp_MtpServer::mtppipe_thread;
+ PThreadPtr p = *(PThreadPtr*)&mtpptr;
+ pthread_create(&thread, NULL, p, this);
server->run();
}
}
@@ -140,9 +147,52 @@ void twmtp_MtpServer::remove_storage(int storageId)
if (server) {
MtpStorage* storage = server->getStorage(storageId);
if (storage) {
+ MTPD("twmtp_MtpServer::remove_storage calling removeStorage\n");
server->removeStorage(storage);
- delete storage;
}
} else
MTPD("server is null in remove_storage");
+ MTPD("twmtp_MtpServer::remove_storage DONE\n");
+}
+
+int twmtp_MtpServer::mtppipe_thread(void)
+{
+ if (mtp_read_pipe == -1) {
+ MTPD("mtppipe_thread exiting because mtp_read_pipe not set\n");
+ return 0;
+ }
+ MTPD("Starting twmtp_MtpServer::mtppipe_thread\n");
+ int read_count;
+ struct mtpmsg mtp_message;
+ while (1) {
+ read_count = ::read(mtp_read_pipe, &mtp_message, sizeof(mtp_message));
+ MTPD("read %i from mtppipe\n", read_count);
+ if (read_count == sizeof(mtp_message)) {
+ if (mtp_message.message_type == MTP_MESSAGE_ADD_STORAGE) {
+ MTPI("mtppipe add storage %i '%s'\n", mtp_message.storage_id, mtp_message.path);
+ long reserveSpace = 1;
+ bool removable = false;
+ MtpStorage* storage = new MtpStorage(mtp_message.storage_id, mtp_message.path, mtp_message.display, reserveSpace, removable, mtp_message.maxFileSize, refserver);
+ server->addStorage(storage);
+ MTPD("mtppipe done adding storage\n");
+ } else if (mtp_message.message_type == MTP_MESSAGE_REMOVE_STORAGE) {
+ MTPI("mtppipe remove storage %i\n", mtp_message.storage_id);
+ remove_storage(mtp_message.storage_id);
+ MTPD("mtppipe done removing storage\n");
+ } else {
+ MTPE("Unknown mtppipe message value: %i\n", mtp_message.message_type);
+ }
+ } else {
+ MTPE("twmtp_MtpServer::mtppipe_thread unexpected read_count %i\n", read_count);
+ close(mtp_read_pipe);
+ break;
+ }
+ }
+ MTPD("twmtp_MtpServer::mtppipe_thread closing\n");
+ return 0;
+}
+
+void twmtp_MtpServer::set_read_pipe(int pipe)
+{
+ mtp_read_pipe = pipe;
}
diff --git a/mtp/mtp_MtpServer.hpp b/mtp/mtp_MtpServer.hpp
index 3153e80bf..622ed6d6f 100755
--- a/mtp/mtp_MtpServer.hpp
+++ b/mtp/mtp_MtpServer.hpp
@@ -52,11 +52,16 @@ class twmtp_MtpServer {
void add_storage();
void remove_storage(int storageId);
void set_storages(storages* mtpstorages);
+ void set_read_pipe(int pipe);
storages *stores;
private:
+ typedef int (twmtp_MtpServer::*ThreadPtr)(void);
+ typedef void* (*PThreadPtr)(void *);
+ int mtppipe_thread(void);
bool usePtp;
MtpServer* server;
MtpServer* refserver;
+ int mtp_read_pipe;
};
#endif
diff --git a/mtp/tw_sys_atomics.h b/mtp/tw_sys_atomics.h
new file mode 100644
index 000000000..6349a931d
--- /dev/null
+++ b/mtp/tw_sys_atomics.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _TW_SYS_ATOMICS_H
+#define _TW_SYS_ATOMICS_H
+
+#include <sys/cdefs.h>
+#include <sys/time.h>
+
+__BEGIN_DECLS
+
+/* Note: atomic operations that were exported by the C library didn't
+ * provide any memory barriers, which created potential issues on
+ * multi-core devices. We now define them as inlined calls to
+ * GCC sync builtins, which always provide a full barrier.
+ *
+ * NOTE: The C library still exports atomic functions by the same
+ * name to ensure ABI stability for existing NDK machine code.
+ *
+ * If you are an NDK developer, we encourage you to rebuild your
+ * unmodified sources against this header as soon as possible.
+ */
+
+/* This was kanged from Android 4.4 bionic/libc/include/sys/atomics.h
+ * This header was removed in Android 5.0 in favor of stdatomics.h but
+ * to maintain compatibility across multiple trees, we are including our
+ * own copy.
+ */
+
+#ifndef __ATOMIC_INLINE__
+#define __ATOMIC_INLINE__ static __inline__ __attribute__((always_inline))
+#endif
+
+__ATOMIC_INLINE__ int
+__tw_atomic_cmpxchg(int old_value, int new_value, volatile int* ptr)
+{
+ /* We must return 0 on success */
+ return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+__END_DECLS
+
+#endif /* _TW_SYS_ATOMICS_H */
diff --git a/mtp/twrpMtp.cpp b/mtp/twrpMtp.cpp
index d9db4246e..d47b8fa0d 100755
--- a/mtp/twrpMtp.cpp
+++ b/mtp/twrpMtp.cpp
@@ -72,12 +72,14 @@ twrpMtp::twrpMtp(int debug_enabled = 0) {
if (debug_enabled)
MtpDebug::enableDebug();
mtpstorages = new storages;
+ mtp_read_pipe = -1;
}
int twrpMtp::start(void) {
MTPI("Starting MTP\n");
twmtp_MtpServer *mtp = new twmtp_MtpServer();
mtp->set_storages(mtpstorages);
+ mtp->set_read_pipe(mtp_read_pipe);
mtp->start();
return 0;
}
@@ -90,7 +92,7 @@ pthread_t twrpMtp::threadserver(void) {
return thread;
}
-pid_t twrpMtp::forkserver(void) {
+pid_t twrpMtp::forkserver(int mtppipe[2]) {
pid_t pid;
if ((pid = fork()) == -1) {
MTPE("MTP fork failed.\n");
@@ -98,8 +100,11 @@ pid_t twrpMtp::forkserver(void) {
}
if (pid == 0) {
// Child process
+ close(mtppipe[1]); // Child closes write side
+ mtp_read_pipe = mtppipe[0];
start();
MTPD("MTP child process exited.\n");
+ close(mtppipe[0]);
_exit(0);
} else {
return pid;
diff --git a/mtp/twrpMtp.hpp b/mtp/twrpMtp.hpp
index 3aaa96414..ec7cd4b59 100755
--- a/mtp/twrpMtp.hpp
+++ b/mtp/twrpMtp.hpp
@@ -35,7 +35,7 @@ class twrpMtp {
public:
twrpMtp(int debug_enabled /* = 0 */);
pthread_t threadserver(void);
- pid_t forkserver(void);
+ pid_t forkserver(int mtppipe[2]);
void addStorage(std::string display, std::string path, int mtpid, uint64_t maxFileSize);
private:
int start(void);
@@ -43,5 +43,6 @@ class twrpMtp {
typedef void* (*PThreadPtr)(void *);
storages *mtpstorages;
storage *s;
+ int mtp_read_pipe;
};
#endif
diff --git a/partition.cpp b/partition.cpp
index b3c436f8b..b20367f77 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -153,6 +153,7 @@ TWPartition::TWPartition() {
Ignore_Blkid = false;
Retain_Layout_Version = false;
Crypto_Key_Location = "footer";
+ MTP_Storage_ID = 0;
}
TWPartition::~TWPartition(void) {
@@ -1028,7 +1029,7 @@ bool TWPartition::UnMount(bool Display_Error) {
return true; // Never unmount system if you're not supposed to unmount it
if (Is_Storage)
- TWFunc::Toggle_MTP(false);
+ PartitionManager.Remove_MTP_Storage(MTP_Storage_ID);
if (!Symlink_Mount_Point.empty())
umount(Symlink_Mount_Point.c_str());
@@ -1049,7 +1050,7 @@ bool TWPartition::UnMount(bool Display_Error) {
}
bool TWPartition::Wipe(string New_File_System) {
- bool wiped = false, update_crypt = false, recreate_media = true, mtp_toggle = true;
+ bool wiped = false, update_crypt = false, recreate_media = true;
int check;
string Layout_Filename = Mount_Point + "/.layout_version";
@@ -1069,7 +1070,6 @@ bool TWPartition::Wipe(string New_File_System) {
if (Has_Data_Media && Current_File_System == New_File_System) {
wiped = Wipe_Data_Without_Wiping_Media();
recreate_media = false;
- mtp_toggle = false;
} else {
DataManager::GetValue(TW_RM_RF_VAR, check);
@@ -1088,9 +1088,6 @@ bool TWPartition::Wipe(string New_File_System) {
else if (New_File_System == "f2fs")
wiped = Wipe_F2FS();
else {
- if (Is_Storage) {
- TWFunc::Toggle_MTP(true);
- }
LOGERR("Unable to wipe '%s' -- unknown file system '%s'\n", Mount_Point.c_str(), New_File_System.c_str());
unlink("/.layout_version");
return false;
@@ -1123,8 +1120,8 @@ bool TWPartition::Wipe(string New_File_System) {
Recreate_Media_Folder();
}
}
- if (Is_Storage && mtp_toggle) {
- TWFunc::Toggle_MTP(true);
+ if (Is_Storage) {
+ PartitionManager.Add_MTP_Storage(MTP_Storage_ID);
}
return wiped;
}
@@ -1377,20 +1374,22 @@ bool TWPartition::Wipe_Encryption() {
Is_Decrypted = false;
Is_Encrypted = false;
Find_Actual_Block_Device();
- bool mtp_was_enabled = TWFunc::Toggle_MTP(false);
if (Wipe(Fstab_File_System)) {
Has_Data_Media = Save_Data_Media;
if (Has_Data_Media && !Symlink_Mount_Point.empty()) {
Recreate_Media_Folder();
+ if (Mount(false))
+ PartitionManager.Add_MTP_Storage(MTP_Storage_ID);
}
#ifndef TW_OEM_BUILD
gui_print("You may need to reboot recovery to be able to use /data again.\n");
#endif
- TWFunc::Toggle_MTP(mtp_was_enabled);
return true;
} else {
Has_Data_Media = Save_Data_Media;
LOGERR("Unable to format to remove encryption.\n");
+ if (Has_Data_Media && Mount(false))
+ PartitionManager.Add_MTP_Storage(MTP_Storage_ID);
return false;
}
return false;
@@ -1599,10 +1598,13 @@ bool TWPartition::Wipe_MTD() {
}
bool TWPartition::Wipe_RMRF() {
- if (Is_Storage)
- TWFunc::Toggle_MTP(false);
if (!Mount(true))
return false;
+ // This is the only wipe that leaves the partition mounted, so we
+ // must manually remove the partition from MTP if it is a storage
+ // partition.
+ if (Is_Storage)
+ PartitionManager.Remove_MTP_Storage(MTP_Storage_ID);
gui_print("Removing all files under '%s'\n", Mount_Point.c_str());
TWFunc::removeDir(Mount_Point, true);
diff --git a/partitionmanager.cpp b/partitionmanager.cpp
index 92b287557..ebd8c9675 100644
--- a/partitionmanager.cpp
+++ b/partitionmanager.cpp
@@ -43,6 +43,7 @@
#ifdef TW_HAS_MTP
#include "mtp/mtp_MtpServer.hpp"
#include "mtp/twrpMtp.hpp"
+#include "mtp/MtpMessage.hpp"
#endif
extern "C" {
@@ -57,6 +58,7 @@ extern bool datamedia;
TWPartitionManager::TWPartitionManager(void) {
mtp_was_enabled = false;
+ mtp_write_fd = -1;
}
int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error) {
@@ -64,6 +66,7 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
char fstab_line[MAX_FSTAB_LINE_LENGTH];
TWPartition* settings_partition = NULL;
TWPartition* andsec_partition = NULL;
+ unsigned int storageid = 1 << 16; // upper 16 bits are for physical storage device, we pretend to have only one
fstabFile = fopen(Fstab_Filename.c_str(), "rt");
if (fstabFile == NULL) {
@@ -82,6 +85,10 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
memset(fstab_line, 0, sizeof(fstab_line));
if (partition->Process_Fstab_Line(line, Display_Error)) {
+ if (partition->Is_Storage) {
+ ++storageid;
+ partition->MTP_Storage_ID = storageid;
+ }
if (!settings_partition && partition->Is_Settings_Storage && partition->Is_Present) {
settings_partition = partition;
} else {
@@ -106,6 +113,9 @@ int TWPartitionManager::Process_Fstab(string Fstab_Filename, bool Display_Error)
datamedia = true;
Dat->Setup_Data_Media();
settings_partition = Dat;
+ // Since /data was not considered a storage partition earlier, we still need to assign an MTP ID
+ ++storageid;
+ Dat->MTP_Storage_ID = storageid;
}
}
if (!settings_partition) {
@@ -301,6 +311,8 @@ void TWPartitionManager::Output_Partition(TWPartition* Part) {
printf(" Backup_Method: %s\n", back_meth.c_str());
if (Part->Mount_Flags || !Part->Mount_Options.empty())
printf(" Mount_Flags=0x%8x, Mount_Options=%s\n", Part->Mount_Flags, Part->Mount_Options.c_str());
+ if (Part->MTP_Storage_ID)
+ printf(" MTP_Storage_ID: %i\n", Part->MTP_Storage_ID);
printf("\n");
}
@@ -1146,13 +1158,10 @@ int TWPartitionManager::Wipe_Media_From_Data(void) {
return false;
gui_print("Wiping internal storage -- /data/media...\n");
- mtp_was_enabled = TWFunc::Toggle_MTP(false);
+ Remove_MTP_Storage(dat->MTP_Storage_ID);
TWFunc::removeDir("/data/media", false);
if (mkdir("/data/media", S_IRWXU | S_IRWXG | S_IWGRP | S_IXGRP) != 0) {
- if (mtp_was_enabled) {
- if (!Enable_MTP())
- Disable_MTP();
- }
+ Add_MTP_Storage(dat->MTP_Storage_ID);
return false;
}
if (dat->Has_Data_Media) {
@@ -1161,10 +1170,7 @@ int TWPartitionManager::Wipe_Media_From_Data(void) {
dat->UnMount(false);
dat->Mount(false);
}
- if (mtp_was_enabled) {
- if (!Enable_MTP())
- Disable_MTP();
- }
+ Add_MTP_Storage(dat->MTP_Storage_ID);
return true;
} else {
LOGERR("Unable to locate /data.\n");
@@ -1485,7 +1491,7 @@ int TWPartitionManager::usb_storage_enable(void) {
if (TWFunc::Path_Exists(lun_file))
has_multiple_lun = true;
}
- mtp_was_enabled = TWFunc::Toggle_MTP(false);
+ mtp_was_enabled = TWFunc::Toggle_MTP(false); // Must disable MTP for USB Storage
if (!has_multiple_lun) {
LOGINFO("Device doesn't have multiple lun files, mount current storage\n");
sprintf(lun_file, CUSTOM_LUN_FILE, 0);
@@ -1896,6 +1902,14 @@ bool TWPartitionManager::Enable_MTP(void) {
char vendor[PROPERTY_VALUE_MAX];
char product[PROPERTY_VALUE_MAX];
int count = 0;
+
+ int mtppipe[2];
+
+ if (pipe(mtppipe) < 0) {
+ LOGERR("Error creating MTP pipe\n");
+ return false;
+ }
+
property_set("sys.usb.config", "none");
property_get("usb.vendor", vendor, "18D1");
property_get("usb.product.mtpadb", product, "4EE2");
@@ -1910,24 +1924,29 @@ bool TWPartitionManager::Enable_MTP(void) {
* twrp set tw_mtp_debug 1
*/
twrpMtp *mtp = new twrpMtp(DataManager::GetIntValue("tw_mtp_debug"));
- unsigned int storageid = 1 << 16; // upper 16 bits are for physical storage device, we pretend to have only one
for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
if ((*iter)->Is_Storage && (*iter)->Is_Present && (*iter)->Mount(false)) {
- ++storageid;
- printf("twrp addStorage %s, mtpstorageid: %u\n", (*iter)->Storage_Path.c_str(), storageid);
- mtp->addStorage((*iter)->Storage_Name, (*iter)->Storage_Path, storageid, (*iter)->Get_Max_FileSize());
+ printf("twrp addStorage %s, mtpstorageid: %u\n", (*iter)->Storage_Path.c_str(), (*iter)->MTP_Storage_ID);
+ mtp->addStorage((*iter)->Storage_Name, (*iter)->Storage_Path, (*iter)->MTP_Storage_ID, (*iter)->Get_Max_FileSize());
count++;
}
}
if (count) {
- mtppid = mtp->forkserver();
+ mtppid = mtp->forkserver(mtppipe);
if (mtppid) {
+ close(mtppipe[0]); // Host closes read side
+ mtp_write_fd = mtppipe[1];
DataManager::SetValue("tw_mtp_enabled", 1);
return true;
} else {
+ close(mtppipe[0]);
+ close(mtppipe[1]);
LOGERR("Failed to enable MTP\n");
return false;
}
+ } else {
+ close(mtppipe[0]);
+ close(mtppipe[1]);
}
LOGERR("No valid storage partitions found for MTP.\n");
#else
@@ -1956,6 +1975,8 @@ bool TWPartitionManager::Disable_MTP(void) {
mtppid = 0;
// We don't care about the exit value, but this prevents a zombie process
waitpid(mtppid, &status, 0);
+ close(mtp_write_fd);
+ mtp_write_fd = -1;
}
property_set("sys.usb.config", "adb");
DataManager::SetValue("tw_mtp_enabled", 0);
@@ -1966,3 +1987,115 @@ bool TWPartitionManager::Disable_MTP(void) {
return false;
#endif
}
+
+TWPartition* TWPartitionManager::Find_Partition_By_MTP_Storage_ID(unsigned int Storage_ID) {
+ std::vector<TWPartition*>::iterator iter;
+
+ for (iter = Partitions.begin(); iter != Partitions.end(); iter++) {
+ if ((*iter)->MTP_Storage_ID == Storage_ID)
+ return (*iter);
+ }
+ return NULL;
+}
+
+bool TWPartitionManager::Add_Remove_MTP_Storage(TWPartition* Part, int message_type) {
+#ifdef TW_HAS_MTP
+ struct mtpmsg mtp_message;
+
+ if (!mtppid)
+ return false; // MTP is disabled
+
+ if (mtp_write_fd < 0) {
+ LOGERR("MTP: mtp_write_fd is not set\n");
+ return false;
+ }
+
+ if (Part) {
+ if (message_type == MTP_MESSAGE_REMOVE_STORAGE) {
+ mtp_message.message_type = MTP_MESSAGE_REMOVE_STORAGE; // Remove
+ LOGINFO("sending message to remove %i\n", Part->MTP_Storage_ID);
+ mtp_message.storage_id = Part->MTP_Storage_ID;
+ if (write(mtp_write_fd, &mtp_message, sizeof(mtp_message)) <= 0) {
+ LOGERR("error sending message to remove storage %i\n", Part->MTP_Storage_ID);
+ return false;
+ } else {
+ LOGINFO("Message sent, remove storage ID: %i\n", Part->MTP_Storage_ID);
+ return true;
+ }
+ } else if (message_type == MTP_MESSAGE_ADD_STORAGE && Part->Is_Mounted()) {
+ mtp_message.message_type = MTP_MESSAGE_ADD_STORAGE; // Add
+ mtp_message.storage_id = Part->MTP_Storage_ID;
+ mtp_message.path = Part->Storage_Path.c_str();
+ mtp_message.display = Part->Storage_Name.c_str();
+ mtp_message.maxFileSize = Part->Get_Max_FileSize();
+ LOGINFO("sending message to add %i '%s'\n", Part->MTP_Storage_ID, mtp_message.path);
+ if (write(mtp_write_fd, &mtp_message, sizeof(mtp_message)) <= 0) {
+ LOGERR("error sending message to add storage %i\n", Part->MTP_Storage_ID);
+ return false;
+ } else {
+ LOGINFO("Message sent, add storage ID: %i\n", Part->MTP_Storage_ID);
+ return true;
+ }
+ } else {
+ LOGERR("Unknown MTP message type: %i\n", message_type);
+ }
+ } else {
+ // This hopefully never happens as the error handling should
+ // occur in the calling function.
+ LOGERR("TWPartitionManager::Add_Remove_MTP_Storage NULL partition given\n");
+ }
+ return true;
+#else
+ LOGERR("MTP support not included\n");
+ DataManager::SetValue("tw_mtp_enabled", 0);
+ return false;
+#endif
+}
+
+bool TWPartitionManager::Add_MTP_Storage(string Mount_Point) {
+#ifdef TW_HAS_MTP
+ TWPartition* Part = PartitionManager.Find_Partition_By_Path(Mount_Point);
+ if (Part) {
+ return PartitionManager.Add_Remove_MTP_Storage(Part, MTP_MESSAGE_ADD_STORAGE);
+ } else {
+ LOGERR("TWFunc::Add_MTP_Storage unable to locate partition for '%s'\n", Mount_Point.c_str());
+ }
+#endif
+ return false;
+}
+
+bool TWPartitionManager::Add_MTP_Storage(unsigned int Storage_ID) {
+#ifdef TW_HAS_MTP
+ TWPartition* Part = PartitionManager.Find_Partition_By_MTP_Storage_ID(Storage_ID);
+ if (Part) {
+ return PartitionManager.Add_Remove_MTP_Storage(Part, MTP_MESSAGE_ADD_STORAGE);
+ } else {
+ LOGERR("TWFunc::Add_MTP_Storage unable to locate partition for %i\n", Storage_ID);
+ }
+#endif
+ return false;
+}
+
+bool TWPartitionManager::Remove_MTP_Storage(string Mount_Point) {
+#ifdef TW_HAS_MTP
+ TWPartition* Part = PartitionManager.Find_Partition_By_Path(Mount_Point);
+ if (Part) {
+ return PartitionManager.Add_Remove_MTP_Storage(Part, MTP_MESSAGE_REMOVE_STORAGE);
+ } else {
+ LOGERR("TWFunc::Remove_MTP_Storage unable to locate partition for '%s'\n", Mount_Point.c_str());
+ }
+#endif
+ return false;
+}
+
+bool TWPartitionManager::Remove_MTP_Storage(unsigned int Storage_ID) {
+#ifdef TW_HAS_MTP
+ TWPartition* Part = PartitionManager.Find_Partition_By_MTP_Storage_ID(Storage_ID);
+ if (Part) {
+ return PartitionManager.Add_Remove_MTP_Storage(Part, MTP_MESSAGE_REMOVE_STORAGE);
+ } else {
+ LOGERR("TWFunc::Remove_MTP_Storage unable to locate partition for %i\n", Storage_ID);
+ }
+#endif
+ return false;
+}
diff --git a/partitions.hpp b/partitions.hpp
index 8458e9363..43f553547 100644
--- a/partitions.hpp
+++ b/partitions.hpp
@@ -75,6 +75,7 @@ public:
string MTD_Name; // Name of the partition for MTD devices
bool Is_Present; // Indicates if the partition is currently present as a block device
string Crypto_Key_Location; // Location of the crypto key used for decrypting encrypted data partitions
+ unsigned int MTP_Storage_ID;
protected:
bool Has_Data_Media; // Indicates presence of /data/media, may affect wiping and backup methods
@@ -214,6 +215,10 @@ public:
void Output_Storage_Fstab(); // Creates a /cache/recovery/storage.fstab file with a list of all potential storage locations for app use
bool Enable_MTP(); // Enables MTP
bool Disable_MTP(); // Disables MTP
+ bool Add_MTP_Storage(string Mount_Point); // Adds or removes an MTP Storage partition
+ bool Add_MTP_Storage(unsigned int Storage_ID); // Adds or removes an MTP Storage partition
+ bool Remove_MTP_Storage(string Mount_Point); // Adds or removes an MTP Storage partition
+ bool Remove_MTP_Storage(unsigned int Storage_ID); // Adds or removes an MTP Storage partition
private:
void Setup_Settings_Storage_Partition(TWPartition* Part); // Sets up settings storage
@@ -222,10 +227,13 @@ private:
bool Backup_Partition(TWPartition* Part, string Backup_Folder, bool generate_md5, unsigned long long* img_bytes_remaining, unsigned long long* file_bytes_remaining, unsigned long *img_time, unsigned long *file_time, unsigned long long *img_bytes, unsigned long long *file_bytes);
bool Restore_Partition(TWPartition* Part, string Restore_Name, int partition_count, const unsigned long long *total_restore_size, unsigned long long *already_restored_size);
void Output_Partition(TWPartition* Part);
+ TWPartition* Find_Partition_By_MTP_Storage_ID(unsigned int Storage_ID); // Returns a pointer to a partition based on MTP Storage ID
+ bool Add_Remove_MTP_Storage(TWPartition* Part, int message_type); // Adds or removes an MTP Storage partition
TWPartition* Find_Next_Storage(string Path, string Exclude);
int Open_Lun_File(string Partition_Path, string Lun_File);
pid_t mtppid;
bool mtp_was_enabled;
+ int mtp_write_fd;
private:
std::vector<TWPartition*> Partitions; // Vector list of all partitions