diff --git a/AppFuseUtil.cpp b/AppFuseUtil.cpp index c491ecd..711e70b 100644 --- a/AppFuseUtil.cpp +++ b/AppFuseUtil.cpp @@ -49,9 +49,6 @@ static android::status_t GetMountPath(uid_t uid, const std::string& name, std::s } static android::status_t Mount(int device_fd, const std::string& path) { - // Remove existing mount. - android::vold::ForceUnmount(path); - const auto opts = StringPrintf( "fd=%i," "rootmode=40000," @@ -115,6 +112,11 @@ int MountAppFuse(uid_t uid, int mountId, android::base::unique_fd* device_fd) { return -1; } + // Forcibly remove the existing mount before we attempt to prepare the + // directory. If we have a dangling mount, then PrepareDir may fail if the + // indirection to FUSE doesn't work. + android::vold::ForceUnmount(path); + // Create directories. const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0); if (result != android::OK) { diff --git a/FsCrypt.cpp b/FsCrypt.cpp index 5f659a8..3028b60 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -269,7 +269,7 @@ static bool lookup_key_ref(const std::map& key_map, useri std::string* raw_ref) { auto refi = key_map.find(user_id); if (refi == key_map.end()) { - LOG(ERROR) << "Cannot find key for " << user_id; + LOG(DEBUG) << "Cannot find key for " << user_id; return false; } *raw_ref = refi->second; diff --git a/IdleMaint.cpp b/IdleMaint.cpp index 47c277e..2b5a8f1 100644 --- a/IdleMaint.cpp +++ b/IdleMaint.cpp @@ -49,8 +49,8 @@ using android::fs_mgr::Fstab; using android::fs_mgr::ReadDefaultFstab; 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 6a3830f..1616d80 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -194,13 +195,55 @@ status_t KillProcessesUsingPath(const std::string& path) { } status_t BindMount(const std::string& source, const std::string& target) { - if (::mount(source.c_str(), target.c_str(), "", MS_BIND, NULL)) { + if (UnmountTree(target) < 0) { + return -errno; + } + if (TEMP_FAILURE_RETRY(mount(source.c_str(), target.c_str(), nullptr, MS_BIND, nullptr)) < 0) { PLOG(ERROR) << "Failed to bind mount " << source << " to " << target; return -errno; } return OK; } +status_t Symlink(const std::string& target, const std::string& linkpath) { + if (Unlink(linkpath) < 0) { + return -errno; + } + if (TEMP_FAILURE_RETRY(symlink(target.c_str(), linkpath.c_str())) < 0) { + PLOG(ERROR) << "Failed to create symlink " << linkpath << " to " << target; + return -errno; + } + return OK; +} + +status_t Unlink(const std::string& linkpath) { + if (TEMP_FAILURE_RETRY(unlink(linkpath.c_str())) < 0 && errno != EINVAL && errno != ENOENT) { + PLOG(ERROR) << "Failed to unlink " << linkpath; + return -errno; + } + return OK; +} + +status_t CreateDir(const std::string& dir, mode_t mode) { + struct stat sb; + if (TEMP_FAILURE_RETRY(stat(dir.c_str(), &sb)) == 0) { + if (S_ISDIR(sb.st_mode)) { + return OK; + } else if (TEMP_FAILURE_RETRY(unlink(dir.c_str())) == -1) { + PLOG(ERROR) << "Failed to unlink " << dir; + return -errno; + } + } else if (errno != ENOENT) { + PLOG(ERROR) << "Failed to stat " << dir; + return -errno; + } + if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), mode)) == -1 && errno != EEXIST) { + PLOG(ERROR) << "Failed to mkdir " << dir; + return -errno; + } + return OK; +} + bool FindValue(const std::string& raw, const std::string& key, std::string* value) { auto qual = key + "=\""; size_t start = 0; @@ -801,13 +844,87 @@ status_t UnmountTreeWithPrefix(const std::string& prefix) { } status_t UnmountTree(const std::string& mountPoint) { - if (umount2(mountPoint.c_str(), MNT_DETACH)) { + if (TEMP_FAILURE_RETRY(umount2(mountPoint.c_str(), MNT_DETACH)) < 0 && errno != EINVAL && + errno != ENOENT) { PLOG(ERROR) << "Failed to unmount " << mountPoint; return -errno; } 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 = OK; + 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 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) { + status_t res = DeleteDirContents(pathname); + if (res < 0) { + return res; + } + if (TEMP_FAILURE_RETRY(rmdir(pathname.c_str())) < 0 && errno != ENOENT) { + PLOG(ERROR) << "rmdir failed on " << pathname; + return -errno; + } + LOG(VERBOSE) << "Success: rmdir on " << pathname; + return OK; +} + +status_t DeleteDirContents(const std::string& pathname) { + // Shamelessly borrowed from android::installd + std::unique_ptr dirp(opendir(pathname.c_str()), closedir); + if (!dirp) { + if (errno == ENOENT) { + return OK; + } + PLOG(ERROR) << "Failed to opendir " << pathname; + return -errno; + } + return delete_dir_contents(dirp.get()); +} + // 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 c083021..af4e401 100644 --- a/Utils.h +++ b/Utils.h @@ -57,6 +57,15 @@ status_t KillProcessesUsingPath(const std::string& path); /* Creates bind mount from source to target */ status_t BindMount(const std::string& source, const std::string& target); +/** Creates a symbolic link to target */ +status_t Symlink(const std::string& target, const std::string& linkpath); + +/** Calls unlink(2) at linkpath */ +status_t Unlink(const std::string& linkpath); + +/** Creates the given directory if it is not already available */ +status_t CreateDir(const std::string& dir, mode_t mode); + bool FindValue(const std::string& raw, const std::string& key, std::string* value); /* Reads filesystem metadata from device at path */ @@ -130,6 +139,9 @@ bool IsRunningInEmulator(); status_t UnmountTreeWithPrefix(const std::string& prefix); status_t UnmountTree(const std::string& mountPoint); +status_t DeleteDirContentsAndDir(const std::string& pathname); +status_t DeleteDirContents(const std::string& pathname); + status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout); bool FsyncDirectory(const std::string& dirname); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 3a8754f..1762b70 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -276,6 +276,16 @@ binder::Status VoldNativeService::onUserStopped(int32_t userId) { return translate(VolumeManager::Instance()->onUserStopped(userId)); } +binder::Status VoldNativeService::addAppIds(const std::vector& packageNames, + const std::vector& appIds) { + return ok(); +} + +binder::Status VoldNativeService::addSandboxIds(const std::vector& appIds, + const std::vector& sandboxIds) { + return ok(); +} + binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; @@ -330,10 +340,16 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF vol->setMountUserId(mountUserId); int res = vol->mount(); + if (res != OK) { + return translate(res); + } if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) { - VolumeManager::Instance()->setPrimary(vol); + res = VolumeManager::Instance()->setPrimary(vol); + if (res != OK) { + return translate(res); + } } - return translate(res); + return translate(OK); } binder::Status VoldNativeService::unmount(const std::string& volId) { @@ -431,24 +447,7 @@ binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { ENFORCE_UID(AID_SYSTEM); ACQUIRE_LOCK; - std::string tmp; - switch (remountMode) { - case REMOUNT_MODE_NONE: - tmp = "none"; - break; - case REMOUNT_MODE_DEFAULT: - tmp = "default"; - break; - case REMOUNT_MODE_READ: - tmp = "read"; - break; - case REMOUNT_MODE_WRITE: - tmp = "write"; - break; - default: - return error("Unknown mode " + std::to_string(remountMode)); - } - return translate(VolumeManager::Instance()->remountUid(uid, tmp)); + return translate(VolumeManager::Instance()->remountUid(uid, remountMode)); } binder::Status VoldNativeService::mkdirs(const std::string& path) { @@ -807,6 +806,18 @@ binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr, public os::Bn binder::Status onUserStarted(int32_t userId); binder::Status onUserStopped(int32_t userId); + binder::Status addAppIds(const std::vector& packageNames, + const std::vector& appIds); + binder::Status addSandboxIds(const std::vector& appIds, + const std::vector& sandboxIds); + binder::Status onSecureKeyguardStateChanged(bool isShowing); binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio); @@ -118,8 +123,10 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status destroyUserStorage(const std::unique_ptr& 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 897c2a8..44bff5a 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -58,6 +59,7 @@ #include "NetlinkManager.h" #include "Process.h" #include "Utils.h" +#include "VoldNativeService.h" #include "VoldUtil.h" #include "VolumeManager.h" #include "cryptfs.h" @@ -67,15 +69,28 @@ #include "model/ObbVolume.h" #include "model/StubVolume.h" +using android::OK; +using android::base::GetBoolProperty; using android::base::StartsWith; +using android::base::StringAppendF; using android::base::StringPrintf; using android::base::unique_fd; +using android::vold::BindMount; +using android::vold::CreateDir; +using android::vold::DeleteDirContents; +using android::vold::DeleteDirContentsAndDir; +using android::vold::Symlink; +using android::vold::Unlink; +using android::vold::UnmountTree; +using android::vold::VoldNativeService; static const char* kPathUserMount = "/mnt/user"; static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk"; 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; @@ -103,7 +118,7 @@ VolumeManager::~VolumeManager() {} 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); } @@ -351,22 +366,14 @@ int VolumeManager::forgetPartition(const std::string& partGuid, const std::strin 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); } std::string target(StringPrintf("/mnt/user/%d/primary", userId)); - if (TEMP_FAILURE_RETRY(unlink(target.c_str()))) { - if (errno != ENOENT) { - PLOG(WARNING) << "Failed to unlink " << target; - } - } LOG(DEBUG) << "Linking " << source << " to " << target; - if (TEMP_FAILURE_RETRY(symlink(source.c_str(), target.c_str()))) { - PLOG(WARNING) << "Failed to link"; - return -errno; - } + Symlink(source, target); return 0; } @@ -381,6 +388,7 @@ int VolumeManager::onUserRemoved(userid_t userId) { } int VolumeManager::onUserStarted(userid_t userId) { + 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. @@ -395,6 +403,7 @@ int VolumeManager::onUserStarted(userid_t userId) { } int VolumeManager::onUserStopped(userid_t userId) { + LOG(VERBOSE) << "onUserStopped: " << userId; mStartedUsers.erase(userId); return 0; } @@ -421,7 +430,30 @@ int VolumeManager::setPrimary(const std::shared_ptr& return 0; } -int VolumeManager::remountUid(uid_t uid, const std::string& mode) { +int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { + std::string mode; + switch (mountMode) { + case VoldNativeService::REMOUNT_MODE_NONE: + mode = "none"; + break; + case VoldNativeService::REMOUNT_MODE_DEFAULT: + mode = "default"; + break; + case VoldNativeService::REMOUNT_MODE_READ: + mode = "read"; + break; + case VoldNativeService::REMOUNT_MODE_WRITE: + case VoldNativeService::REMOUNT_MODE_LEGACY: + case VoldNativeService::REMOUNT_MODE_INSTALLER: + mode = "write"; + break; + case VoldNativeService::REMOUNT_MODE_FULL: + mode = "full"; + break; + default: + PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode); + return -1; + } LOG(DEBUG) << "Remounting " << uid << " as mode " << mode; DIR* dir; @@ -522,6 +554,8 @@ int VolumeManager::remountUid(uid_t uid, const std::string& mode) { storageSource = "/mnt/runtime/read"; } else if (mode == "write") { storageSource = "/mnt/runtime/write"; + } else if (mode == "full") { + storageSource = "/mnt/runtime/full"; } else { // Sane default of no storage visible _exit(0); diff --git a/VolumeManager.h b/VolumeManager.h index e0a1bd6..9bf7599 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -95,7 +95,7 @@ class VolumeManager { int setPrimary(const std::shared_ptr& vol); - int remountUid(uid_t uid, const std::string& mode); + int remountUid(uid_t uid, int32_t remountMode); /* Reset all internal state, typically during framework boot */ int reset(); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index abcbf4a..03fe258 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -32,6 +32,9 @@ interface IVold { void onUserStarted(int userId); 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 +99,11 @@ interface IVold { 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(); @@ -146,6 +154,9 @@ interface IVold { const int REMOUNT_MODE_DEFAULT = 1; const int REMOUNT_MODE_READ = 2; const int REMOUNT_MODE_WRITE = 3; + const int REMOUNT_MODE_LEGACY = 4; + const int REMOUNT_MODE_INSTALLER = 5; + const int REMOUNT_MODE_FULL = 6; const int VOLUME_STATE_UNMOUNTED = 0; const int VOLUME_STATE_CHECKING = 1; diff --git a/main.cpp b/main.cpp index accaa01..7555276 100644 --- a/main.cpp +++ b/main.cpp @@ -54,7 +54,7 @@ using android::fs_mgr::ReadDefaultFstab; 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 f933982..552fe2f 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -16,9 +16,10 @@ #include "EmulatedVolume.h" #include "Utils.h" +#include "VolumeManager.h" -#include #include +#include #include #include #include @@ -89,6 +90,7 @@ status_t EmulatedVolume::doMount() { "-w", "-G", "-i", + "-o", mRawPath.c_str(), label.c_str(), NULL)) { diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 1339eb3..0a6b351 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -21,6 +21,7 @@ #include "fs/Vfat.h" #include +#include #include #include #include @@ -34,6 +35,7 @@ #include #include +using android::base::GetBoolProperty; using android::base::StringPrintf; namespace android { diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index b04dd70..ffc7900 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -35,7 +35,7 @@ namespace vold { VolumeBase::VolumeBase(Type type) : mType(type), mMountFlags(0), - mMountUserId(-1), + mMountUserId(USER_UNKNOWN), mCreated(false), mState(State::kUnmounted), mSilent(false) {} @@ -219,11 +219,7 @@ status_t VolumeBase::mount() { setState(State::kChecking); status_t res = doMount(); - if (res == OK) { - setState(State::kMounted); - } else { - setState(State::kUnmountable); - } + setState(res == OK ? State::kMounted : State::kUnmountable); return res; } @@ -267,5 +263,10 @@ status_t VolumeBase::doFormat(const std::string& fsType) { return -ENOTSUP; } +std::ostream& VolumeBase::operator<<(std::ostream& stream) const { + return stream << " VolumeBase{id=" << mId << ",mountFlags=" << mMountFlags + << ",mountUserId=" << mMountUserId << "}"; +} + } // namespace vold } // namespace android diff --git a/model/VolumeBase.h b/model/VolumeBase.h index 28802d4..53eeb6f 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -27,6 +27,8 @@ #include #include +static constexpr userid_t USER_UNKNOWN = ((userid_t)-1); + namespace android { namespace vold { @@ -97,12 +99,16 @@ class VolumeBase { std::shared_ptr 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); diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp index a7c5e3d..a620edd 100644 --- a/vold_prepare_subdirs.cpp +++ b/vold_prepare_subdirs.cpp @@ -134,6 +134,10 @@ static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int fla if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, vendor_de_path + "/fpdata")) { return false; } + auto facedata_path = vendor_de_path + "/facedata"; + if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, facedata_path)) { + return false; + } } if (flags & android::os::IVold::STORAGE_FLAG_CE) { auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id); @@ -149,6 +153,11 @@ static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int fla system_ce_path + "/backup_stage")) { return false; } + auto vendor_ce_path = android::vold::BuildDataVendorCePath(user_id); + auto facedata_path = vendor_ce_path + "/facedata"; + if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, facedata_path)) { + return false; + } } } return true;