MoveStorage.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "MoveStorage.h"
  17. #include "Utils.h"
  18. #include "VolumeManager.h"
  19. #include <android-base/logging.h>
  20. #include <android-base/properties.h>
  21. #include <android-base/stringprintf.h>
  22. #include <hardware_legacy/power.h>
  23. #include <private/android_filesystem_config.h>
  24. #include <thread>
  25. #include <dirent.h>
  26. #include <sys/wait.h>
  27. #define CONSTRAIN(amount, low, high) \
  28. ((amount) < (low) ? (low) : ((amount) > (high) ? (high) : (amount)))
  29. static const char* kPropBlockingExec = "persist.sys.blocking_exec";
  30. using android::base::StringPrintf;
  31. namespace android {
  32. namespace vold {
  33. // TODO: keep in sync with PackageManager
  34. static const int kMoveSucceeded = -100;
  35. static const int kMoveFailedInternalError = -6;
  36. static const char* kCpPath = "/system/bin/cp";
  37. static const char* kRmPath = "/system/bin/rm";
  38. static const char* kWakeLock = "MoveTask";
  39. static void notifyProgress(int progress,
  40. const android::sp<android::os::IVoldTaskListener>& listener) {
  41. if (listener) {
  42. android::os::PersistableBundle extras;
  43. listener->onStatus(progress, extras);
  44. }
  45. }
  46. static bool pushBackContents(const std::string& path, std::vector<std::string>& cmd,
  47. int searchLevels) {
  48. if (searchLevels == 0) {
  49. cmd.emplace_back(path);
  50. return true;
  51. }
  52. auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(path.c_str()), closedir);
  53. if (!dirp) {
  54. PLOG(ERROR) << "Unable to open directory: " << path;
  55. return false;
  56. }
  57. bool found = false;
  58. struct dirent* ent;
  59. while ((ent = readdir(dirp.get())) != NULL) {
  60. if ((!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, ".."))) {
  61. continue;
  62. }
  63. auto subdir = path + "/" + ent->d_name;
  64. found |= pushBackContents(subdir, cmd, searchLevels - 1);
  65. }
  66. return found;
  67. }
  68. static status_t execRm(const std::string& path, int startProgress, int stepProgress,
  69. const android::sp<android::os::IVoldTaskListener>& listener) {
  70. notifyProgress(startProgress, listener);
  71. uint64_t expectedBytes = GetTreeBytes(path);
  72. uint64_t startFreeBytes = GetFreeBytes(path);
  73. std::vector<std::string> cmd;
  74. cmd.push_back(kRmPath);
  75. cmd.push_back("-f"); /* force: remove without confirmation, no error if it doesn't exist */
  76. cmd.push_back("-R"); /* recursive: remove directory contents */
  77. if (!pushBackContents(path, cmd, 2)) {
  78. LOG(WARNING) << "No contents in " << path;
  79. return OK;
  80. }
  81. if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
  82. return ForkExecvp(cmd);
  83. }
  84. pid_t pid = ForkExecvpAsync(cmd);
  85. if (pid == -1) return -1;
  86. int status;
  87. while (true) {
  88. if (waitpid(pid, &status, WNOHANG) == pid) {
  89. if (WIFEXITED(status)) {
  90. LOG(DEBUG) << "Finished rm with status " << WEXITSTATUS(status);
  91. return (WEXITSTATUS(status) == 0) ? OK : -1;
  92. } else {
  93. break;
  94. }
  95. }
  96. sleep(1);
  97. uint64_t deltaFreeBytes = GetFreeBytes(path) - startFreeBytes;
  98. notifyProgress(
  99. startProgress +
  100. CONSTRAIN((int)((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress),
  101. listener);
  102. }
  103. return -1;
  104. }
  105. static status_t execCp(const std::string& fromPath, const std::string& toPath, int startProgress,
  106. int stepProgress,
  107. const android::sp<android::os::IVoldTaskListener>& listener) {
  108. notifyProgress(startProgress, listener);
  109. uint64_t expectedBytes = GetTreeBytes(fromPath);
  110. uint64_t startFreeBytes = GetFreeBytes(toPath);
  111. if (expectedBytes > startFreeBytes) {
  112. LOG(ERROR) << "Data size " << expectedBytes << " is too large to fit in free space "
  113. << startFreeBytes;
  114. return -1;
  115. }
  116. std::vector<std::string> cmd;
  117. cmd.push_back(kCpPath);
  118. cmd.push_back("-p"); /* preserve timestamps, ownership, and permissions */
  119. cmd.push_back("-R"); /* recurse into subdirectories (DEST must be a directory) */
  120. cmd.push_back("-P"); /* Do not follow symlinks [default] */
  121. cmd.push_back("-d"); /* don't dereference symlinks */
  122. if (!pushBackContents(fromPath, cmd, 1)) {
  123. LOG(WARNING) << "No contents in " << fromPath;
  124. return OK;
  125. }
  126. cmd.push_back(toPath.c_str());
  127. if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
  128. return ForkExecvp(cmd);
  129. }
  130. pid_t pid = ForkExecvpAsync(cmd);
  131. if (pid == -1) return -1;
  132. int status;
  133. while (true) {
  134. if (waitpid(pid, &status, WNOHANG) == pid) {
  135. if (WIFEXITED(status)) {
  136. LOG(DEBUG) << "Finished cp with status " << WEXITSTATUS(status);
  137. return (WEXITSTATUS(status) == 0) ? OK : -1;
  138. } else {
  139. break;
  140. }
  141. }
  142. sleep(1);
  143. uint64_t deltaFreeBytes = startFreeBytes - GetFreeBytes(toPath);
  144. notifyProgress(
  145. startProgress +
  146. CONSTRAIN((int)((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress),
  147. listener);
  148. }
  149. return -1;
  150. }
  151. static void bringOffline(const std::shared_ptr<VolumeBase>& vol) {
  152. vol->destroy();
  153. vol->setSilent(true);
  154. vol->create();
  155. vol->setMountFlags(0);
  156. vol->mount();
  157. }
  158. static void bringOnline(const std::shared_ptr<VolumeBase>& vol) {
  159. vol->destroy();
  160. vol->setSilent(false);
  161. vol->create();
  162. }
  163. static status_t moveStorageInternal(const std::shared_ptr<VolumeBase>& from,
  164. const std::shared_ptr<VolumeBase>& to,
  165. const android::sp<android::os::IVoldTaskListener>& listener) {
  166. std::string fromPath;
  167. std::string toPath;
  168. // TODO: add support for public volumes
  169. if (from->getType() != VolumeBase::Type::kEmulated) goto fail;
  170. if (to->getType() != VolumeBase::Type::kEmulated) goto fail;
  171. // Step 1: tear down volumes and mount silently without making
  172. // visible to userspace apps
  173. {
  174. std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
  175. bringOffline(from);
  176. bringOffline(to);
  177. }
  178. fromPath = from->getInternalPath();
  179. toPath = to->getInternalPath();
  180. // Step 2: clean up any stale data
  181. if (execRm(toPath, 10, 10, listener) != OK) {
  182. goto fail;
  183. }
  184. // Step 3: perform actual copy
  185. if (execCp(fromPath, toPath, 20, 60, listener) != OK) {
  186. goto copy_fail;
  187. }
  188. // NOTE: MountService watches for this magic value to know
  189. // that move was successful
  190. notifyProgress(82, listener);
  191. {
  192. std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
  193. bringOnline(from);
  194. bringOnline(to);
  195. }
  196. // Step 4: clean up old data
  197. if (execRm(fromPath, 85, 15, listener) != OK) {
  198. goto fail;
  199. }
  200. notifyProgress(kMoveSucceeded, listener);
  201. return OK;
  202. copy_fail:
  203. // if we failed to copy the data we should not leave it laying around
  204. // in target location. Do not check return value, we can not do any
  205. // useful anyway.
  206. execRm(toPath, 80, 1, listener);
  207. fail:
  208. // clang-format off
  209. {
  210. std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
  211. bringOnline(from);
  212. bringOnline(to);
  213. }
  214. // clang-format on
  215. notifyProgress(kMoveFailedInternalError, listener);
  216. return -1;
  217. }
  218. void MoveStorage(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to,
  219. const android::sp<android::os::IVoldTaskListener>& listener) {
  220. acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
  221. android::os::PersistableBundle extras;
  222. status_t res = moveStorageInternal(from, to, listener);
  223. if (listener) {
  224. listener->onFinished(res, extras);
  225. }
  226. release_wake_lock(kWakeLock);
  227. }
  228. } // namespace vold
  229. } // namespace android