Bind mount Android/ directory in FUSE.

For apps seeing the FUSE filesystem, we want to bind-mount the Android/
directory to the lower filesystem. The main reason for this is game
performance - Android/ contains both OBBs and app-private external data,
and both are heavily accessed during game startup. This is a pretty
straightforward bind-mount on top of /mnt/user.

Bug: 137890172
Test: Running the following:
df /storge/emulated/0 ==> /dev/fuse (FUSE)
df /storage/emulated/0/Android ==> /data/media (sdcardfs)
Test: atest AdoptableHostTest

Change-Id: Ic17a5751b5a94846ee565ff935644a078044ab06
gugelfrei
Martijn Coenen 5 years ago
parent 6f5802e160
commit 5700261e5a

@ -1076,6 +1076,7 @@ status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_pat
if (status != android::OK) {
LOG(ERROR) << "Failed to unmount " << pass_through_path;
}
rmdir(pass_through_path.c_str());
LOG(INFO) << "Unmounting fuse path " << fuse_path;
android::status_t result = ForceUnmount(fuse_path);
@ -1089,8 +1090,10 @@ status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_pat
PLOG(ERROR) << "Failed to unmount with MNT_DETACH " << fuse_path;
return -errno;
}
return android::OK;
result = android::OK;
}
rmdir(fuse_path.c_str());
return result;
}

@ -69,6 +69,46 @@ std::string EmulatedVolume::getLabel() {
}
}
static status_t mountFuseBindMounts(int userId, const std::string& label) {
// TODO(b/134706060) we don't actually want to mount the "write" view by
// default, since it gives write access to all OBB dirs.
std::string androidSource(
StringPrintf("/mnt/runtime/write/%s/%d/Android", label.c_str(), userId));
std::string androidTarget(
StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
if (access(androidSource.c_str(), F_OK) != 0) {
// Android path may not exist yet if users has just been created; create it on
// the lower fs.
if (fs_prepare_dir(androidSource.c_str(), 0771, AID_ROOT, AID_ROOT) != 0) {
PLOG(ERROR) << "Failed to create " << androidSource;
return -errno;
}
}
LOG(INFO) << "Bind mounting " << androidSource << " on " << androidTarget;
auto status = BindMount(androidSource, androidTarget);
if (status != OK) {
return status;
}
LOG(INFO) << "Bind mounted " << androidSource << " on " << androidTarget;
return OK;
}
static status_t unmountFuseBindMounts(int userId, const std::string& label) {
std::string androidTarget(
StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId));
LOG(INFO) << "Unmounting " << androidTarget;
auto status = UnmountTree(androidTarget);
if (status != OK) {
return status;
}
LOG(INFO) << "Unmounted " << androidTarget;
return OK;
}
status_t EmulatedVolume::doMount() {
std::string label = getLabel();
bool isVisible = getMountFlags() & MountFlags::kVisible;
@ -159,6 +199,9 @@ status_t EmulatedVolume::doMount() {
return -EIO;
}
}
// Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
return mountFuseBindMounts(user_id, label);
}
return OK;
@ -171,20 +214,18 @@ status_t EmulatedVolume::doUnmount() {
// error code and might cause broken behaviour in applications.
KillProcessesUsingPath(getPath());
int userId = getMountUserId();
if (mFuseMounted) {
std::string label = getLabel();
// Ignoring unmount return status because we do want to try to unmount
// the rest cleanly.
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(getMountUserId(), getInternalPath(), label) != OK) {
unmountFuseBindMounts(userId, label);
if (UnmountUserFuse(userId, getInternalPath(), label) != OK) {
PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume";
return -errno;
}
rmdir(fuse_path.c_str());
rmdir(pass_through_path.c_str());
mFuseMounted = false;
}
if (getMountUserId() != 0) {

@ -269,13 +269,6 @@ status_t PublicVolume::doUnmount() {
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()));
rmdir(fuse_path.c_str());
rmdir(pass_through_path.c_str());
mFuseMounted = false;
}

Loading…
Cancel
Save