• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include "EmulatedVolume.h"
18 
19 #include "AppFuseUtil.h"
20 #include "Utils.h"
21 #include "VolumeManager.h"
22 
23 #include <android-base/logging.h>
24 #include <android-base/properties.h>
25 #include <android-base/scopeguard.h>
26 #include <android-base/stringprintf.h>
27 #include <cutils/fs.h>
28 #include <private/android_filesystem_config.h>
29 #include <utils/Timers.h>
30 
31 #include <fcntl.h>
32 #include <stdlib.h>
33 #include <sys/mount.h>
34 #include <sys/stat.h>
35 #include <sys/sysmacros.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 
39 using android::base::StringPrintf;
40 
41 namespace android {
42 namespace vold {
43 
44 static const char* kSdcardFsPath = "/system/bin/sdcard";
45 
EmulatedVolume(const std::string & rawPath,int userId)46 EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId)
47     : VolumeBase(Type::kEmulated) {
48     setId(StringPrintf("emulated;%u", userId));
49     mRawPath = rawPath;
50     mLabel = "emulated";
51     mFuseMounted = false;
52     mUseSdcardFs = IsSdcardfsUsed();
53     mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
54 }
55 
EmulatedVolume(const std::string & rawPath,dev_t device,const std::string & fsUuid,int userId)56 EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid,
57                                int userId)
58     : VolumeBase(Type::kEmulated) {
59     setId(StringPrintf("emulated:%u,%u;%u", major(device), minor(device), userId));
60     mRawPath = rawPath;
61     mLabel = fsUuid;
62     mFuseMounted = false;
63     mUseSdcardFs = IsSdcardfsUsed();
64     mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false);
65 }
66 
~EmulatedVolume()67 EmulatedVolume::~EmulatedVolume() {}
68 
getLabel()69 std::string EmulatedVolume::getLabel() {
70     // We could have migrated storage to an adopted private volume, so always
71     // call primary storage "emulated" to avoid media rescans.
72     if (getMountFlags() & MountFlags::kPrimary) {
73         return "emulated";
74     } else {
75         return mLabel;
76     }
77 }
78 
79 // Creates a bind mount from source to target
doFuseBindMount(const std::string & source,const std::string & target,std::list<std::string> & pathsToUnmount)80 static status_t doFuseBindMount(const std::string& source, const std::string& target,
81                                 std::list<std::string>& pathsToUnmount) {
82     LOG(INFO) << "Bind mounting " << source << " on " << target;
83     auto status = BindMount(source, target);
84     if (status != OK) {
85         return status;
86     }
87     LOG(INFO) << "Bind mounted " << source << " on " << target;
88     pathsToUnmount.push_front(target);
89     return OK;
90 }
91 
mountFuseBindMounts()92 status_t EmulatedVolume::mountFuseBindMounts() {
93     std::string androidSource;
94     std::string label = getLabel();
95     int userId = getMountUserId();
96     std::list<std::string> pathsToUnmount;
97 
98     auto unmounter = [&]() {
99         LOG(INFO) << "mountFuseBindMounts() unmount scope_guard running";
100         for (const auto& path : pathsToUnmount) {
101             LOG(INFO) << "Unmounting " << path;
102             auto status = UnmountTree(path);
103             if (status != OK) {
104                 LOG(INFO) << "Failed to unmount " << path;
105             } else {
106                 LOG(INFO) << "Unmounted " << path;
107             }
108         }
109     };
110     auto unmount_guard = android::base::make_scope_guard(unmounter);
111 
112     if (mUseSdcardFs) {
113         androidSource = StringPrintf("/mnt/runtime/default/%s/%d/Android", label.c_str(), userId);
114     } else {
115         androidSource = StringPrintf("/%s/%d/Android", mRawPath.c_str(), userId);
116     }
117 
118     status_t status = OK;
119     // When app data isolation is enabled, obb/ will be mounted per app, otherwise we should
120     // bind mount the whole Android/ to speed up reading.
121     if (!mAppDataIsolationEnabled) {
122         std::string androidDataSource = StringPrintf("%s/data", androidSource.c_str());
123         std::string androidDataTarget(
124                 StringPrintf("/mnt/user/%d/%s/%d/Android/data", userId, label.c_str(), userId));
125         status = doFuseBindMount(androidDataSource, androidDataTarget, pathsToUnmount);
126         if (status != OK) {
127             return status;
128         }
129 
130         std::string androidObbSource = StringPrintf("%s/obb", androidSource.c_str());
131         std::string androidObbTarget(
132                 StringPrintf("/mnt/user/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
133         status = doFuseBindMount(androidObbSource, androidObbTarget, pathsToUnmount);
134         if (status != OK) {
135             return status;
136         }
137     }
138 
139     // Installers get the same view as all other apps, with the sole exception that the
140     // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires
141     // a special bind mount, since app-private and OBB dirs share the same GID, but we
142     // only want to give access to the latter.
143     if (mUseSdcardFs) {
144         std::string obbSource(StringPrintf("/mnt/runtime/write/%s/%d/Android/obb",
145                 label.c_str(), userId));
146         std::string obbInstallerTarget(StringPrintf("/mnt/installer/%d/%s/%d/Android/obb",
147                 userId, label.c_str(), userId));
148 
149         status = doFuseBindMount(obbSource, obbInstallerTarget, pathsToUnmount);
150         if (status != OK) {
151             return status;
152         }
153     } else if (mAppDataIsolationEnabled) {
154         std::string obbSource(StringPrintf("%s/obb", androidSource.c_str()));
155         std::string obbInstallerTarget(StringPrintf("/mnt/installer/%d/%s/%d/Android/obb",
156                 userId, label.c_str(), userId));
157 
158         status = doFuseBindMount(obbSource, obbInstallerTarget, pathsToUnmount);
159         if (status != OK) {
160             return status;
161         }
162     }
163 
164     // /mnt/androidwriteable is similar to /mnt/installer, but it's for
165     // MOUNT_EXTERNAL_ANDROID_WRITABLE apps and it can also access DATA (Android/data) dirs.
166     if (mAppDataIsolationEnabled) {
167         std::string obbSource = mUseSdcardFs ?
168             StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", label.c_str(), userId)
169             : StringPrintf("%s/obb", androidSource.c_str());
170 
171         std::string obbAndroidWritableTarget(
172                 StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/obb",
173                 userId, label.c_str(), userId));
174 
175         status = doFuseBindMount(obbSource, obbAndroidWritableTarget, pathsToUnmount);
176         if (status != OK) {
177             return status;
178         }
179 
180         std::string dataSource = mUseSdcardFs ?
181                 StringPrintf("/mnt/runtime/write/%s/%d/Android/data", label.c_str(), userId)
182                 : StringPrintf("%s/data", androidSource.c_str());
183         std::string dataTarget(StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/data",
184                 userId, label.c_str(), userId));
185 
186         status = doFuseBindMount(dataSource, dataTarget, pathsToUnmount);
187         if (status != OK) {
188             return status;
189         }
190     }
191     unmount_guard.Disable();
192     return OK;
193 }
194 
unmountFuseBindMounts()195 status_t EmulatedVolume::unmountFuseBindMounts() {
196     std::string label = getLabel();
197     int userId = getMountUserId();
198 
199     if (mUseSdcardFs || mAppDataIsolationEnabled) {
200         std::string installerTarget(
201                 StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
202         LOG(INFO) << "Unmounting " << installerTarget;
203         auto status = UnmountTree(installerTarget);
204         if (status != OK) {
205             LOG(ERROR) << "Failed to unmount " << installerTarget;
206             // Intentional continue to try to unmount the other bind mount
207         }
208     }
209     if (mAppDataIsolationEnabled) {
210         std::string obbTarget( StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/obb",
211                 userId, label.c_str(), userId));
212         LOG(INFO) << "Unmounting " << obbTarget;
213         auto status = UnmountTree(obbTarget);
214         if (status != OK) {
215             LOG(ERROR) << "Failed to unmount " << obbTarget;
216             // Intentional continue to try to unmount the other bind mount
217         }
218         std::string dataTarget(StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/data",
219                 userId, label.c_str(), userId));
220         LOG(INFO) << "Unmounting " << dataTarget;
221         status = UnmountTree(dataTarget);
222         if (status != OK) {
223             LOG(ERROR) << "Failed to unmount " << dataTarget;
224             // Intentional continue to try to unmount the other bind mount
225         }
226     }
227 
228     // When app data isolation is enabled, kill all apps that obb/ is mounted, otherwise we should
229     // umount the whole Android/ dir.
230     if (mAppDataIsolationEnabled) {
231         std::string appObbDir(StringPrintf("%s/%d/Android/obb", getPath().c_str(), userId));
232         KillProcessesWithMountPrefix(appObbDir);
233     } else {
234         std::string androidDataTarget(
235                 StringPrintf("/mnt/user/%d/%s/%d/Android/data", userId, label.c_str(), userId));
236 
237         LOG(INFO) << "Unmounting " << androidDataTarget;
238         auto status = UnmountTree(androidDataTarget);
239         if (status != OK) {
240             return status;
241         }
242         LOG(INFO) << "Unmounted " << androidDataTarget;
243 
244         std::string androidObbTarget(
245                 StringPrintf("/mnt/user/%d/%s/%d/Android/obb", userId, label.c_str(), userId));
246 
247         LOG(INFO) << "Unmounting " << androidObbTarget;
248         status = UnmountTree(androidObbTarget);
249         if (status != OK) {
250             return status;
251         }
252         LOG(INFO) << "Unmounted " << androidObbTarget;
253     }
254     return OK;
255 }
256 
unmountSdcardFs()257 status_t EmulatedVolume::unmountSdcardFs() {
258     if (!mUseSdcardFs || getMountUserId() != 0) {
259         // For sdcardfs, only unmount for user 0, since user 0 will always be running
260         // and the paths don't change for different users.
261         return OK;
262     }
263 
264     ForceUnmount(mSdcardFsDefault);
265     ForceUnmount(mSdcardFsRead);
266     ForceUnmount(mSdcardFsWrite);
267     ForceUnmount(mSdcardFsFull);
268 
269     rmdir(mSdcardFsDefault.c_str());
270     rmdir(mSdcardFsRead.c_str());
271     rmdir(mSdcardFsWrite.c_str());
272     rmdir(mSdcardFsFull.c_str());
273 
274     mSdcardFsDefault.clear();
275     mSdcardFsRead.clear();
276     mSdcardFsWrite.clear();
277     mSdcardFsFull.clear();
278 
279     return OK;
280 }
281 
doMount()282 status_t EmulatedVolume::doMount() {
283     std::string label = getLabel();
284     bool isVisible = getMountFlags() & MountFlags::kVisible;
285 
286     mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str());
287     mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", label.c_str());
288     mSdcardFsWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str());
289     mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", label.c_str());
290 
291     setInternalPath(mRawPath);
292     setPath(StringPrintf("/storage/%s", label.c_str()));
293 
294     if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
295         fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
296         fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) ||
297         fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) {
298         PLOG(ERROR) << getId() << " failed to create mount points";
299         return -errno;
300     }
301 
302     dev_t before = GetDevice(mSdcardFsFull);
303 
304     bool isFuse = base::GetBoolProperty(kPropFuse, false);
305 
306     // Mount sdcardfs regardless of FUSE, since we need it to bind-mount on top of the
307     // FUSE volume for various reasons.
308     if (mUseSdcardFs && getMountUserId() == 0) {
309         LOG(INFO) << "Executing sdcardfs";
310         int sdcardFsPid;
311         if (!(sdcardFsPid = fork())) {
312             // clang-format off
313             if (execl(kSdcardFsPath, kSdcardFsPath,
314                     "-u", "1023", // AID_MEDIA_RW
315                     "-g", "1023", // AID_MEDIA_RW
316                     "-m",
317                     "-w",
318                     "-G",
319                     "-i",
320                     "-o",
321                     mRawPath.c_str(),
322                     label.c_str(),
323                     NULL)) {
324                 // clang-format on
325                 PLOG(ERROR) << "Failed to exec";
326             }
327 
328             LOG(ERROR) << "sdcardfs exiting";
329             _exit(1);
330         }
331 
332         if (sdcardFsPid == -1) {
333             PLOG(ERROR) << getId() << " failed to fork";
334             return -errno;
335         }
336 
337         nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
338         while (before == GetDevice(mSdcardFsFull)) {
339             LOG(DEBUG) << "Waiting for sdcardfs to spin up...";
340             usleep(50000);  // 50ms
341 
342             nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
343             if (nanoseconds_to_milliseconds(now - start) > 5000) {
344                 LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up";
345                 return -ETIMEDOUT;
346             }
347         }
348         /* sdcardfs will have exited already. The filesystem will still be running */
349         TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0));
350         sdcardFsPid = 0;
351     }
352 
353     if (isFuse && isVisible) {
354         // Make sure we unmount sdcardfs if we bail out with an error below
355         auto sdcardfs_unmounter = [&]() {
356             LOG(INFO) << "sdcardfs_unmounter scope_guard running";
357             unmountSdcardFs();
358         };
359         auto sdcardfs_guard = android::base::make_scope_guard(sdcardfs_unmounter);
360 
361         LOG(INFO) << "Mounting emulated fuse volume";
362         android::base::unique_fd fd;
363         int user_id = getMountUserId();
364         auto volumeRoot = getRootPath();
365 
366         // Make sure Android/ dirs exist for bind mounting
367         status_t res = PrepareAndroidDirs(volumeRoot);
368         if (res != OK) {
369             LOG(ERROR) << "Failed to prepare Android/ directories";
370             return res;
371         }
372 
373         res = MountUserFuse(user_id, getInternalPath(), label, &fd);
374         if (res != 0) {
375             PLOG(ERROR) << "Failed to mount emulated fuse volume";
376             return res;
377         }
378 
379         mFuseMounted = true;
380         auto fuse_unmounter = [&]() {
381             LOG(INFO) << "fuse_unmounter scope_guard running";
382             fd.reset();
383             if (UnmountUserFuse(user_id, getInternalPath(), label) != OK) {
384                 PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
385             }
386             mFuseMounted = false;
387         };
388         auto fuse_guard = android::base::make_scope_guard(fuse_unmounter);
389 
390         auto callback = getMountCallback();
391         if (callback) {
392             bool is_ready = false;
393             callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready);
394             if (!is_ready) {
395                 return -EIO;
396             }
397         }
398 
399         // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
400         res = mountFuseBindMounts();
401         if (res != OK) {
402             return res;
403         }
404 
405         ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, label), 256u);
406 
407         // By default, FUSE has a max_dirty ratio of 1%. This means that out of
408         // all dirty pages in the system, only 1% is allowed to belong to any
409         // FUSE filesystem. The reason this is in place is that FUSE
410         // filesystems shouldn't be trusted by default; a FUSE filesystem could
411         // take up say 100% of dirty pages, and subsequently refuse to write
412         // them back to storage.  The kernel will then apply rate-limiting, and
413         // block other tasks from writing.  For this particular FUSE filesystem
414         // however, we trust the implementation, because it is a part of the
415         // Android platform. So use the default ratio of 100%.
416         //
417         // The reason we're setting this is that there's a suspicion that the
418         // kernel starts rate-limiting the FUSE filesystem under extreme
419         // memory pressure scenarios. While the kernel will only rate limit if
420         // the writeback can't keep up with the write rate, under extreme
421         // memory pressure the write rate may dip as well, in which case FUSE
422         // writes to a 1% max_ratio filesystem are throttled to an extreme amount.
423         //
424         // To prevent this, just give FUSE 40% max_ratio, meaning it can take
425         // up to 40% of all dirty pages in the system.
426         ConfigureMaxDirtyRatioForFuse(GetFuseMountPathForUser(user_id, label), 40u);
427 
428         // All mounts where successful, disable scope guards
429         sdcardfs_guard.Disable();
430         fuse_guard.Disable();
431     }
432 
433     return OK;
434 }
435 
doUnmount()436 status_t EmulatedVolume::doUnmount() {
437     int userId = getMountUserId();
438 
439     // Kill all processes using the filesystem before we unmount it. If we
440     // unmount the filesystem first, most file system operations will return
441     // ENOTCONN until the unmount completes. This is an exotic and unusual
442     // error code and might cause broken behaviour in applications.
443     if (mFuseMounted) {
444         // For FUSE specifically, we have an emulated volume per user, so only kill
445         // processes using files from this particular user.
446         std::string user_path(StringPrintf("%s/%d", getPath().c_str(), getMountUserId()));
447         LOG(INFO) << "Killing all processes referencing " << user_path;
448         KillProcessesUsingPath(user_path);
449     } else {
450         KillProcessesUsingPath(getPath());
451     }
452 
453     if (mFuseMounted) {
454         std::string label = getLabel();
455 
456         // Ignoring unmount return status because we do want to try to unmount
457         // the rest cleanly.
458         unmountFuseBindMounts();
459 
460         if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
461             PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
462             return -errno;
463         }
464 
465         mFuseMounted = false;
466     }
467 
468     return unmountSdcardFs();
469 }
470 
getRootPath() const471 std::string EmulatedVolume::getRootPath() const {
472     int user_id = getMountUserId();
473     std::string volumeRoot = StringPrintf("%s/%d", getInternalPath().c_str(), user_id);
474 
475     return volumeRoot;
476 }
477 
478 }  // namespace vold
479 }  // namespace android
480