#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/sysmacros.h>
#include <sys/wait.h>
#include <unistd.h>
*/
const char *VolumeManager::LOOPDIR = "/mnt/obb";
-static const char* kUserMountPath = "/mnt/user";
+static const char* kPathUserMount = "/mnt/user";
+static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk";
+
+static const char* kPropVirtualDisk = "persist.sys.virtual_disk";
+
+/* 512MiB is large enough for testing purposes */
+static const unsigned int kSizeVirtualDisk = 536870912;
static const unsigned int kMajorBlockMmc = 179;
static const unsigned int kMajorBlockExperimentalMin = 240;
}
*createdDMDevice = true;
} else {
- strcpy(buffer, loopDevice);
+ strlcpy(buffer, loopDevice, len);
*createdDMDevice = false;
}
return 0;
return buffer;
}
+int VolumeManager::updateVirtualDisk() {
+ if (property_get_bool(kPropVirtualDisk, false)) {
+ if (access(kPathVirtualDisk, F_OK) != 0) {
+ Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512);
+ }
+
+ if (mVirtualDisk == nullptr) {
+ if (Loop::create(kPathVirtualDisk, mVirtualDiskPath) != 0) {
+ LOG(ERROR) << "Failed to create virtual disk";
+ return -1;
+ }
+
+ struct stat buf;
+ if (stat(mVirtualDiskPath.c_str(), &buf) < 0) {
+ PLOG(ERROR) << "Failed to stat " << mVirtualDiskPath;
+ return -1;
+ }
+
+ auto disk = new android::vold::Disk("virtual", buf.st_rdev, "virtual",
+ android::vold::Disk::Flags::kAdoptable | android::vold::Disk::Flags::kSd);
+ disk->create();
+ mVirtualDisk = std::shared_ptr<android::vold::Disk>(disk);
+ mDisks.push_back(mVirtualDisk);
+ }
+ } else {
+ if (mVirtualDisk != nullptr) {
+ dev_t device = mVirtualDisk->getDevice();
+
+ auto i = mDisks.begin();
+ while (i != mDisks.end()) {
+ if ((*i)->getDevice() == device) {
+ (*i)->destroy();
+ i = mDisks.erase(i);
+ } else {
+ ++i;
+ }
+ }
+
+ Loop::destroyByDevice(mVirtualDiskPath.c_str());
+ mVirtualDisk = nullptr;
+ }
+
+ if (access(kPathVirtualDisk, F_OK) == 0) {
+ unlink(kPathVirtualDisk);
+ }
+ }
+ return 0;
+}
+
int VolumeManager::setDebug(bool enable) {
mDebug = enable;
return 0;
new android::vold::EmulatedVolume("/data/media"));
mInternalEmulated->create();
+ // Consider creating a virtual disk
+ updateVirtualDisk();
+
return 0;
}
switch (evt->getAction()) {
case NetlinkEvent::Action::kAdd: {
- for (auto source : mDiskSources) {
+ for (const auto& source : mDiskSources) {
if (source->matches(eventPath)) {
// For now, assume that MMC and virtio-blk (the latter is
// emulator-specific; see Disk.cpp for details) devices are SD,
}
case NetlinkEvent::Action::kChange: {
LOG(DEBUG) << "Disk at " << major << ":" << minor << " changed";
- for (auto disk : mDisks) {
+ for (const auto& disk : mDisks) {
if (disk->getDevice() == device) {
disk->readMetadata();
disk->readPartitions();
}
void VolumeManager::addDiskSource(const std::shared_ptr<DiskSource>& diskSource) {
+ std::lock_guard<std::mutex> lock(mLock);
mDiskSources.push_back(diskSource);
}
if (mInternalEmulated->getId() == id) {
return mInternalEmulated;
}
- for (auto disk : mDisks) {
+ for (const auto& disk : mDisks) {
auto vol = disk->findVolume(id);
if (vol != nullptr) {
return vol;
void VolumeManager::listVolumes(android::vold::VolumeBase::Type type,
std::list<std::string>& list) {
list.clear();
- for (auto disk : mDisks) {
+ for (const auto& disk : mDisks) {
disk->listVolumes(type, list);
}
}
// Note that sometimes the system will spin up processes from Zygote
// before actually starting the user, so we're okay if Zygote
// already created this directory.
- std::string path(StringPrintf("%s/%d", kUserMountPath, userId));
+ std::string path(StringPrintf("%s/%d", kPathUserMount, userId));
fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
mStartedUsers.insert(userId);
}
endmntent(fp);
- for (auto path : toUnmount) {
+ for (const auto& path : toUnmount) {
if (umount2(path.c_str(), MNT_DETACH)) {
ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
}
}
// We purposefully leave the namespace open across the fork
- nsFd = openat(pidFd, "ns/mnt", O_RDONLY);
+ nsFd = openat(pidFd, "ns/mnt", O_RDONLY); // not O_CLOEXEC
if (nsFd < 0) {
PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
goto next;
_exit(0);
}
if (TEMP_FAILURE_RETRY(mount(storageSource.c_str(), "/storage",
- NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+ NULL, MS_BIND | MS_REC, NULL)) == -1) {
PLOG(ERROR) << "Failed to mount " << storageSource << " for "
<< de->d_name;
_exit(1);
}
+ if (TEMP_FAILURE_RETRY(mount(NULL, "/storage", NULL,
+ MS_REC | MS_SLAVE, NULL)) == -1) {
+ PLOG(ERROR) << "Failed to set MS_SLAVE to /storage for "
+ << de->d_name;
+ _exit(1);
+ }
// Mount user-specific symlink helper into place
userid_t user_id = multiuser_get_user_id(uid);
// newly connected framework hears all events.
mInternalEmulated->destroy();
mInternalEmulated->create();
- for (auto disk : mDisks) {
+ for (const auto& disk : mDisks) {
disk->destroy();
disk->create();
}
+ updateVirtualDisk();
mAddedUsers.clear();
mStartedUsers.clear();
return 0;
}
+// Can be called twice (sequentially) during shutdown. should be safe for that.
int VolumeManager::shutdown() {
+ if (mInternalEmulated == nullptr) {
+ return 0; // already shutdown
+ }
mInternalEmulated->destroy();
- for (auto disk : mDisks) {
+ mInternalEmulated = nullptr;
+ for (const auto& disk : mDisks) {
disk->destroy();
}
mDisks.clear();
if (mInternalEmulated != nullptr) {
mInternalEmulated->unmount();
}
- for (auto disk : mDisks) {
+ for (const auto& disk : mDisks) {
disk->unmountAll();
}
}
endmntent(fp);
- for (auto path : toUnmount) {
+ for (const auto& path : toUnmount) {
SLOGW("Tearing down stale mount %s", path.c_str());
android::vold::ForceUnmount(path);
}
cleanupDm = true;
} else {
sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
- strcpy(dmDevice, loopDevice);
+ strlcpy(dmDevice, loopDevice, sizeof(dmDevice));
}
/*
oldNumSec = info.st_size / 512;
- unsigned long numImgSectors;
- if (sb.c_opts & ASEC_SB_C_OPTS_EXT4)
- numImgSectors = adjustSectorNumExt4(numSectors);
- else
- numImgSectors = adjustSectorNumFAT(numSectors);
- /*
- * add one block for the superblock
- */
- SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1);
- if (oldNumSec == numImgSectors + 1) {
- SLOGW("Size unchanged; ignoring resize request");
- return 0;
- } else if (oldNumSec > numImgSectors + 1) {
- SLOGE("Only growing is currently supported.");
- close(fd);
- return -1;
- }
-
/*
* Try to read superblock.
*/
return -1;
}
+ unsigned long numImgSectors;
if (!(sb.c_opts & ASEC_SB_C_OPTS_EXT4)) {
SLOGE("Only ext4 partitions are supported for resize");
errno = EINVAL;
return -1;
+ } else {
+ numImgSectors = adjustSectorNumExt4(numSectors);
+ }
+
+ /*
+ * add one block for the superblock
+ */
+ SLOGD("Resizing from %lu sectors to %lu sectors", oldNumSec, numImgSectors + 1);
+ if (oldNumSec == numImgSectors + 1) {
+ SLOGW("Size unchanged; ignoring resize request");
+ return 0;
+ } else if (oldNumSec > numImgSectors + 1) {
+ SLOGE("Only growing is currently supported.");
+ close(fd);
+ return -1;
}
if (Loop::resizeImageFile(asecFileName, numImgSectors + 1)) {
// Create a string to compare against that has a trailing slash
int loopDirLen = strlen(VolumeManager::LOOPDIR);
char loopDir[loopDirLen + 2];
- strcpy(loopDir, VolumeManager::LOOPDIR);
+ strlcpy(loopDir, VolumeManager::LOOPDIR, sizeof(loopDir));
loopDir[loopDirLen++] = '/';
loopDir[loopDirLen] = '\0';