blob: 4f5ebe861aeb85b4be50f9043a5aac200afbcbbe [file] [log] [blame]
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -07001/*
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
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -060017#include "MoveStorage.h"
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070018#include "Utils.h"
19#include "VolumeManager.h"
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070020
Elliott Hughes7e128fb2015-12-04 15:50:53 -080021#include <android-base/stringprintf.h>
22#include <android-base/logging.h>
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070023#include <private/android_filesystem_config.h>
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070024#include <hardware_legacy/power.h>
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070025
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -060026#include <thread>
27
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070028#include <dirent.h>
29#include <sys/wait.h>
30
Chih-Hung Hsiehcc5d5802016-05-11 15:05:05 -070031#define CONSTRAIN(amount, low, high) ((amount) < (low) ? (low) : ((amount) > (high) ? (high) : (amount)))
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070032
Jeff Sharkeyfce701b2016-07-29 15:52:41 -060033#define EXEC_BLOCKING 0
34
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070035using android::base::StringPrintf;
36
37namespace android {
38namespace vold {
39
40// TODO: keep in sync with PackageManager
41static const int kMoveSucceeded = -100;
42static const int kMoveFailedInternalError = -6;
43
44static const char* kCpPath = "/system/bin/cp";
45static const char* kRmPath = "/system/bin/rm";
46
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -070047static const char* kWakeLock = "MoveTask";
48
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -060049static void notifyProgress(int progress,
50 const android::sp<android::os::IVoldTaskListener>& listener) {
51 if (listener) {
Jeff Sharkey52f7a912017-09-15 12:57:44 -060052 android::os::PersistableBundle extras;
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -060053 listener->onStatus(progress, extras);
Jeff Sharkey52f7a912017-09-15 12:57:44 -060054 }
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070055}
56
Jeff Sharkey46bb69f2017-06-21 13:52:23 -060057static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd,
58 bool addWildcard) {
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070059 DIR* dir = opendir(path.c_str());
60 if (dir == NULL) {
61 return -1;
62 }
63 bool found = false;
64 struct dirent* ent;
65 while ((ent = readdir(dir)) != NULL) {
66 if ((!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, ".."))) {
67 continue;
68 }
Jeff Sharkey46bb69f2017-06-21 13:52:23 -060069 if (addWildcard) {
70 cmd.push_back(StringPrintf("%s/%s/*", path.c_str(), ent->d_name));
71 } else {
72 cmd.push_back(StringPrintf("%s/%s", path.c_str(), ent->d_name));
73 }
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070074 found = true;
75 }
76 closedir(dir);
77 return found ? OK : -1;
78}
79
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -060080static status_t execRm(const std::string& path, int startProgress, int stepProgress,
81 const android::sp<android::os::IVoldTaskListener>& listener) {
82 notifyProgress(startProgress, listener);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070083
84 uint64_t expectedBytes = GetTreeBytes(path);
85 uint64_t startFreeBytes = GetFreeBytes(path);
86
87 std::vector<std::string> cmd;
88 cmd.push_back(kRmPath);
89 cmd.push_back("-f"); /* force: remove without confirmation, no error if it doesn't exist */
90 cmd.push_back("-R"); /* recursive: remove directory contents */
Jeff Sharkey46bb69f2017-06-21 13:52:23 -060091 if (pushBackContents(path, cmd, true) != OK) {
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070092 LOG(WARNING) << "No contents in " << path;
93 return OK;
94 }
95
Jeff Sharkeyfce701b2016-07-29 15:52:41 -060096#if EXEC_BLOCKING
97 return ForkExecvp(cmd);
98#else
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -070099 pid_t pid = ForkExecvpAsync(cmd);
100 if (pid == -1) return -1;
101
102 int status;
103 while (true) {
104 if (waitpid(pid, &status, WNOHANG) == pid) {
105 if (WIFEXITED(status)) {
106 LOG(DEBUG) << "Finished rm with status " << WEXITSTATUS(status);
107 return (WEXITSTATUS(status) == 0) ? OK : -1;
108 } else {
109 break;
110 }
111 }
112
113 sleep(1);
114 uint64_t deltaFreeBytes = GetFreeBytes(path) - startFreeBytes;
115 notifyProgress(startProgress + CONSTRAIN((int)
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600116 ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700117 }
118 return -1;
Jeff Sharkeyfce701b2016-07-29 15:52:41 -0600119#endif
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700120}
121
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600122static status_t execCp(const std::string& fromPath, const std::string& toPath, int startProgress,
123 int stepProgress, const android::sp<android::os::IVoldTaskListener>& listener) {
124 notifyProgress(startProgress, listener);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700125
126 uint64_t expectedBytes = GetTreeBytes(fromPath);
127 uint64_t startFreeBytes = GetFreeBytes(toPath);
128
Jeff Sharkeya0220a52017-04-03 17:11:45 -0600129 if (expectedBytes > startFreeBytes) {
130 LOG(ERROR) << "Data size " << expectedBytes << " is too large to fit in free space "
131 << startFreeBytes;
132 return -1;
133 }
134
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700135 std::vector<std::string> cmd;
136 cmd.push_back(kCpPath);
137 cmd.push_back("-p"); /* preserve timestamps, ownership, and permissions */
138 cmd.push_back("-R"); /* recurse into subdirectories (DEST must be a directory) */
139 cmd.push_back("-P"); /* Do not follow symlinks [default] */
140 cmd.push_back("-d"); /* don't dereference symlinks */
Jeff Sharkey46bb69f2017-06-21 13:52:23 -0600141 if (pushBackContents(fromPath, cmd, false) != OK) {
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700142 LOG(WARNING) << "No contents in " << fromPath;
143 return OK;
144 }
145 cmd.push_back(toPath.c_str());
146
Jeff Sharkeyfce701b2016-07-29 15:52:41 -0600147#if EXEC_BLOCKING
148 return ForkExecvp(cmd);
149#else
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700150 pid_t pid = ForkExecvpAsync(cmd);
151 if (pid == -1) return -1;
152
153 int status;
154 while (true) {
155 if (waitpid(pid, &status, WNOHANG) == pid) {
156 if (WIFEXITED(status)) {
157 LOG(DEBUG) << "Finished cp with status " << WEXITSTATUS(status);
158 return (WEXITSTATUS(status) == 0) ? OK : -1;
159 } else {
160 break;
161 }
162 }
163
164 sleep(1);
165 uint64_t deltaFreeBytes = startFreeBytes - GetFreeBytes(toPath);
166 notifyProgress(startProgress + CONSTRAIN((int)
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600167 ((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700168 }
169 return -1;
Jeff Sharkeyfce701b2016-07-29 15:52:41 -0600170#endif
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700171}
172
173static void bringOffline(const std::shared_ptr<VolumeBase>& vol) {
174 vol->destroy();
175 vol->setSilent(true);
176 vol->create();
177 vol->setMountFlags(0);
178 vol->mount();
179}
180
181static void bringOnline(const std::shared_ptr<VolumeBase>& vol) {
182 vol->destroy();
183 vol->setSilent(false);
184 vol->create();
185}
186
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600187static status_t moveStorageInternal(const std::shared_ptr<VolumeBase>& from,
188 const std::shared_ptr<VolumeBase>& to,
189 const android::sp<android::os::IVoldTaskListener>& listener) {
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700190 std::string fromPath;
191 std::string toPath;
192
193 // TODO: add support for public volumes
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600194 if (from->getType() != VolumeBase::Type::kEmulated) goto fail;
195 if (to->getType() != VolumeBase::Type::kEmulated) goto fail;
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700196
197 // Step 1: tear down volumes and mount silently without making
198 // visible to userspace apps
Henrik Baard7f52bca2015-11-26 12:05:13 +0100199 {
200 std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600201 bringOffline(from);
202 bringOffline(to);
Henrik Baard7f52bca2015-11-26 12:05:13 +0100203 }
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700204
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600205 fromPath = from->getInternalPath();
206 toPath = to->getInternalPath();
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700207
208 // Step 2: clean up any stale data
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600209 if (execRm(toPath, 10, 10, listener) != OK) {
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700210 goto fail;
211 }
212
213 // Step 3: perform actual copy
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600214 if (execCp(fromPath, toPath, 20, 60, listener) != OK) {
Henrik Baard77f156d2015-12-17 13:58:42 +0100215 goto copy_fail;
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700216 }
217
218 // NOTE: MountService watches for this magic value to know
219 // that move was successful
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600220 notifyProgress(82, listener);
Henrik Baard7f52bca2015-11-26 12:05:13 +0100221 {
222 std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600223 bringOnline(from);
224 bringOnline(to);
Henrik Baard7f52bca2015-11-26 12:05:13 +0100225 }
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700226
227 // Step 4: clean up old data
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600228 if (execRm(fromPath, 85, 15, listener) != OK) {
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700229 goto fail;
230 }
231
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600232 notifyProgress(kMoveSucceeded, listener);
233 return OK;
Henrik Baard77f156d2015-12-17 13:58:42 +0100234
235copy_fail:
236 // if we failed to copy the data we should not leave it laying around
237 // in target location. Do not check return value, we can not do any
238 // useful anyway.
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600239 execRm(toPath, 80, 1, listener);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700240fail:
Henrik Baard7f52bca2015-11-26 12:05:13 +0100241 {
242 std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600243 bringOnline(from);
244 bringOnline(to);
Henrik Baard7f52bca2015-11-26 12:05:13 +0100245 }
Jeff Sharkey01a0e7f2017-10-17 16:06:32 -0600246 notifyProgress(kMoveFailedInternalError, listener);
247 return -1;
248}
249
250void MoveStorage(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to,
251 const android::sp<android::os::IVoldTaskListener>& listener) {
252 acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
253
254 android::os::PersistableBundle extras;
255 status_t res = moveStorageInternal(from, to, listener);
256 if (listener) {
257 listener->onFinished(res, extras);
258 }
259
Jeff Sharkeyc86ab6f2015-06-26 14:02:09 -0700260 release_wake_lock(kWakeLock);
Jeff Sharkey1d6fbcc2015-04-24 16:00:03 -0700261}
262
263} // namespace vold
264} // namespace android