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 #include "Utils.h" 19 20 #include <android-base/stringprintf.h> 21 #include <android-base/logging.h> 22 #include <cutils/fs.h> 23 #include <private/android_filesystem_config.h> 24 25 #include <fcntl.h> 26 #include <stdlib.h> 27 #include <sys/mount.h> 28 #include <sys/stat.h> 29 #include <sys/types.h> 30 #include <sys/wait.h> 31 32 using android::base::StringPrintf; 33 34 namespace android { 35 namespace vold { 36 37 static const char* kFusePath = "/system/bin/sdcard"; 38 39 EmulatedVolume::EmulatedVolume(const std::string& rawPath) : 40 VolumeBase(Type::kEmulated), mFusePid(0) { 41 setId("emulated"); 42 mRawPath = rawPath; 43 mLabel = "emulated"; 44 } 45 46 EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, 47 const std::string& fsUuid) : VolumeBase(Type::kEmulated), mFusePid(0) { 48 setId(StringPrintf("emulated:%u,%u", major(device), minor(device))); 49 mRawPath = rawPath; 50 mLabel = fsUuid; 51 } 52 53 EmulatedVolume::~EmulatedVolume() { 54 } 55 56 status_t EmulatedVolume::doMount() { 57 // We could have migrated storage to an adopted private volume, so always 58 // call primary storage "emulated" to avoid media rescans. 59 std::string label = mLabel; 60 if (getMountFlags() & MountFlags::kPrimary) { 61 label = "emulated"; 62 } 63 64 mFuseDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str()); 65 mFuseRead = StringPrintf("/mnt/runtime/read/%s", label.c_str()); 66 mFuseWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str()); 67 68 setInternalPath(mRawPath); 69 setPath(StringPrintf("/storage/%s", label.c_str())); 70 71 if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || 72 fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) || 73 fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) { 74 PLOG(ERROR) << getId() << " failed to create mount points"; 75 return -errno; 76 } 77 78 dev_t before = GetDevice(mFuseWrite); 79 80 if (!(mFusePid = fork())) { 81 if (execl(kFusePath, kFusePath, 82 "-u", "1023", // AID_MEDIA_RW 83 "-g", "1023", // AID_MEDIA_RW 84 "-m", 85 "-w", 86 mRawPath.c_str(), 87 label.c_str(), 88 NULL)) { 89 PLOG(ERROR) << "Failed to exec"; 90 } 91 92 LOG(ERROR) << "FUSE exiting"; 93 _exit(1); 94 } 95 96 if (mFusePid == -1) { 97 PLOG(ERROR) << getId() << " failed to fork"; 98 return -errno; 99 } 100 101 while (before == GetDevice(mFuseWrite)) { 102 LOG(VERBOSE) << "Waiting for FUSE to spin up..."; 103 usleep(50000); // 50ms 104 } 105 106 return OK; 107 } 108 109 status_t EmulatedVolume::doUnmount() { 110 // Unmount the storage before we kill the FUSE process. If we kill 111 // the FUSE process first, most file system operations will return 112 // ENOTCONN until the unmount completes. This is an exotic and unusual 113 // error code and might cause broken behaviour in applications. 114 KillProcessesUsingPath(getPath()); 115 ForceUnmount(mFuseDefault); 116 ForceUnmount(mFuseRead); 117 ForceUnmount(mFuseWrite); 118 119 if (mFusePid > 0) { 120 kill(mFusePid, SIGTERM); 121 TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0)); 122 mFusePid = 0; 123 } 124 125 rmdir(mFuseDefault.c_str()); 126 rmdir(mFuseRead.c_str()); 127 rmdir(mFuseWrite.c_str()); 128 129 mFuseDefault.clear(); 130 mFuseRead.clear(); 131 mFuseWrite.clear(); 132 133 return OK; 134 } 135 136 } // namespace vold 137 } // namespace android 138