@ -22,6 +22,7 @@
# include <android-base/logging.h>
# include <android-base/properties.h>
# include <android-base/scopeguard.h>
# include <android-base/stringprintf.h>
# include <cutils/fs.h>
# include <private/android_filesystem_config.h>
@ -48,7 +49,6 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId)
mRawPath = rawPath ;
mLabel = " emulated " ;
mFuseMounted = false ;
mAndroidMounted = false ;
mUseSdcardFs = IsFilesystemSupported ( " sdcardfs " ) ;
mAppDataIsolationEnabled = base : : GetBoolProperty ( kVoldAppDataIsolationEnabled , false ) ;
}
@ -60,7 +60,6 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s
mRawPath = rawPath ;
mLabel = fsUuid ;
mFuseMounted = false ;
mAndroidMounted = false ;
mUseSdcardFs = IsFilesystemSupported ( " sdcardfs " ) ;
mAppDataIsolationEnabled = base : : GetBoolProperty ( kVoldAppDataIsolationEnabled , false ) ;
}
@ -78,22 +77,37 @@ std::string EmulatedVolume::getLabel() {
}
// Creates a bind mount from source to target
static status_t doFuseBindMount ( const std : : string & source , const std : : string & target ) {
static status_t doFuseBindMount ( const std : : string & source , const std : : string & target ,
std : : list < std : : string > & pathsToUnmount ) {
LOG ( INFO ) < < " Bind mounting " < < source < < " on " < < target ;
auto status = BindMount ( source , target ) ;
if ( status ! = OK ) {
return status ;
}
LOG ( INFO ) < < " Bind mounted " < < source < < " on " < < target ;
pathsToUnmount . push_front ( target ) ;
return OK ;
}
status_t EmulatedVolume : : mountFuseBindMounts ( ) {
CHECK ( ! mAndroidMounted ) ;
std : : string androidSource ;
std : : string label = getLabel ( ) ;
int userId = getMountUserId ( ) ;
std : : list < std : : string > pathsToUnmount ;
auto unmounter = [ & ] ( ) {
LOG ( INFO ) < < " mountFuseBindMounts() unmount scope_guard running " ;
for ( const auto & path : pathsToUnmount ) {
LOG ( INFO ) < < " Unmounting " < < path ;
auto status = UnmountTree ( path ) ;
if ( status ! = OK ) {
LOG ( INFO ) < < " Failed to unmount " < < path ;
} else {
LOG ( INFO ) < < " Unmounted " < < path ;
}
}
} ;
auto unmount_guard = android : : base : : make_scope_guard ( unmounter ) ;
if ( mUseSdcardFs ) {
androidSource = StringPrintf ( " /mnt/runtime/default/%s/%d/Android " , label . c_str ( ) , userId ) ;
@ -105,38 +119,43 @@ status_t EmulatedVolume::mountFuseBindMounts() {
// When app data isolation is enabled, obb/ will be mounted per app, otherwise we should
// bind mount the whole Android/ to speed up reading.
if ( ! mAppDataIsolationEnabled ) {
std : : string androidTarget (
StringPrintf ( " /mnt/user/%d/%s/%d/Android " , userId , label . c_str ( ) , userId ) ) ;
status = doFuseBindMount ( androidSource , androidTarget ) ;
}
std : : string androidDataSource = StringPrintf ( " %s/data " , androidSource . c_str ( ) ) ;
std : : string androidDataTarget (
StringPrintf ( " /mnt/user/%d/%s/%d/Android/data " , userId , label . c_str ( ) , userId ) ) ;
status = doFuseBindMount ( androidDataSource , androidDataTarget , pathsToUnmount ) ;
if ( status ! = OK ) {
return status ;
}
if ( status ! = OK ) {
return status ;
std : : string androidObbSource = StringPrintf ( " %s/obb " , androidSource . c_str ( ) ) ;
std : : string androidObbTarget (
StringPrintf ( " /mnt/user/%d/%s/%d/Android/obb " , userId , label . c_str ( ) , userId ) ) ;
status = doFuseBindMount ( androidObbSource , androidObbTarget , pathsToUnmount ) ;
if ( status ! = OK ) {
return status ;
}
}
mAndroidMounted = true ;
// Installers get the same view as all other apps, with the sole exception that the
// OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires
// a special bind mount, since app-private and OBB dirs share the same GID, but we
// only want to give access to the latter.
if ( ! mUseSdcardFs ) {
return OK ;
}
std : : string installerSource (
StringPrintf ( " /mnt/runtime/write/%s/%d/Android/obb " , label . c_str ( ) , userId ) ) ;
std : : string installerTarget (
StringPrintf ( " /mnt/installer/%d/%s/%d/Android/obb " , userId , label . c_str ( ) , userId ) ) ;
if ( mUseSdcardFs ) {
std : : string installerSource (
StringPrintf ( " /mnt/runtime/write/%s/%d/Android/obb " , label . c_str ( ) , userId ) ) ;
std : : string installerTarget (
StringPrintf ( " /mnt/installer/%d/%s/%d/Android/obb " , userId , label . c_str ( ) , userId ) ) ;
status = doFuseBindMount ( installerSource , installerTarget ) ;
if ( status ! = OK ) {
return status ;
status = doFuseBindMount ( installerSource , installerTarget , pathsToUnmount ) ;
if ( status ! = OK ) {
return status ;
}
}
unmount_guard . Disable ( ) ;
return OK ;
}
status_t EmulatedVolume : : unmountFuseBindMounts ( ) {
CHECK ( mAndroidMounted ) ;
std : : string label = getLabel ( ) ;
int userId = getMountUserId ( ) ;
@ -156,19 +175,54 @@ status_t EmulatedVolume::unmountFuseBindMounts() {
std : : string appObbDir ( StringPrintf ( " %s/%d/Android/obb " , getPath ( ) . c_str ( ) , userId ) ) ;
KillProcessesWithMountPrefix ( appObbDir ) ;
} else {
std : : string androidTarget (
StringPrintf ( " /mnt/user/%d/%s/%d/Android " , userId , label . c_str ( ) , userId ) ) ;
std : : string androidDataTarget (
StringPrintf ( " /mnt/user/%d/%s/%d/Android/data " , userId , label . c_str ( ) , userId ) ) ;
LOG ( INFO ) < < " Unmounting " < < androidDataTarget ;
auto status = UnmountTree ( androidDataTarget ) ;
if ( status ! = OK ) {
return status ;
}
LOG ( INFO ) < < " Unmounted " < < androidDataTarget ;
std : : string androidObbTarget (
StringPrintf ( " /mnt/user/%d/%s/%d/Android/obb " , userId , label . c_str ( ) , userId ) ) ;
LOG ( INFO ) < < " Unmounting " < < androidTarget ;
auto status = UnmountTree ( androidTarget ) ;
LOG ( INFO ) < < " Unmounting " < < android Obb Target;
status = UnmountTree ( android Obb Target) ;
if ( status ! = OK ) {
return status ;
}
LOG ( INFO ) < < " Unmounted " < < androidTarget ;
LOG ( INFO ) < < " Unmounted " < < android Obb Target;
}
return OK ;
}
status_t EmulatedVolume : : unmountSdcardFs ( ) {
if ( ! mUseSdcardFs | | 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 ;
}
ForceUnmount ( mSdcardFsDefault ) ;
ForceUnmount ( mSdcardFsRead ) ;
ForceUnmount ( mSdcardFsWrite ) ;
ForceUnmount ( mSdcardFsFull ) ;
rmdir ( mSdcardFsDefault . c_str ( ) ) ;
rmdir ( mSdcardFsRead . c_str ( ) ) ;
rmdir ( mSdcardFsWrite . c_str ( ) ) ;
rmdir ( mSdcardFsFull . c_str ( ) ) ;
mSdcardFsDefault . clear ( ) ;
mSdcardFsRead . clear ( ) ;
mSdcardFsWrite . clear ( ) ;
mSdcardFsFull . clear ( ) ;
return OK ;
}
status_t EmulatedVolume : : doMount ( ) {
std : : string label = getLabel ( ) ;
bool isVisible = getMountFlags ( ) & MountFlags : : kVisible ;
@ -239,7 +293,15 @@ status_t EmulatedVolume::doMount() {
TEMP_FAILURE_RETRY ( waitpid ( sdcardFsPid , nullptr , 0 ) ) ;
sdcardFsPid = 0 ;
}
if ( isFuse & & isVisible ) {
// Make sure we unmount sdcardfs if we bail out with an error below
auto sdcardfs_unmounter = [ & ] ( ) {
LOG ( INFO ) < < " sdcardfs_unmounter scope_guard running " ;
unmountSdcardFs ( ) ;
} ;
auto sdcardfs_guard = android : : base : : make_scope_guard ( sdcardfs_unmounter ) ;
LOG ( INFO ) < < " Mounting emulated fuse volume " ;
android : : base : : unique_fd fd ;
int user_id = getMountUserId ( ) ;
@ -259,13 +321,21 @@ status_t EmulatedVolume::doMount() {
}
mFuseMounted = true ;
auto fuse_unmounter = [ & ] ( ) {
LOG ( INFO ) < < " fuse_unmounter scope_guard running " ;
fd . reset ( ) ;
if ( UnmountUserFuse ( user_id , getInternalPath ( ) , label ) ! = OK ) {
PLOG ( INFO ) < < " UnmountUserFuse failed on emulated fuse volume " ;
}
mFuseMounted = false ;
} ;
auto fuse_guard = android : : base : : make_scope_guard ( fuse_unmounter ) ;
auto callback = getMountCallback ( ) ;
if ( callback ) {
bool is_ready = false ;
callback - > onVolumeChecking ( std : : move ( fd ) , getPath ( ) , getInternalPath ( ) , & is_ready ) ;
if ( ! is_ready ) {
fd . reset ( ) ;
doUnmount ( ) ;
return - EIO ;
}
}
@ -273,10 +343,12 @@ status_t EmulatedVolume::doMount() {
// Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
res = mountFuseBindMounts ( ) ;
if ( res ! = OK ) {
fd . reset ( ) ;
doUnmount ( ) ;
return res ;
}
return res ;
// All mounts where successful, disable scope guards
sdcardfs_guard . Disable ( ) ;
fuse_guard . Disable ( ) ;
}
return OK ;
@ -304,10 +376,8 @@ status_t EmulatedVolume::doUnmount() {
// Ignoring unmount return status because we do want to try to unmount
// the rest cleanly.
if ( mAndroidMounted ) {
unmountFuseBindMounts ( ) ;
mAndroidMounted = false ;
}
unmountFuseBindMounts ( ) ;
if ( UnmountUserFuse ( userId , getInternalPath ( ) , label ) ! = OK ) {
PLOG ( INFO ) < < " UnmountUserFuse failed on emulated fuse volume " ;
return - errno ;
@ -315,28 +385,8 @@ status_t EmulatedVolume::doUnmount() {
mFuseMounted = false ;
}
if ( getMountUserId ( ) ! = 0 | | ! mUseSdcardFs ) {
// 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 ;
}
ForceUnmount ( mSdcardFsDefault ) ;
ForceUnmount ( mSdcardFsRead ) ;
ForceUnmount ( mSdcardFsWrite ) ;
ForceUnmount ( mSdcardFsFull ) ;
rmdir ( mSdcardFsDefault . c_str ( ) ) ;
rmdir ( mSdcardFsRead . c_str ( ) ) ;
rmdir ( mSdcardFsWrite . c_str ( ) ) ;
rmdir ( mSdcardFsFull . c_str ( ) ) ;
mSdcardFsDefault . clear ( ) ;
mSdcardFsRead . clear ( ) ;
mSdcardFsWrite . clear ( ) ;
mSdcardFsFull . clear ( ) ;
return OK ;
return unmountSdcardFs ( ) ;
}
std : : string EmulatedVolume : : getRootPath ( ) const {