Merge "Extract AppFuse as a util" am: 7be8a7ee1d am: d04a16cbd5
am: 9f7af4b6e3
Change-Id: I92a3fa8828e983df876d42637913737e2b31fd4f
diff --git a/IdleMaint.cpp b/IdleMaint.cpp
index 79894fc..d73b6d2 100644
--- a/IdleMaint.cpp
+++ b/IdleMaint.cpp
@@ -47,8 +47,8 @@
using android::base::WriteStringToFile;
using android::hardware::Return;
using android::hardware::Void;
-using android::hardware::health::storage::V1_0::IGarbageCollectCallback;
using android::hardware::health::storage::V1_0::IStorage;
+using android::hardware::health::storage::V1_0::IGarbageCollectCallback;
using android::hardware::health::storage::V1_0::Result;
namespace android {
diff --git a/Utils.cpp b/Utils.cpp
index ce1f777..57417d6 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -25,6 +25,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <logwrap/logwrap.h>
#include <private/android_filesystem_config.h>
@@ -792,6 +793,76 @@
return OK;
}
+static status_t delete_dir_contents(DIR* dir) {
+ // Shamelessly borrowed from android::installd
+ int dfd = dirfd(dir);
+ if (dfd < 0) {
+ return -errno;
+ }
+
+ status_t result;
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ const char* name = de->d_name;
+ if (de->d_type == DT_DIR) {
+ /* always skip "." and ".." */
+ if (name[0] == '.') {
+ if (name[1] == 0) continue;
+ if ((name[1] == '.') && (name[2] == 0)) continue;
+ }
+
+ android::base::unique_fd subfd(
+ openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
+ if (subfd.get() == -1) {
+ PLOG(ERROR) << "Couldn't openat " << name;
+ result = -errno;
+ continue;
+ }
+ std::unique_ptr<DIR, decltype(&closedir)> subdirp(
+ android::base::Fdopendir(std::move(subfd)), closedir);
+ if (!subdirp) {
+ PLOG(ERROR) << "Couldn't fdopendir " << name;
+ result = -errno;
+ continue;
+ }
+ result = delete_dir_contents(subdirp.get());
+ if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) {
+ PLOG(ERROR) << "Couldn't unlinkat " << name;
+ result = -errno;
+ }
+ } else {
+ if (unlinkat(dfd, name, 0) < 0) {
+ PLOG(ERROR) << "Couldn't unlinkat " << name;
+ result = -errno;
+ }
+ }
+ }
+ return result;
+}
+
+status_t DeleteDirContentsAndDir(const std::string& pathname) {
+ // Shamelessly borrowed from android::installd
+ std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir(pathname.c_str()), closedir);
+ if (!dirp) {
+ if (errno == ENOENT) {
+ return OK;
+ }
+ PLOG(ERROR) << "Failed to opendir " << pathname;
+ return -errno;
+ }
+ status_t res = delete_dir_contents(dirp.get());
+ if (res < 0) {
+ return res;
+ }
+ dirp.reset(nullptr);
+ if (rmdir(pathname.c_str()) != 0) {
+ PLOG(ERROR) << "rmdir failed on " << pathname;
+ return -errno;
+ }
+ LOG(VERBOSE) << "Success: rmdir on " << pathname;
+ return OK;
+}
+
// TODO(118708649): fix duplication with init/util.h
status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout) {
android::base::Timer t;
diff --git a/Utils.h b/Utils.h
index 4d3522a..e6f4792 100644
--- a/Utils.h
+++ b/Utils.h
@@ -133,6 +133,8 @@
status_t UnmountTree(const std::string& prefix);
+status_t DeleteDirContentsAndDir(const std::string& pathname);
+
status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout);
} // namespace vold
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index c58ff01..c2d4e0b 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -147,6 +147,69 @@
return ok();
}
+binder::Status checkArgumentPackageName(const std::string& packageName) {
+ // This logic is borrowed from PackageParser.java
+ bool hasSep = false;
+ bool front = true;
+
+ for (size_t i = 0; i < packageName.length(); ++i) {
+ char c = packageName[i];
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ front = false;
+ continue;
+ }
+ if (!front) {
+ if ((c >= '0' && c <= '9') || c == '_') {
+ continue;
+ }
+ }
+ if (c == '.') {
+ hasSep = true;
+ front = true;
+ continue;
+ }
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Bad package character %c in %s", c, packageName.c_str()));
+ }
+
+ if (front) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Missing separator in %s", packageName.c_str()));
+ }
+
+ return ok();
+}
+
+binder::Status checkArgumentPackageNames(const std::vector<std::string>& packageNames) {
+ for (size_t i = 0; i < packageNames.size(); ++i) {
+ binder::Status status = checkArgumentPackageName(packageNames[i]);
+ if (!status.isOk()) {
+ return status;
+ }
+ }
+ return ok();
+}
+
+binder::Status checkArgumentSandboxId(const std::string& sandboxId) {
+ // sandboxId will be in either the format shared-<shared-user-id> or <package-name>
+ // and <shared-user-id> name has same requirements as <package-name>.
+ std::size_t nameStartIndex = 0;
+ if (android::base::StartsWith(sandboxId, "shared-")) {
+ nameStartIndex = 7; // len("shared-")
+ }
+ return checkArgumentPackageName(sandboxId.substr(nameStartIndex));
+}
+
+binder::Status checkArgumentSandboxIds(const std::vector<std::string>& sandboxIds) {
+ for (size_t i = 0; i < sandboxIds.size(); ++i) {
+ binder::Status status = checkArgumentSandboxId(sandboxIds[i]);
+ if (!status.isOk()) {
+ return status;
+ }
+ }
+ return ok();
+}
+
#define ENFORCE_UID(uid) \
{ \
binder::Status status = checkUid((uid)); \
@@ -179,6 +242,38 @@
} \
}
+#define CHECK_ARGUMENT_PACKAGE_NAMES(packageNames) \
+ { \
+ binder::Status status = checkArgumentPackageNames((packageNames)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+ }
+
+#define CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds) \
+ { \
+ binder::Status status = checkArgumentSandboxIds((sandboxIds)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+ }
+
+#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) \
+ { \
+ binder::Status status = checkArgumentPackageName((packageName)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+ }
+
+#define CHECK_ARGUMENT_SANDBOX_ID(sandboxId) \
+ { \
+ binder::Status status = checkArgumentSandboxId((sandboxId)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+ }
+
#define ACQUIRE_LOCK \
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock()); \
ATRACE_CALL();
@@ -262,11 +357,17 @@
return translate(VolumeManager::Instance()->onUserRemoved(userId));
}
-binder::Status VoldNativeService::onUserStarted(int32_t userId) {
+binder::Status VoldNativeService::onUserStarted(int32_t userId,
+ const std::vector<std::string>& packageNames,
+ const std::vector<int>& appIds,
+ const std::vector<std::string>& sandboxIds) {
ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAMES(packageNames);
+ CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds);
ACQUIRE_LOCK;
- return translate(VolumeManager::Instance()->onUserStarted(userId));
+ return translate(
+ VolumeManager::Instance()->onUserStarted(userId, packageNames, appIds, sandboxIds));
}
binder::Status VoldNativeService::onUserStopped(int32_t userId) {
@@ -276,6 +377,24 @@
return translate(VolumeManager::Instance()->onUserStopped(userId));
}
+binder::Status VoldNativeService::addAppIds(const std::vector<std::string>& packageNames,
+ const std::vector<int32_t>& appIds) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAMES(packageNames);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->addAppIds(packageNames, appIds));
+}
+
+binder::Status VoldNativeService::addSandboxIds(const std::vector<int32_t>& appIds,
+ const std::vector<std::string>& sandboxIds) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->addSandboxIds(appIds, sandboxIds));
+}
+
binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
@@ -330,10 +449,16 @@
vol->setMountUserId(mountUserId);
int res = vol->mount();
- if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
- VolumeManager::Instance()->setPrimary(vol);
+ if (res != OK) {
+ return translate(res);
}
- return translate(res);
+ if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
+ res = VolumeManager::Instance()->setPrimary(vol);
+ if (res != OK) {
+ return translate(res);
+ }
+ }
+ return translate(OK);
}
binder::Status VoldNativeService::unmount(const std::string& volId) {
@@ -805,6 +930,30 @@
return translateBool(fscrypt_destroy_user_storage(uuid_, userId, flags));
}
+binder::Status VoldNativeService::prepareSandboxForApp(const std::string& packageName,
+ int32_t appId, const std::string& sandboxId,
+ int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ CHECK_ARGUMENT_SANDBOX_ID(sandboxId);
+ ACQUIRE_LOCK;
+
+ return translate(
+ VolumeManager::Instance()->prepareSandboxForApp(packageName, appId, sandboxId, userId));
+}
+
+binder::Status VoldNativeService::destroySandboxForApp(const std::string& packageName,
+ const std::string& sandboxId,
+ int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ CHECK_ARGUMENT_SANDBOX_ID(sandboxId);
+ ACQUIRE_LOCK;
+
+ return translate(
+ VolumeManager::Instance()->destroySandboxForApp(packageName, sandboxId, userId));
+}
+
binder::Status VoldNativeService::startCheckpoint(int32_t retry) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 161acb8..726de68 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -39,9 +39,16 @@
binder::Status onUserAdded(int32_t userId, int32_t userSerial);
binder::Status onUserRemoved(int32_t userId);
- binder::Status onUserStarted(int32_t userId);
+ binder::Status onUserStarted(int32_t userId, const std::vector<std::string>& packageNames,
+ const std::vector<int>& appIds,
+ const std::vector<std::string>& sandboxIds);
binder::Status onUserStopped(int32_t userId);
+ binder::Status addAppIds(const std::vector<std::string>& packageNames,
+ const std::vector<int32_t>& appIds);
+ binder::Status addSandboxIds(const std::vector<int32_t>& appIds,
+ const std::vector<std::string>& sandboxIds);
+
binder::Status onSecureKeyguardStateChanged(bool isShowing);
binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio);
@@ -118,8 +125,10 @@
binder::Status destroyUserStorage(const std::unique_ptr<std::string>& uuid, int32_t userId,
int32_t flags);
- binder::Status mountExternalStorageForApp(const std::string& packageName, int32_t appId,
- const std::string& sandboxId, int32_t userId);
+ binder::Status prepareSandboxForApp(const std::string& packageName, int32_t appId,
+ const std::string& sandboxId, int32_t userId);
+ binder::Status destroySandboxForApp(const std::string& packageName,
+ const std::string& sandboxId, int32_t userId);
binder::Status startCheckpoint(int32_t retry);
binder::Status needsCheckpoint(bool* _aidl_return);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 45dd591..0b2f1bf 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -30,6 +30,7 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <array>
#include <linux/kdev_t.h>
@@ -57,6 +58,7 @@
#include "NetlinkManager.h"
#include "Process.h"
#include "Utils.h"
+#include "VoldNativeService.h"
#include "VoldUtil.h"
#include "VolumeManager.h"
#include "cryptfs.h"
@@ -66,15 +68,20 @@
#include "model/ObbVolume.h"
#include "model/StubVolume.h"
+using android::base::GetBoolProperty;
using android::base::StartsWith;
+using android::base::StringAppendF;
using android::base::StringPrintf;
using android::base::unique_fd;
static const char* kPathUserMount = "/mnt/user";
static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk";
+static const char* kIsolatedStorage = "persist.sys.isolated_storage";
static const char* kPropVirtualDisk = "persist.sys.virtual_disk";
+static const std::string kEmptyString("");
+
/* 512MiB is large enough for testing purposes */
static const unsigned int kSizeVirtualDisk = 536870912;
@@ -102,7 +109,7 @@
int VolumeManager::updateVirtualDisk() {
ATRACE_NAME("VolumeManager::updateVirtualDisk");
- if (android::base::GetBoolProperty(kPropVirtualDisk, false)) {
+ if (GetBoolProperty(kPropVirtualDisk, false)) {
if (access(kPathVirtualDisk, F_OK) != 0) {
Loop::createImageFile(kPathVirtualDisk, kSizeVirtualDisk / 512);
}
@@ -349,7 +356,7 @@
int VolumeManager::linkPrimary(userid_t userId) {
std::string source(mPrimary->getPath());
- if (mPrimary->getType() == android::vold::VolumeBase::Type::kEmulated) {
+ if (mPrimary->isEmulated()) {
source = StringPrintf("%s/%d", source.c_str(), userId);
fs_prepare_dir(source.c_str(), 0755, AID_ROOT, AID_ROOT);
}
@@ -368,6 +375,390 @@
return 0;
}
+int VolumeManager::mountPkgSpecificDir(const std::string& mntSourceRoot,
+ const std::string& mntTargetRoot,
+ const std::string& packageName, const char* dirName) {
+ std::string mntSourceDir =
+ StringPrintf("%s/Android/%s/%s", mntSourceRoot.c_str(), dirName, packageName.c_str());
+ std::string mntTargetDir =
+ StringPrintf("%s/Android/%s/%s", mntTargetRoot.c_str(), dirName, packageName.c_str());
+ if (umount2(mntTargetDir.c_str(), MNT_DETACH) == -1 && errno != EINVAL && errno != ENOENT) {
+ PLOG(ERROR) << "Failed to unmount " << mntTargetDir;
+ return -1;
+ }
+ if (TEMP_FAILURE_RETRY(mount(mntSourceDir.c_str(), mntTargetDir.c_str(), nullptr,
+ MS_BIND | MS_REC, nullptr)) == -1) {
+ PLOG(ERROR) << "Failed to mount " << mntSourceDir << " to " << mntTargetDir;
+ return -1;
+ }
+ if (TEMP_FAILURE_RETRY(
+ mount(nullptr, mntTargetDir.c_str(), nullptr, MS_REC | MS_SLAVE, nullptr)) == -1) {
+ PLOG(ERROR) << "Failed to set MS_SLAVE at " << mntTargetDir;
+ return -1;
+ }
+ return 0;
+}
+
+int VolumeManager::mountPkgSpecificDirsForRunningProcs(
+ userid_t userId, const std::vector<std::string>& packageNames,
+ const std::vector<std::string>& visibleVolLabels) {
+ // TODO: New processes could be started while traversing over the existing
+ // processes which would end up not having the necessary bind mounts. This
+ // issue needs to be fixed, may be by doing multiple passes here?
+ std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir("/proc"), closedir);
+ if (!dirp) {
+ PLOG(ERROR) << "Failed to opendir /proc";
+ return -1;
+ }
+
+ std::string rootName;
+ // Figure out root namespace to compare against below
+ if (!android::vold::Readlinkat(dirfd(dirp.get()), "1/ns/mnt", &rootName)) {
+ PLOG(ERROR) << "Failed to read root namespace";
+ return -1;
+ }
+
+ struct stat fullWriteSb;
+ if (TEMP_FAILURE_RETRY(stat("/mnt/runtime/write", &fullWriteSb)) == -1) {
+ PLOG(ERROR) << "Failed to stat /mnt/runtime/write";
+ return -1;
+ }
+
+ std::unordered_set<appid_t> validAppIds;
+ for (auto& package : packageNames) {
+ validAppIds.insert(mAppIds[package]);
+ }
+ std::vector<std::string>& userPackages = mUserPackages[userId];
+
+ struct dirent* de;
+ // Poke through all running PIDs look for apps running in userId
+ while ((de = readdir(dirp.get()))) {
+ pid_t pid;
+ if (de->d_type != DT_DIR) continue;
+ if (!android::base::ParseInt(de->d_name, &pid)) continue;
+
+ const unique_fd pidFd(
+ openat(dirfd(dirp.get()), de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (pidFd.get() < 0) {
+ PLOG(WARNING) << "Failed to open /proc/" << pid;
+ continue;
+ }
+ struct stat sb;
+ if (fstat(pidFd.get(), &sb) != 0) {
+ PLOG(WARNING) << "Failed to stat " << de->d_name;
+ continue;
+ }
+ if (multiuser_get_user_id(sb.st_uid) != userId) {
+ continue;
+ }
+
+ // Matches so far, but refuse to touch if in root namespace
+ LOG(VERBOSE) << "Found matching PID " << de->d_name;
+ std::string pidName;
+ if (!android::vold::Readlinkat(pidFd.get(), "ns/mnt", &pidName)) {
+ PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
+ continue;
+ }
+ if (rootName == pidName) {
+ LOG(WARNING) << "Skipping due to root namespace";
+ continue;
+ }
+
+ // Only update the mount points of processes running with one of validAppIds.
+ // This should skip any isolated uids.
+ appid_t appId = multiuser_get_app_id(sb.st_uid);
+ if (validAppIds.find(appId) == validAppIds.end()) {
+ continue;
+ }
+
+ std::vector<std::string> packagesForUid;
+ for (auto& package : userPackages) {
+ if (mAppIds[package] == appId) {
+ packagesForUid.push_back(package);
+ }
+ }
+ if (packagesForUid.empty()) {
+ continue;
+ }
+ const std::string& sandboxId = mSandboxIds[appId];
+
+ // We purposefully leave the namespace open across the fork
+ unique_fd nsFd(openat(pidFd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
+ if (nsFd.get() < 0) {
+ PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
+ continue;
+ }
+
+ pid_t child;
+ if (!(child = fork())) {
+ if (setns(nsFd.get(), CLONE_NEWNS) != 0) {
+ PLOG(ERROR) << "Failed to setns for " << de->d_name;
+ _exit(1);
+ }
+
+ struct stat storageSb;
+ if (TEMP_FAILURE_RETRY(stat("/storage", &storageSb)) == -1) {
+ PLOG(ERROR) << "Failed to stat /storage";
+ _exit(1);
+ }
+
+ // Some packages have access to full external storage, identify processes belonging
+ // to those packages by comparing inode no.s of /mnt/runtime/write and /storage
+ if (storageSb.st_dev == fullWriteSb.st_dev && storageSb.st_ino == fullWriteSb.st_ino) {
+ _exit(0);
+ } else {
+ // Some packages don't have access to external storage and processes belonging to
+ // those packages don't have anything mounted at /storage. So, identify those
+ // processes by comparing inode no.s of /mnt/user/%d/package/%s
+ // and /storage
+ std::string pkgStorageSource;
+ for (auto& package : packagesForUid) {
+ std::string sandbox =
+ StringPrintf("/mnt/user/%d/package/%s", userId, package.c_str());
+ struct stat s;
+ if (TEMP_FAILURE_RETRY(stat(sandbox.c_str(), &s)) == -1) {
+ PLOG(ERROR) << "Failed to stat " << sandbox;
+ _exit(1);
+ }
+ if (storageSb.st_dev == s.st_dev && storageSb.st_ino == s.st_ino) {
+ pkgStorageSource = sandbox;
+ break;
+ }
+ }
+ if (pkgStorageSource.empty()) {
+ _exit(0);
+ }
+ }
+
+ for (auto& volumeLabel : visibleVolLabels) {
+ std::string mntSource = StringPrintf("/mnt/runtime/write/%s", volumeLabel.c_str());
+ std::string mntTarget = StringPrintf("/storage/%s", volumeLabel.c_str());
+ if (volumeLabel == "emulated") {
+ StringAppendF(&mntSource, "/%d", userId);
+ StringAppendF(&mntTarget, "/%d", userId);
+ }
+ for (auto& package : packagesForUid) {
+ mountPkgSpecificDir(mntSource, mntTarget, package, "data");
+ mountPkgSpecificDir(mntSource, mntTarget, package, "media");
+ mountPkgSpecificDir(mntSource, mntTarget, package, "obb");
+ }
+ }
+ _exit(0);
+ }
+
+ if (child == -1) {
+ PLOG(ERROR) << "Failed to fork";
+ } else {
+ TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
+ }
+ }
+ return 0;
+}
+
+int VolumeManager::prepareSandboxes(userid_t userId, const std::vector<std::string>& packageNames,
+ const std::vector<std::string>& visibleVolLabels) {
+ if (visibleVolLabels.empty()) {
+ return 0;
+ }
+ for (auto& volumeLabel : visibleVolLabels) {
+ std::string volumeRoot(StringPrintf("/mnt/runtime/write/%s", volumeLabel.c_str()));
+ bool isVolPrimaryEmulated = (volumeLabel == mPrimary->getLabel() && mPrimary->isEmulated());
+ if (isVolPrimaryEmulated) {
+ StringAppendF(&volumeRoot, "/%d", userId);
+ if (fs_prepare_dir(volumeRoot.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << volumeRoot;
+ return -errno;
+ }
+ }
+
+ std::string sandboxRoot =
+ prepareSubDirs(volumeRoot, "Android/sandbox/", 0700, AID_ROOT, AID_ROOT);
+ if (sandboxRoot.empty()) {
+ return -errno;
+ }
+
+ if (!createPkgSpecificDirRoots(volumeRoot)) {
+ return -errno;
+ }
+
+ std::string mntTargetRoot = StringPrintf("/mnt/user/%d", userId);
+ if (fs_prepare_dir(mntTargetRoot.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << mntTargetRoot;
+ return -errno;
+ }
+ mntTargetRoot.append("/package");
+ if (fs_prepare_dir(mntTargetRoot.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << mntTargetRoot;
+ return -errno;
+ }
+
+ for (auto& packageName : packageNames) {
+ const auto& it = mAppIds.find(packageName);
+ if (it == mAppIds.end()) {
+ PLOG(ERROR) << "appId is not available for " << packageName;
+ continue;
+ }
+ appid_t appId = it->second;
+ std::string sandboxId = mSandboxIds[appId];
+ uid_t uid = multiuser_get_uid(userId, appId);
+
+ // [1] Create /mnt/runtime/write/emulated/0/Android/sandbox/<sandboxId>
+ // [2] Create /mnt/user/0/package/<packageName>/emulated/0
+ // Mount [1] at [2]
+ std::string pkgSandboxSourceDir = prepareSandboxSource(uid, sandboxId, sandboxRoot);
+ if (pkgSandboxSourceDir.empty()) {
+ return -errno;
+ }
+ std::string pkgSandboxTargetDir = prepareSandboxTarget(
+ packageName, uid, volumeLabel, mntTargetRoot, isVolPrimaryEmulated);
+ if (pkgSandboxTargetDir.empty()) {
+ return -errno;
+ }
+ if (umount2(pkgSandboxTargetDir.c_str(), MNT_DETACH) == -1 && errno != EINVAL &&
+ errno != ENOENT) {
+ PLOG(ERROR) << "Failed to unmount " << pkgSandboxTargetDir;
+ return -errno;
+ }
+ if (TEMP_FAILURE_RETRY(mount(pkgSandboxSourceDir.c_str(), pkgSandboxTargetDir.c_str(),
+ nullptr, MS_BIND | MS_REC, nullptr)) == -1) {
+ PLOG(ERROR) << "Failed to mount " << pkgSandboxSourceDir << " at "
+ << pkgSandboxTargetDir;
+ return -errno;
+ }
+ if (TEMP_FAILURE_RETRY(mount(nullptr, pkgSandboxTargetDir.c_str(), nullptr,
+ MS_SLAVE | MS_REC, nullptr)) == -1) {
+ PLOG(ERROR) << "Failed to mount " << pkgSandboxSourceDir << " at "
+ << pkgSandboxTargetDir;
+ return -errno;
+ }
+
+ // Create Android/{data,media,obb}/<packageName> segments at
+ // [1] /mnt/runtime/write/emulated/0/ and
+ // [2] /mnt/runtime/write/emulated/0/Android/sandbox/<sandboxId>/emulated/0/
+ if (!createPkgSpecificDirs(packageName, uid, volumeRoot, pkgSandboxSourceDir)) {
+ return -errno;
+ }
+
+ if (volumeLabel == mPrimary->getLabel()) {
+ // Create [1] /mnt/user/0/package/<packageName>/self/
+ // Already created [2] /mnt/user/0/package/<packageName>/emulated/0
+ // Mount [2] at [1]
+ std::string pkgPrimaryTargetDir =
+ StringPrintf("%s/%s/self", mntTargetRoot.c_str(), packageName.c_str());
+ if (fs_prepare_dir(pkgPrimaryTargetDir.c_str(), 0755, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to fs_prepare_dir on " << pkgPrimaryTargetDir;
+ return -errno;
+ }
+ StringAppendF(&pkgPrimaryTargetDir, "/primary");
+ std::string primarySource(mPrimary->getPath());
+ if (isVolPrimaryEmulated) {
+ StringAppendF(&primarySource, "/%d", userId);
+ }
+ if (TEMP_FAILURE_RETRY(unlink(pkgPrimaryTargetDir.c_str()))) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Failed to unlink " << pkgPrimaryTargetDir;
+ }
+ }
+ if (TEMP_FAILURE_RETRY(symlink(primarySource.c_str(), pkgPrimaryTargetDir.c_str()))) {
+ PLOG(ERROR) << "Failed to link " << primarySource << " at "
+ << pkgPrimaryTargetDir;
+ return -errno;
+ }
+ }
+ }
+ }
+ mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels);
+ return 0;
+}
+
+std::string VolumeManager::prepareSubDirs(const std::string& pathPrefix, const std::string& subDirs,
+ mode_t mode, uid_t uid, gid_t gid) {
+ std::string path(pathPrefix);
+ std::vector<std::string> subDirList = android::base::Split(subDirs, "/");
+ for (size_t i = 0; i < subDirList.size(); ++i) {
+ std::string subDir = subDirList[i];
+ if (subDir.empty()) {
+ continue;
+ }
+ StringAppendF(&path, "/%s", subDir.c_str());
+ if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << path;
+ return kEmptyString;
+ }
+ }
+ return path;
+}
+
+std::string VolumeManager::prepareSandboxSource(uid_t uid, const std::string& sandboxId,
+ const std::string& sandboxRootDir) {
+ std::string sandboxSourceDir(sandboxRootDir);
+ StringAppendF(&sandboxSourceDir, "/%s", sandboxId.c_str());
+ if (fs_prepare_dir(sandboxSourceDir.c_str(), 0755, uid, uid) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << sandboxSourceDir;
+ return kEmptyString;
+ }
+ return sandboxSourceDir;
+}
+
+std::string VolumeManager::prepareSandboxTarget(const std::string& packageName, uid_t uid,
+ const std::string& volumeLabel,
+ const std::string& mntTargetRootDir,
+ bool isUserDependent) {
+ std::string segment;
+ if (isUserDependent) {
+ segment = StringPrintf("%s/%s/%d/", packageName.c_str(), volumeLabel.c_str(),
+ multiuser_get_user_id(uid));
+ } else {
+ segment = StringPrintf("%s/%s/", packageName.c_str(), volumeLabel.c_str());
+ }
+ return prepareSubDirs(mntTargetRootDir, segment.c_str(), 0755, uid, uid);
+}
+
+std::string VolumeManager::preparePkgDataSource(const std::string& packageName, uid_t uid,
+ const std::string& dataRootDir) {
+ std::string dataSourceDir = StringPrintf("%s/%s", dataRootDir.c_str(), packageName.c_str());
+ if (fs_prepare_dir(dataSourceDir.c_str(), 0755, uid, uid) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << dataSourceDir;
+ return kEmptyString;
+ }
+ return dataSourceDir;
+}
+
+bool VolumeManager::createPkgSpecificDirRoots(const std::string& volumeRoot) {
+ std::string volumeAndroidRoot = StringPrintf("%s/Android", volumeRoot.c_str());
+ if (fs_prepare_dir(volumeAndroidRoot.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << volumeAndroidRoot;
+ return false;
+ }
+ std::array<std::string, 3> dirs = {"data", "media", "obb"};
+ for (auto& dir : dirs) {
+ std::string path = StringPrintf("%s/%s", volumeAndroidRoot.c_str(), dir.c_str());
+ if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ PLOG(ERROR) << "fs_prepare_dir failed on " << path;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool VolumeManager::createPkgSpecificDirs(const std::string& packageName, uid_t uid,
+ const std::string& volumeRoot,
+ const std::string& sandboxDirRoot) {
+ std::array<std::string, 3> dirs = {"data", "media", "obb"};
+ for (auto& dir : dirs) {
+ std::string sourceDir = StringPrintf("%s/Android/%s", volumeRoot.c_str(), dir.c_str());
+ if (prepareSubDirs(sourceDir, packageName, 0755, uid, uid).empty()) {
+ return false;
+ }
+ std::string sandboxSegment =
+ StringPrintf("Android/%s/%s/", dir.c_str(), packageName.c_str());
+ if (prepareSubDirs(sandboxDirRoot, sandboxSegment, 0755, uid, uid).empty()) {
+ return false;
+ }
+ }
+ return true;
+}
+
int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) {
mAddedUsers[userId] = userSerialNumber;
return 0;
@@ -378,7 +769,10 @@
return 0;
}
-int VolumeManager::onUserStarted(userid_t userId) {
+int VolumeManager::onUserStarted(userid_t userId, const std::vector<std::string>& packageNames,
+ const std::vector<int>& appIds,
+ const std::vector<std::string>& sandboxIds) {
+ LOG(VERBOSE) << "onUserStarted: " << userId;
// 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.
@@ -386,14 +780,153 @@
fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT);
mStartedUsers.insert(userId);
+ mUserPackages[userId] = packageNames;
+ for (size_t i = 0; i < packageNames.size(); ++i) {
+ mAppIds[packageNames[i]] = appIds[i];
+ mSandboxIds[appIds[i]] = sandboxIds[i];
+ }
if (mPrimary) {
linkPrimary(userId);
}
+ if (GetBoolProperty(kIsolatedStorage, false)) {
+ std::vector<std::string> visibleVolLabels;
+ for (auto& volId : mVisibleVolumeIds) {
+ auto vol = findVolume(volId);
+ userid_t mountUserId = vol->getMountUserId();
+ if (mountUserId == userId || vol->isEmulated()) {
+ visibleVolLabels.push_back(vol->getLabel());
+ }
+ }
+ if (prepareSandboxes(userId, packageNames, visibleVolLabels) != 0) {
+ return -errno;
+ }
+ }
return 0;
}
int VolumeManager::onUserStopped(userid_t userId) {
+ LOG(VERBOSE) << "onUserStopped: " << userId;
mStartedUsers.erase(userId);
+
+ if (GetBoolProperty(kIsolatedStorage, false)) {
+ mUserPackages.erase(userId);
+ std::string mntTargetDir = StringPrintf("/mnt/user/%d", userId);
+ if (android::vold::UnmountTree(mntTargetDir) != 0) {
+ PLOG(ERROR) << "unmountTree on " << mntTargetDir << " failed";
+ return -errno;
+ }
+ if (android::vold::DeleteDirContentsAndDir(mntTargetDir) < 0) {
+ PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << mntTargetDir;
+ return -errno;
+ }
+ LOG(VERBOSE) << "Success: DeleteDirContentsAndDir on " << mntTargetDir;
+ }
+ return 0;
+}
+
+int VolumeManager::addAppIds(const std::vector<std::string>& packageNames,
+ const std::vector<int32_t>& appIds) {
+ for (size_t i = 0; i < packageNames.size(); ++i) {
+ mAppIds[packageNames[i]] = appIds[i];
+ }
+ return 0;
+}
+
+int VolumeManager::addSandboxIds(const std::vector<int32_t>& appIds,
+ const std::vector<std::string>& sandboxIds) {
+ for (size_t i = 0; i < appIds.size(); ++i) {
+ mSandboxIds[appIds[i]] = sandboxIds[i];
+ }
+ return 0;
+}
+
+int VolumeManager::prepareSandboxForApp(const std::string& packageName, appid_t appId,
+ const std::string& sandboxId, userid_t userId) {
+ if (!GetBoolProperty(kIsolatedStorage, false)) {
+ return 0;
+ } else if (mStartedUsers.find(userId) == mStartedUsers.end()) {
+ // User not started, no need to do anything now. Required bind mounts for the package will
+ // be created when the user starts.
+ return 0;
+ }
+ LOG(VERBOSE) << "prepareSandboxForApp: " << packageName << ", appId=" << appId
+ << ", sandboxId=" << sandboxId << ", userId=" << userId;
+ mUserPackages[userId].push_back(packageName);
+ mAppIds[packageName] = appId;
+ mSandboxIds[appId] = sandboxId;
+
+ std::vector<std::string> visibleVolLabels;
+ for (auto& volId : mVisibleVolumeIds) {
+ auto vol = findVolume(volId);
+ userid_t mountUserId = vol->getMountUserId();
+ if (mountUserId == userId || vol->isEmulated()) {
+ visibleVolLabels.push_back(vol->getLabel());
+ }
+ }
+ return prepareSandboxes(userId, {packageName}, visibleVolLabels);
+}
+
+int VolumeManager::destroySandboxForApp(const std::string& packageName,
+ const std::string& sandboxId, userid_t userId) {
+ if (!GetBoolProperty(kIsolatedStorage, false)) {
+ return 0;
+ }
+ LOG(VERBOSE) << "destroySandboxForApp: " << packageName << ", sandboxId=" << sandboxId
+ << ", userId=" << userId;
+ auto& userPackages = mUserPackages[userId];
+ std::remove(userPackages.begin(), userPackages.end(), packageName);
+ // If the package is not uninstalled in any other users, remove appId and sandboxId
+ // corresponding to it from the internal state.
+ bool installedInAnyUser = false;
+ for (auto& it : mUserPackages) {
+ auto& packages = it.second;
+ if (std::find(packages.begin(), packages.end(), packageName) != packages.end()) {
+ installedInAnyUser = true;
+ break;
+ }
+ }
+ if (!installedInAnyUser) {
+ const auto& entry = mAppIds.find(packageName);
+ if (entry != mAppIds.end()) {
+ mSandboxIds.erase(entry->second);
+ mAppIds.erase(entry);
+ }
+ }
+
+ std::vector<std::string> visibleVolLabels;
+ for (auto& volId : mVisibleVolumeIds) {
+ auto vol = findVolume(volId);
+ userid_t mountUserId = vol->getMountUserId();
+ if (mountUserId == userId || vol->isEmulated()) {
+ if (destroySandboxForAppOnVol(packageName, sandboxId, userId, vol->getLabel()) < 0) {
+ return -errno;
+ }
+ }
+ }
+ return 0;
+}
+
+int VolumeManager::destroySandboxForAppOnVol(const std::string& packageName,
+ const std::string& sandboxId, userid_t userId,
+ const std::string& volLabel) {
+ LOG(VERBOSE) << "destroySandboxOnVol: " << packageName << ", userId=" << userId
+ << ", volLabel=" << volLabel;
+ std::string pkgSandboxTarget =
+ StringPrintf("/mnt/user/%d/package/%s", userId, packageName.c_str());
+ if (android::vold::UnmountTree(pkgSandboxTarget)) {
+ PLOG(ERROR) << "UnmountTree failed on " << pkgSandboxTarget;
+ }
+
+ std::string sandboxDir = StringPrintf("/mnt/runtime/write/%s", volLabel.c_str());
+ if (volLabel == mPrimary->getLabel() && mPrimary->isEmulated()) {
+ StringAppendF(&sandboxDir, "/%d", userId);
+ }
+ StringAppendF(&sandboxDir, "/Android/sandbox/%s", sandboxId.c_str());
+
+ if (android::vold::DeleteDirContentsAndDir(sandboxDir) < 0) {
+ PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << sandboxDir;
+ return -errno;
+ }
return 0;
}
@@ -411,7 +944,93 @@
return 0;
}
+int VolumeManager::onVolumeMounted(android::vold::VolumeBase* vol) {
+ if (!GetBoolProperty(kIsolatedStorage, false)) {
+ return 0;
+ }
+
+ if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_VISIBLE) == 0) {
+ return 0;
+ }
+
+ mVisibleVolumeIds.insert(vol->getId());
+ userid_t mountUserId = vol->getMountUserId();
+ if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_PRIMARY) != 0) {
+ // We don't want to create another shared_ptr here because then we will end up with
+ // two shared_ptrs owning the underlying pointer without sharing it.
+ mPrimary = findVolume(vol->getId());
+ for (userid_t userId : mStartedUsers) {
+ if (linkPrimary(userId) != 0) {
+ return -errno;
+ }
+ }
+ }
+ if (vol->isEmulated()) {
+ for (userid_t userId : mStartedUsers) {
+ if (prepareSandboxes(userId, mUserPackages[userId], {vol->getLabel()}) != 0) {
+ return -errno;
+ }
+ }
+ } else if (mStartedUsers.find(mountUserId) != mStartedUsers.end()) {
+ if (prepareSandboxes(mountUserId, mUserPackages[mountUserId], {vol->getLabel()}) != 0) {
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+int VolumeManager::onVolumeUnmounted(android::vold::VolumeBase* vol) {
+ if (!GetBoolProperty(kIsolatedStorage, false)) {
+ return 0;
+ }
+
+ if (mVisibleVolumeIds.erase(vol->getId()) == 0) {
+ return 0;
+ }
+
+ if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_PRIMARY) != 0) {
+ mPrimary = nullptr;
+ }
+
+ LOG(VERBOSE) << "visibleVolumeUnmounted: " << vol;
+ userid_t mountUserId = vol->getMountUserId();
+ if (vol->isEmulated()) {
+ for (userid_t userId : mStartedUsers) {
+ if (destroySandboxesForVol(vol, userId) != 0) {
+ return -errno;
+ }
+ }
+ } else if (mStartedUsers.find(mountUserId) != mStartedUsers.end()) {
+ if (destroySandboxesForVol(vol, mountUserId) != 0) {
+ return -errno;
+ }
+ }
+ return 0;
+}
+
+int VolumeManager::destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId) {
+ LOG(VERBOSE) << "destroysandboxesForVol: " << vol << " for user=" << userId;
+ const std::vector<std::string>& packageNames = mUserPackages[userId];
+ for (auto& packageName : packageNames) {
+ std::string volSandboxRoot = StringPrintf("/mnt/user/%d/package/%s/%s", userId,
+ packageName.c_str(), vol->getLabel().c_str());
+ if (android::vold::UnmountTree(volSandboxRoot) != 0) {
+ PLOG(ERROR) << "unmountTree on " << volSandboxRoot << " failed";
+ continue;
+ }
+ if (android::vold::DeleteDirContentsAndDir(volSandboxRoot) < 0) {
+ PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << volSandboxRoot;
+ continue;
+ }
+ LOG(VERBOSE) << "Success: DeleteDirContentsAndDir on " << volSandboxRoot;
+ }
+ return 0;
+}
+
int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol) {
+ if (GetBoolProperty(kIsolatedStorage, false)) {
+ return 0;
+ }
mPrimary = vol;
for (userid_t userId : mStartedUsers) {
linkPrimary(userId);
@@ -420,6 +1039,11 @@
}
int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
+ // If the isolated storage is enabled, return -1 since in the isolated storage world, there
+ // are no longer any runtime storage permissions, so this shouldn't be called anymore.
+ if (GetBoolProperty(kIsolatedStorage, false)) {
+ return -1;
+ }
LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
DIR* dir;
@@ -552,6 +1176,14 @@
updateVirtualDisk();
mAddedUsers.clear();
mStartedUsers.clear();
+
+ mUserPackages.clear();
+ mAppIds.clear();
+ mSandboxIds.clear();
+ mVisibleVolumeIds.clear();
+
+ // For unmounting dirs under /mnt/user/<user-id>/package/<package-name>
+ android::vold::UnmountTree("/mnt/user/");
return 0;
}
diff --git a/VolumeManager.h b/VolumeManager.h
index 9227819..9e990d0 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -88,9 +88,21 @@
int onUserAdded(userid_t userId, int userSerialNumber);
int onUserRemoved(userid_t userId);
- int onUserStarted(userid_t userId);
+ int onUserStarted(userid_t userId, const std::vector<std::string>& packageNames,
+ const std::vector<int>& appIds, const std::vector<std::string>& sandboxIds);
int onUserStopped(userid_t userId);
+ int addAppIds(const std::vector<std::string>& packageNames, const std::vector<int32_t>& appIds);
+ int addSandboxIds(const std::vector<int32_t>& appIds,
+ const std::vector<std::string>& sandboxIds);
+ int prepareSandboxForApp(const std::string& packageName, appid_t appId,
+ const std::string& sandboxId, userid_t userId);
+ int destroySandboxForApp(const std::string& packageName, const std::string& sandboxId,
+ userid_t userId);
+
+ int onVolumeMounted(android::vold::VolumeBase* vol);
+ int onVolumeUnmounted(android::vold::VolumeBase* vol);
+
int onSecureKeyguardStateChanged(bool isShowing);
int setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol);
@@ -137,6 +149,29 @@
int linkPrimary(userid_t userId);
+ int prepareSandboxes(userid_t userId, const std::vector<std::string>& packageNames,
+ const std::vector<std::string>& visibleVolLabels);
+ int mountPkgSpecificDirsForRunningProcs(userid_t userId,
+ const std::vector<std::string>& packageNames,
+ const std::vector<std::string>& visibleVolLabels);
+ int destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId);
+ std::string prepareSandboxSource(uid_t uid, const std::string& sandboxId,
+ const std::string& sandboxRootDir);
+ std::string prepareSandboxTarget(const std::string& packageName, uid_t uid,
+ const std::string& volumeLabel,
+ const std::string& mntTargetRootDir, bool isUserDependent);
+ std::string preparePkgDataSource(const std::string& packageName, uid_t uid,
+ const std::string& dataRootDir);
+ std::string prepareSubDirs(const std::string& pathPrefix, const std::string& subDirs,
+ mode_t mode, uid_t uid, gid_t gid);
+ bool createPkgSpecificDirRoots(const std::string& volumeRoot);
+ bool createPkgSpecificDirs(const std::string& packageName, uid_t uid,
+ const std::string& volumeRoot, const std::string& sandboxDirRoot);
+ int mountPkgSpecificDir(const std::string& mntSourceRoot, const std::string& mntTargetRoot,
+ const std::string& packageName, const char* dirName);
+ int destroySandboxForAppOnVol(const std::string& packageName, const std::string& sandboxId,
+ userid_t userId, const std::string& volLabel);
+
void handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk);
void handleDiskChanged(dev_t device);
void handleDiskRemoved(dev_t device);
@@ -160,6 +195,11 @@
std::shared_ptr<android::vold::VolumeBase> mInternalEmulated;
std::shared_ptr<android::vold::VolumeBase> mPrimary;
+ std::unordered_map<std::string, appid_t> mAppIds;
+ std::unordered_map<appid_t, std::string> mSandboxIds;
+ std::unordered_map<userid_t, std::vector<std::string>> mUserPackages;
+ std::unordered_set<std::string> mVisibleVolumeIds;
+
int mNextObbId;
int mNextStubVolumeId;
bool mSecureKeyguardShowing;
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 976eab1..2f7430f 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -29,9 +29,13 @@
void onUserAdded(int userId, int userSerial);
void onUserRemoved(int userId);
- void onUserStarted(int userId);
+ void onUserStarted(int userId, in @utf8InCpp String[] packageNames, in int[] appIds,
+ in @utf8InCpp String[] sandboxIds);
void onUserStopped(int userId);
+ void addAppIds(in @utf8InCpp String[] packageNames, in int[] appIds);
+ void addSandboxIds(in int[] appIds, in @utf8InCpp String[] sandboxIds);
+
void onSecureKeyguardStateChanged(boolean isShowing);
void partition(@utf8InCpp String diskId, int partitionType, int ratio);
@@ -96,6 +100,11 @@
int storageFlags);
void destroyUserStorage(@nullable @utf8InCpp String uuid, int userId, int storageFlags);
+ void prepareSandboxForApp(in @utf8InCpp String packageName, int appId,
+ in @utf8InCpp String sandboxId, int userId);
+ void destroySandboxForApp(in @utf8InCpp String packageName,
+ in @utf8InCpp String sandboxId, int userId);
+
void startCheckpoint(int retry);
boolean needsCheckpoint();
boolean needsRollback();
@@ -142,6 +151,7 @@
const int REMOUNT_MODE_DEFAULT = 1;
const int REMOUNT_MODE_READ = 2;
const int REMOUNT_MODE_WRITE = 3;
+ const int REMOUNT_MODE_FULL = 4;
const int VOLUME_STATE_UNMOUNTED = 0;
const int VOLUME_STATE_CHECKING = 1;
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 5be29be..ae25e9a 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -2458,24 +2458,25 @@
static unsigned int persist_get_max_entries(int encrypted) {
struct crypt_mnt_ftr crypt_ftr;
unsigned int dsize;
- unsigned int max_persistent_entries;
/* If encrypted, use the values from the crypt_ftr, otherwise
* use the values for the current spec.
*/
if (encrypted) {
if (get_crypt_ftr_and_key(&crypt_ftr)) {
- return -1;
+ /* Something is wrong, assume no space for entries */
+ return 0;
}
dsize = crypt_ftr.persist_data_size;
} else {
dsize = CRYPT_PERSIST_DATA_SIZE;
}
- max_persistent_entries =
- (dsize - sizeof(struct crypt_persist_data)) / sizeof(struct crypt_persist_entry);
-
- return max_persistent_entries;
+ if (dsize > sizeof(struct crypt_persist_data)) {
+ return (dsize - sizeof(struct crypt_persist_data)) / sizeof(struct crypt_persist_entry);
+ } else {
+ return 0;
+ }
}
static int persist_get_key(const char* fieldname, char* value) {
diff --git a/main.cpp b/main.cpp
index e1f8404..347c945 100644
--- a/main.cpp
+++ b/main.cpp
@@ -53,7 +53,7 @@
int main(int argc, char** argv) {
atrace_set_tracing_enabled(false);
- setenv("ANDROID_LOG_TAGS", "*:d", 1);
+ setenv("ANDROID_LOG_TAGS", "*:d", 1); // Do not submit with verbose logs enabled
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Vold 3.0 (the awakening) firing up";
diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
index 8d9ac74..8f46191 100644
--- a/model/EmulatedVolume.cpp
+++ b/model/EmulatedVolume.cpp
@@ -16,9 +16,10 @@
#include "EmulatedVolume.h"
#include "Utils.h"
+#include "VolumeManager.h"
-#include <android-base/stringprintf.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
#include <utils/Timers.h>
@@ -68,6 +69,7 @@
setInternalPath(mRawPath);
setPath(StringPrintf("/storage/%s", label.c_str()));
+ setLabel(label);
if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index 8ed4356..77a156c 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -21,6 +21,7 @@
#include "fs/Vfat.h"
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
@@ -34,6 +35,7 @@
#include <sys/types.h>
#include <sys/wait.h>
+using android::base::GetBoolProperty;
using android::base::StringPrintf;
namespace android {
@@ -43,6 +45,8 @@
static const char* kAsecPath = "/mnt/secure/asec";
+static const char* kIsolatedStorage = "persist.sys.isolated_storage";
+
PublicVolume::PublicVolume(dev_t device) : VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) {
setId(StringPrintf("public:%u,%u", major(device), minor(device)));
mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str());
@@ -126,6 +130,7 @@
} else {
setPath(mRawPath);
}
+ setLabel(stableName);
if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
PLOG(ERROR) << getId() << " failed to create mount points";
@@ -178,16 +183,36 @@
PLOG(ERROR) << "Failed to exec";
}
} else {
+ // In Pre-Q, apps have full read access to secondary storage devices but only
+ // write access for their package specific directories. In Q, they only have access
+ // to their own sandboxes and they can write anywhere inside the sandbox. Instead of
+ // updating sdcardfs to allow packages writing into their own sandboxes, we could
+ // just allow them to write anywhere by passing "-w".
// clang-format off
- if (execl(kFusePath, kFusePath,
- "-u", "1023", // AID_MEDIA_RW
- "-g", "1023", // AID_MEDIA_RW
- "-U", std::to_string(getMountUserId()).c_str(),
- mRawPath.c_str(),
- stableName.c_str(),
- NULL)) {
- // clang-format on
- PLOG(ERROR) << "Failed to exec";
+ if (GetBoolProperty(kIsolatedStorage, false)) {
+ if (execl(kFusePath, kFusePath,
+ "-u", "1023", // AID_MEDIA_RW
+ "-g", "1023", // AID_MEDIA_RW
+ "-U", std::to_string(getMountUserId()).c_str(),
+ "-w",
+ mRawPath.c_str(),
+ stableName.c_str(),
+ NULL)) {
+ // clang-format on
+ PLOG(ERROR) << "Failed to exec";
+ }
+ } else {
+ // clang-format off
+ if (execl(kFusePath, kFusePath,
+ "-u", "1023", // AID_MEDIA_RW
+ "-g", "1023", // AID_MEDIA_RW
+ "-U", std::to_string(getMountUserId()).c_str(),
+ mRawPath.c_str(),
+ stableName.c_str(),
+ NULL)) {
+ // clang-format on
+ PLOG(ERROR) << "Failed to exec";
+ }
}
}
diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp
index 300add1..29bc32c 100644
--- a/model/VolumeBase.cpp
+++ b/model/VolumeBase.cpp
@@ -35,7 +35,7 @@
VolumeBase::VolumeBase(Type type)
: mType(type),
mMountFlags(0),
- mMountUserId(-1),
+ mMountUserId(USER_UNKNOWN),
mCreated(false),
mState(State::kUnmounted),
mSilent(false) {}
@@ -143,6 +143,16 @@
return OK;
}
+status_t VolumeBase::setLabel(const std::string& label) {
+ if (mState != State::kChecking) {
+ LOG(WARNING) << getId() << " label change requires state checking";
+ return -EBUSY;
+ }
+
+ mLabel = label;
+ return OK;
+}
+
android::sp<android::os::IVoldListener> VolumeBase::getListener() {
if (mSilent) {
return nullptr;
@@ -220,10 +230,9 @@
setState(State::kChecking);
status_t res = doMount();
if (res == OK) {
- setState(State::kMounted);
- } else {
- setState(State::kUnmountable);
+ res = VolumeManager::Instance()->onVolumeMounted(this);
}
+ setState(res == OK ? State::kMounted : State::kUnmountable);
return res;
}
@@ -242,8 +251,11 @@
}
mVolumes.clear();
- status_t res = doUnmount();
- setState(State::kUnmounted);
+ status_t res = VolumeManager::Instance()->onVolumeUnmounted(this);
+ if (res == OK) {
+ res = doUnmount();
+ setState(State::kUnmounted);
+ }
return res;
}
@@ -267,5 +279,10 @@
return -ENOTSUP;
}
+std::ostream& VolumeBase::operator<<(std::ostream& stream) const {
+ return stream << " VolumeBase{id=" << mId << ",label=" << mLabel
+ << ",mountFlags=" << mMountFlags << ",mountUserId=" << mMountUserId << "}";
+}
+
} // namespace vold
} // namespace android
diff --git a/model/VolumeBase.h b/model/VolumeBase.h
index 92a83f0..ea187bd 100644
--- a/model/VolumeBase.h
+++ b/model/VolumeBase.h
@@ -27,6 +27,8 @@
#include <list>
#include <string>
+static constexpr userid_t USER_UNKNOWN = ((userid_t)-1);
+
namespace android {
namespace vold {
@@ -85,6 +87,7 @@
State getState() { return mState; }
const std::string& getPath() { return mPath; }
const std::string& getInternalPath() { return mInternalPath; }
+ const std::string& getLabel() { return mLabel; }
status_t setDiskId(const std::string& diskId);
status_t setPartGuid(const std::string& partGuid);
@@ -97,12 +100,16 @@
std::shared_ptr<VolumeBase> findVolume(const std::string& id);
+ bool isEmulated() { return mType == Type::kEmulated; }
+
status_t create();
status_t destroy();
status_t mount();
status_t unmount();
status_t format(const std::string& fsType);
+ std::ostream& operator<<(std::ostream& stream) const;
+
protected:
explicit VolumeBase(Type type);
@@ -115,6 +122,7 @@
status_t setId(const std::string& id);
status_t setPath(const std::string& path);
status_t setInternalPath(const std::string& internalPath);
+ status_t setLabel(const std::string& label);
android::sp<android::os::IVoldListener> getListener();
@@ -141,6 +149,12 @@
std::string mInternalPath;
/* Flag indicating that volume should emit no events */
bool mSilent;
+ /**
+ * Label used for representing the package sandboxes on external storage volumes.
+ * For emulated volume, this would be "emulated" and for public volumes, UUID if available,
+ * otherwise some other unique id.
+ */
+ std::string mLabel;
/* Volumes stacked on top of this volume */
std::list<std::shared_ptr<VolumeBase>> mVolumes;