Use sdcardfs for pass-through mounts.
The pass-through mount is used by MediaProvider to access external storage. Previously, it was the raw filesystem (eg ext4/f2fs); the problem with that is that the permissions on that filesystem don't allow MediaProvider to access all the files it needs to - in particular directories under Android/ To solve this problem, we can have the pass-through mount sit on top of sdcardfs instead of the raw filesystem. This means we need to mount sdcardfs even in case we're using FUSE, but we already needed to do this anyway for other performance reasons. Bug: 135341433 Test: atest AdoptableHostTest Change-Id: I893d5e5076c5096d2d55212f643c9a857242e964
This commit is contained in:
parent
9072cef152
commit
6f5802e160
6 changed files with 128 additions and 115 deletions
31
Utils.cpp
31
Utils.cpp
|
@ -995,16 +995,11 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
|
|||
std::string pass_through_path(
|
||||
StringPrintf("%s/%s", pre_pass_through_path.c_str(), relative_upper_path.c_str()));
|
||||
|
||||
// Force 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::status_t result = UnmountUserFuse(pass_through_path, fuse_path);
|
||||
if (result != android::OK) {
|
||||
return -1;
|
||||
}
|
||||
std::string sdcardfs_path(
|
||||
StringPrintf("/mnt/runtime/full/%s", relative_upper_path.c_str()));
|
||||
|
||||
// Create directories.
|
||||
result = PrepareDir(pre_fuse_path, 0700, AID_ROOT, AID_ROOT);
|
||||
auto result = PrepareDir(pre_fuse_path, 0700, AID_ROOT, AID_ROOT);
|
||||
if (result != android::OK) {
|
||||
PLOG(ERROR) << "Failed to prepare directory " << pre_fuse_path;
|
||||
return -1;
|
||||
|
@ -1063,14 +1058,26 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
|
|||
PLOG(ERROR) << "Failed to mount " << fuse_path;
|
||||
return -errno;
|
||||
}
|
||||
LOG(INFO) << "Bind mounting to " << absolute_lower_path;
|
||||
return BindMount(absolute_lower_path, pass_through_path);
|
||||
|
||||
LOG(INFO) << "Bind mounting " << sdcardfs_path << " to " << pass_through_path;
|
||||
return BindMount(sdcardfs_path, pass_through_path);
|
||||
}
|
||||
|
||||
status_t UnmountUserFuse(const std::string& pass_through_path, const std::string& fuse_path) {
|
||||
status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
|
||||
const std::string& relative_upper_path) {
|
||||
std::string fuse_path(StringPrintf("/mnt/user/%d/%s", user_id, relative_upper_path.c_str()));
|
||||
std::string pass_through_path(
|
||||
StringPrintf("/mnt/pass_through/%d/%s", user_id, relative_upper_path.c_str()));
|
||||
|
||||
// Best effort unmount pass_through path
|
||||
sSleepOnUnmount = false;
|
||||
ForceUnmount(pass_through_path);
|
||||
LOG(INFO) << "Unmounting pass_through_path " << pass_through_path;
|
||||
auto status = ForceUnmount(pass_through_path);
|
||||
if (status != android::OK) {
|
||||
LOG(ERROR) << "Failed to unmount " << pass_through_path;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Unmounting fuse path " << fuse_path;
|
||||
android::status_t result = ForceUnmount(fuse_path);
|
||||
sSleepOnUnmount = true;
|
||||
if (result != android::OK) {
|
||||
|
|
3
Utils.h
3
Utils.h
|
@ -154,7 +154,8 @@ bool writeStringToFile(const std::string& payload, const std::string& filename);
|
|||
status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
|
||||
const std::string& relative_upper_path, android::base::unique_fd* fuse_fd);
|
||||
|
||||
status_t UnmountUserFuse(const std::string& pass_through_path, const std::string& fuse_path);
|
||||
status_t UnmountUserFuse(userid_t userId, const std::string& absolute_lower_path,
|
||||
const std::string& relative_upper_path);
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
|
|
@ -59,13 +59,19 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s
|
|||
|
||||
EmulatedVolume::~EmulatedVolume() {}
|
||||
|
||||
status_t EmulatedVolume::doMount() {
|
||||
std::string EmulatedVolume::getLabel() {
|
||||
// We could have migrated storage to an adopted private volume, so always
|
||||
// call primary storage "emulated" to avoid media rescans.
|
||||
std::string label = mLabel;
|
||||
if (getMountFlags() & MountFlags::kPrimary) {
|
||||
label = "emulated";
|
||||
return "emulated";
|
||||
} else {
|
||||
return mLabel;
|
||||
}
|
||||
}
|
||||
|
||||
status_t EmulatedVolume::doMount() {
|
||||
std::string label = getLabel();
|
||||
bool isVisible = getMountFlags() & MountFlags::kVisible;
|
||||
|
||||
mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str());
|
||||
mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", label.c_str());
|
||||
|
@ -87,7 +93,53 @@ status_t EmulatedVolume::doMount() {
|
|||
|
||||
bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
|
||||
|
||||
if (isFuse) {
|
||||
// Mount sdcardfs regardless of FUSE, since we need it to bind-mount on top of the
|
||||
// FUSE volume for various reasons.
|
||||
if (getMountUserId() == 0) {
|
||||
LOG(INFO) << "Executing sdcardfs";
|
||||
int sdcardFsPid;
|
||||
if (!(sdcardFsPid = fork())) {
|
||||
// clang-format off
|
||||
if (execl(kSdcardFsPath, kSdcardFsPath,
|
||||
"-u", "1023", // AID_MEDIA_RW
|
||||
"-g", "1023", // AID_MEDIA_RW
|
||||
"-m",
|
||||
"-w",
|
||||
"-G",
|
||||
"-i",
|
||||
"-o",
|
||||
mRawPath.c_str(),
|
||||
label.c_str(),
|
||||
NULL)) {
|
||||
// clang-format on
|
||||
PLOG(ERROR) << "Failed to exec";
|
||||
}
|
||||
|
||||
LOG(ERROR) << "sdcardfs exiting";
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if (sdcardFsPid == -1) {
|
||||
PLOG(ERROR) << getId() << " failed to fork";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
while (before == GetDevice(mSdcardFsFull)) {
|
||||
LOG(DEBUG) << "Waiting for sdcardfs to spin up...";
|
||||
usleep(50000); // 50ms
|
||||
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
if (nanoseconds_to_milliseconds(now - start) > 5000) {
|
||||
LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up";
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
/* sdcardfs will have exited already. The filesystem will still be running */
|
||||
TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0));
|
||||
sdcardFsPid = 0;
|
||||
}
|
||||
if (isFuse && isVisible) {
|
||||
LOG(INFO) << "Mounting emulated fuse volume";
|
||||
android::base::unique_fd fd;
|
||||
int user_id = getMountUserId();
|
||||
|
@ -98,6 +150,7 @@ status_t EmulatedVolume::doMount() {
|
|||
return -result;
|
||||
}
|
||||
|
||||
mFuseMounted = true;
|
||||
auto callback = getMountCallback();
|
||||
if (callback) {
|
||||
bool is_ready = false;
|
||||
|
@ -106,57 +159,8 @@ status_t EmulatedVolume::doMount() {
|
|||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
} else if (getMountUserId() != 0) {
|
||||
// For sdcardfs, only mount for user 0, since user 0 will always be running
|
||||
// and the paths don't change for different users. Trying to double mount
|
||||
// will cause sepolicy to scream since sdcardfs prevents 'mounton'
|
||||
return OK;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Executing sdcardfs";
|
||||
int sdcardFsPid;
|
||||
if (!(sdcardFsPid = fork())) {
|
||||
// clang-format off
|
||||
if (execl(kSdcardFsPath, kSdcardFsPath,
|
||||
"-u", "1023", // AID_MEDIA_RW
|
||||
"-g", "1023", // AID_MEDIA_RW
|
||||
"-m",
|
||||
"-w",
|
||||
"-G",
|
||||
"-i",
|
||||
"-o",
|
||||
mRawPath.c_str(),
|
||||
label.c_str(),
|
||||
NULL)) {
|
||||
// clang-format on
|
||||
PLOG(ERROR) << "Failed to exec";
|
||||
}
|
||||
|
||||
LOG(ERROR) << "sdcardfs exiting";
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if (sdcardFsPid == -1) {
|
||||
PLOG(ERROR) << getId() << " failed to fork";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
while (before == GetDevice(mSdcardFsFull)) {
|
||||
LOG(DEBUG) << "Waiting for sdcardfs to spin up...";
|
||||
usleep(50000); // 50ms
|
||||
|
||||
nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
if (nanoseconds_to_milliseconds(now - start) > 5000) {
|
||||
LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up";
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
/* sdcardfs will have exited already. The filesystem will still be running */
|
||||
TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -167,27 +171,23 @@ status_t EmulatedVolume::doUnmount() {
|
|||
// error code and might cause broken behaviour in applications.
|
||||
KillProcessesUsingPath(getPath());
|
||||
|
||||
bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
|
||||
if (isFuse) {
|
||||
// We could have migrated storage to an adopted private volume, so always
|
||||
// call primary storage "emulated" to avoid media rescans.
|
||||
std::string label = mLabel;
|
||||
if (getMountFlags() & MountFlags::kPrimary) {
|
||||
label = "emulated";
|
||||
}
|
||||
if (mFuseMounted) {
|
||||
std::string label = getLabel();
|
||||
|
||||
std::string fuse_path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str()));
|
||||
std::string pass_through_path(
|
||||
StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), label.c_str()));
|
||||
if (UnmountUserFuse(pass_through_path, fuse_path) != OK) {
|
||||
if (UnmountUserFuse(getMountUserId(), getInternalPath(), label) != OK) {
|
||||
PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
rmdir(fuse_path.c_str());
|
||||
rmdir(pass_through_path.c_str());
|
||||
return OK;
|
||||
} else if (getMountUserId() != 0) {
|
||||
|
||||
mFuseMounted = false;
|
||||
}
|
||||
if (getMountUserId() != 0) {
|
||||
// For sdcardfs, only unmount for user 0, since user 0 will always be running
|
||||
// and the paths don't change for different users.
|
||||
return OK;
|
||||
|
|
|
@ -46,6 +46,7 @@ class EmulatedVolume : public VolumeBase {
|
|||
status_t doUnmount() override;
|
||||
|
||||
private:
|
||||
std::string getLabel();
|
||||
std::string mRawPath;
|
||||
std::string mLabel;
|
||||
|
||||
|
@ -54,6 +55,9 @@ class EmulatedVolume : public VolumeBase {
|
|||
std::string mSdcardFsWrite;
|
||||
std::string mSdcardFsFull;
|
||||
|
||||
/* Whether we mounted FUSE for this volume */
|
||||
bool mFuseMounted;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(EmulatedVolume);
|
||||
};
|
||||
|
||||
|
|
|
@ -95,6 +95,7 @@ status_t PublicVolume::doDestroy() {
|
|||
}
|
||||
|
||||
status_t PublicVolume::doMount() {
|
||||
bool isVisible = getMountFlags() & MountFlags::kVisible;
|
||||
readMetadata();
|
||||
|
||||
if (mFsType == "vfat" && vfat::IsSupported()) {
|
||||
|
@ -126,7 +127,7 @@ status_t PublicVolume::doMount() {
|
|||
mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", stableName.c_str());
|
||||
|
||||
setInternalPath(mRawPath);
|
||||
if (getMountFlags() & MountFlags::kVisible) {
|
||||
if (isVisible) {
|
||||
setPath(StringPrintf("/storage/%s", stableName.c_str()));
|
||||
} else {
|
||||
setPath(mRawPath);
|
||||
|
@ -154,7 +155,7 @@ status_t PublicVolume::doMount() {
|
|||
initAsecStage();
|
||||
}
|
||||
|
||||
if (!(getMountFlags() & MountFlags::kVisible)) {
|
||||
if (!isVisible) {
|
||||
// Not visible to apps, so no need to spin up sdcardfs or FUSE
|
||||
return OK;
|
||||
}
|
||||
|
@ -169,30 +170,6 @@ status_t PublicVolume::doMount() {
|
|||
|
||||
dev_t before = GetDevice(mSdcardFsFull);
|
||||
|
||||
bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
|
||||
if (isFuse) {
|
||||
LOG(INFO) << "Mounting public fuse volume";
|
||||
android::base::unique_fd fd;
|
||||
int user_id = getMountUserId();
|
||||
int result = MountUserFuse(user_id, getInternalPath(), stableName, &fd);
|
||||
|
||||
if (result != 0) {
|
||||
LOG(ERROR) << "Failed to mount public fuse volume";
|
||||
return -result;
|
||||
}
|
||||
|
||||
auto callback = getMountCallback();
|
||||
if (callback) {
|
||||
bool is_ready = false;
|
||||
callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready);
|
||||
if (!is_ready) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int sdcardFsPid;
|
||||
if (!(sdcardFsPid = fork())) {
|
||||
if (getMountFlags() & MountFlags::kPrimary) {
|
||||
|
@ -245,6 +222,31 @@ status_t PublicVolume::doMount() {
|
|||
/* sdcardfs will have exited already. The filesystem will still be running */
|
||||
TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0));
|
||||
|
||||
bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
|
||||
if (isFuse) {
|
||||
// We need to mount FUSE *after* sdcardfs, since the FUSE daemon may depend
|
||||
// on sdcardfs being up.
|
||||
LOG(INFO) << "Mounting public fuse volume";
|
||||
android::base::unique_fd fd;
|
||||
int user_id = getMountUserId();
|
||||
int result = MountUserFuse(user_id, getInternalPath(), stableName, &fd);
|
||||
|
||||
if (result != 0) {
|
||||
LOG(ERROR) << "Failed to mount public fuse volume";
|
||||
return -result;
|
||||
}
|
||||
|
||||
mFuseMounted = true;
|
||||
auto callback = getMountCallback();
|
||||
if (callback) {
|
||||
bool is_ready = false;
|
||||
callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready);
|
||||
if (!is_ready) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -255,30 +257,26 @@ status_t PublicVolume::doUnmount() {
|
|||
// error code and might cause broken behaviour in applications.
|
||||
KillProcessesUsingPath(getPath());
|
||||
|
||||
bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false);
|
||||
if (isFuse) {
|
||||
if (mFuseMounted) {
|
||||
// Use UUID as stable name, if available
|
||||
std::string stableName = getId();
|
||||
if (!mFsUuid.empty()) {
|
||||
stableName = mFsUuid;
|
||||
}
|
||||
|
||||
if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) {
|
||||
PLOG(INFO) << "UnmountUserFuse failed on public fuse volume";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
std::string fuse_path(
|
||||
StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str()));
|
||||
std::string pass_through_path(
|
||||
StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), stableName.c_str()));
|
||||
if (UnmountUserFuse(pass_through_path, fuse_path) != OK) {
|
||||
PLOG(INFO) << "UnmountUserFuse failed on public fuse volume";
|
||||
return -errno;
|
||||
}
|
||||
ForceUnmount(kAsecPath);
|
||||
ForceUnmount(mRawPath);
|
||||
|
||||
rmdir(fuse_path.c_str());
|
||||
rmdir(pass_through_path.c_str());
|
||||
rmdir(mRawPath.c_str());
|
||||
mRawPath.clear();
|
||||
return OK;
|
||||
|
||||
mFuseMounted = false;
|
||||
}
|
||||
|
||||
ForceUnmount(kAsecPath);
|
||||
|
|
|
@ -65,6 +65,9 @@ class PublicVolume : public VolumeBase {
|
|||
std::string mSdcardFsWrite;
|
||||
std::string mSdcardFsFull;
|
||||
|
||||
/* Whether we mounted FUSE for this volume */
|
||||
bool mFuseMounted;
|
||||
|
||||
/* Filesystem type */
|
||||
std::string mFsType;
|
||||
/* Filesystem UUID */
|
||||
|
|
Loading…
Reference in a new issue