diff --git a/VolumeManager.cpp b/VolumeManager.cpp index e29b920..d47d9f3 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -68,6 +68,7 @@ #include "model/EmulatedVolume.h" #include "model/ObbVolume.h" #include "model/PrivateVolume.h" +#include "model/PublicVolume.h" #include "model/StubVolume.h" using android::OK; @@ -88,6 +89,7 @@ using android::vold::IsVirtioBlkDevice; using android::vold::PrepareAndroidDirs; using android::vold::PrepareAppDirFromRoot; using android::vold::PrivateVolume; +using android::vold::PublicVolume; using android::vold::Symlink; using android::vold::Unlink; using android::vold::UnmountTree; @@ -457,6 +459,31 @@ int VolumeManager::onUserStarted(userid_t userId) { if (mStartedUsers.find(userId) == mStartedUsers.end()) { createEmulatedVolumesForUser(userId); + std::list public_vols; + listVolumes(VolumeBase::Type::kPublic, public_vols); + for (const std::string& id : public_vols) { + PublicVolume* pvol = static_cast(findVolume(id).get()); + if (pvol->getState() != VolumeBase::State::kMounted) { + continue; + } + if (pvol->isVisible() == 0) { + continue; + } + userid_t mountUserId = pvol->getMountUserId(); + if (userId == mountUserId) { + // No need to bind mount for the user that owns the mount + continue; + } + if (mountUserId != VolumeManager::Instance()->getSharedStorageUser(userId)) { + // No need to bind if the user does not share storage with the mount owner + continue; + } + auto bindMountStatus = pvol->bindMountForUser(userId); + if (bindMountStatus != OK) { + LOG(ERROR) << "Bind Mounting Public Volume: " << pvol << " for user: " << userId + << "Failed. Error: " << bindMountStatus; + } + } } mStartedUsers.insert(userId); diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 034fb23..e86d002 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -257,9 +257,45 @@ status_t PublicVolume::doMount() { // See comment in model/EmulatedVolume.cpp ConfigureMaxDirtyRatioForFuse(GetFuseMountPathForUser(user_id, stableName), 40u); + auto vol_manager = VolumeManager::Instance(); + // Create bind mounts for all running users + for (userid_t started_user : vol_manager->getStartedUsers()) { + userid_t mountUserId = getMountUserId(); + if (started_user == mountUserId) { + // No need to bind mount for the user that owns the mount + continue; + } + if (mountUserId != VolumeManager::Instance()->getSharedStorageUser(started_user)) { + // No need to bind if the user does not share storage with the mount owner + continue; + } + auto bindMountStatus = bindMountForUser(started_user); + if (bindMountStatus != OK) { + LOG(ERROR) << "Bind Mounting Public Volume: " << stableName + << " for user: " << started_user << "Failed. Error: " << bindMountStatus; + } + } return OK; } +status_t PublicVolume::bindMountForUser(userid_t user_id) { + userid_t mountUserId = getMountUserId(); + std::string stableName = getId(); + if (!mFsUuid.empty()) { + stableName = mFsUuid; + } + + LOG(INFO) << "Bind Mounting Public Volume for user: " << user_id + << ".Mount owner: " << mountUserId; + auto sourcePath = GetFuseMountPathForUser(mountUserId, stableName); + auto destPath = GetFuseMountPathForUser(user_id, stableName); + PrepareDir(destPath, 0770, AID_ROOT, AID_MEDIA_RW); + auto mountRes = BindMount(sourcePath, destPath); + LOG(INFO) << "Mount status: " << mountRes; + + return mountRes; +} + status_t PublicVolume::doUnmount() { // Unmount the storage before we kill the FUSE process. If we kill // the FUSE process first, most file system operations will return @@ -274,6 +310,20 @@ status_t PublicVolume::doUnmount() { stableName = mFsUuid; } + // Unmount bind mounts for running users + auto vol_manager = VolumeManager::Instance(); + int user_id = getMountUserId(); + for (int started_user : vol_manager->getStartedUsers()) { + if (started_user == user_id) { + // No need to remove bind mount for the user that owns the mount + continue; + } + LOG(INFO) << "Removing Public Volume Bind Mount for: " << started_user; + auto mountPath = GetFuseMountPathForUser(started_user, stableName); + ForceUnmount(mountPath); + rmdir(mountPath.c_str()); + } + if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) { PLOG(INFO) << "UnmountUserFuse failed on public fuse volume"; return -errno; diff --git a/model/PublicVolume.h b/model/PublicVolume.h index 3156b53..ca553b0 100644 --- a/model/PublicVolume.h +++ b/model/PublicVolume.h @@ -42,6 +42,8 @@ class PublicVolume : public VolumeBase { explicit PublicVolume(dev_t device); virtual ~PublicVolume(); + status_t bindMountForUser(userid_t user_id); + protected: status_t doCreate() override; status_t doDestroy() override;