diff options
-rw-r--r-- | gui/action.cpp | 1 | ||||
-rw-r--r-- | gui/partitionlist.cpp | 1 | ||||
-rwxr-xr-x | mtp/MtpDatabase.h | 1 | ||||
-rw-r--r-- | mtp/MtpMessage.hpp | 33 | ||||
-rwxr-xr-x | mtp/MtpServer.cpp | 29 | ||||
-rwxr-xr-x | mtp/MtpStorage.cpp | 58 | ||||
-rwxr-xr-x | mtp/MtpStorage.h | 1 | ||||
-rwxr-xr-x | mtp/btree.cpp | 1 | ||||
-rwxr-xr-x | mtp/mtp_MtpDatabase.cpp | 7 | ||||
-rwxr-xr-x | mtp/mtp_MtpDatabase.hpp | 1 | ||||
-rwxr-xr-x | mtp/mtp_MtpServer.cpp | 52 | ||||
-rwxr-xr-x | mtp/mtp_MtpServer.hpp | 5 | ||||
-rw-r--r-- | mtp/tw_sys_atomics.h | 67 | ||||
-rwxr-xr-x | mtp/twrpMtp.cpp | 7 | ||||
-rwxr-xr-x | mtp/twrpMtp.hpp | 3 | ||||
-rw-r--r-- | partition.cpp | 26 | ||||
-rw-r--r-- | partitionmanager.cpp | 163 | ||||
-rw-r--r-- | partitions.hpp | 8 |
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 |