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