Setup Android/, Android/data and Android/obb dirs correctly.
Normally sdcardfs takes care of setting up these directories on-demand, for example when an app requests its private data directory to be created. On devices without sdcardfs however, we ourselves need to make sure to setup the UID/GID of these directories correctly. Introduce a new PrepareAndroidDirs() function which sets the dirs up correctly. On devices without sdcardfs, that means: Path UID GID mode /Android media_rw media_rw 771 /Android/data media_rw ext_data_rw 771 /Android/obb media_rw ext_obb_rw 771 Bug: 146419093 Test: wipe Android/, reboot, with and without sdcardfs, verify contents Change-Id: I3a879089422c7fc449b6a3e6f1c4b386b86687a4
This commit is contained in:
parent
bff86152e5
commit
62a4b279ab
7 changed files with 106 additions and 22 deletions
28
Utils.cpp
28
Utils.cpp
|
@ -134,7 +134,7 @@ int SetQuotaProjectId(std::string path, long projectId) {
|
|||
return ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
|
||||
}
|
||||
|
||||
int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) {
|
||||
int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) {
|
||||
int ret = 0;
|
||||
if (!StartsWith(path, root)) {
|
||||
return -1;
|
||||
|
@ -1164,5 +1164,31 @@ status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_pat
|
|||
return result;
|
||||
}
|
||||
|
||||
status_t PrepareAndroidDirs(const std::string& volumeRoot) {
|
||||
std::string androidDir = volumeRoot + kAndroidDir;
|
||||
std::string androidDataDir = volumeRoot + kAppDataDir;
|
||||
std::string androidObbDir = volumeRoot + kAppObbDir;
|
||||
|
||||
bool useSdcardFs = IsFilesystemSupported("sdcardfs");
|
||||
|
||||
if (fs_prepare_dir(androidDir.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
|
||||
PLOG(ERROR) << "Failed to create " << androidDir;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
gid_t dataGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_DATA_RW;
|
||||
if (fs_prepare_dir(androidDataDir.c_str(), 0771, AID_MEDIA_RW, dataGid) != 0) {
|
||||
PLOG(ERROR) << "Failed to create " << androidDataDir;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
gid_t obbGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_OBB_RW;
|
||||
if (fs_prepare_dir(androidObbDir.c_str(), 0771, AID_MEDIA_RW, obbGid) != 0) {
|
||||
PLOG(ERROR) << "Failed to create " << androidObbDir;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
|
10
Utils.h
10
Utils.h
|
@ -36,6 +36,11 @@ namespace vold {
|
|||
|
||||
static const char* kPropFuse = "persist.sys.fuse";
|
||||
|
||||
static const char* kAndroidDir = "/Android/";
|
||||
static const char* kAppDataDir = "/Android/data/";
|
||||
static const char* kAppMediaDir = "/Android/media/";
|
||||
static const char* kAppObbDir = "/Android/obb/";
|
||||
|
||||
/* SELinux contexts used depending on the block device type */
|
||||
extern security_context_t sBlkidContext;
|
||||
extern security_context_t sBlkidUntrustedContext;
|
||||
|
@ -52,8 +57,10 @@ int SetQuotaProjectId(std::string path, long projectId);
|
|||
/*
|
||||
* Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'.
|
||||
* 'path' must start with 'root'
|
||||
* ONLY for use with app-specific data directories on external storage!
|
||||
* (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.)
|
||||
*/
|
||||
int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid);
|
||||
int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
/* fs_prepare_dir wrapper that creates with SELinux context */
|
||||
status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
|
||||
|
@ -164,6 +171,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path,
|
|||
status_t UnmountUserFuse(userid_t userId, const std::string& absolute_lower_path,
|
||||
const std::string& relative_upper_path);
|
||||
|
||||
status_t PrepareAndroidDirs(const std::string& volumeRoot);
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
||||
|
|
|
@ -81,7 +81,9 @@ using android::vold::BindMount;
|
|||
using android::vold::CreateDir;
|
||||
using android::vold::DeleteDirContents;
|
||||
using android::vold::DeleteDirContentsAndDir;
|
||||
using android::vold::PrepareDirsFromRoot;
|
||||
using android::vold::IsFilesystemSupported;
|
||||
using android::vold::PrepareAndroidDirs;
|
||||
using android::vold::PrepareAppDirsFromRoot;
|
||||
using android::vold::PrivateVolume;
|
||||
using android::vold::Symlink;
|
||||
using android::vold::Unlink;
|
||||
|
@ -822,6 +824,29 @@ int VolumeManager::unmountAll() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static gid_t getAppDirGid(const std::string& appDir) {
|
||||
// Create app-specific dirs with the correct UID/GID
|
||||
gid_t gid = AID_MEDIA_RW;
|
||||
if (!IsFilesystemSupported("sdcardfs")) {
|
||||
if (appDir == android::vold::kAppDataDir) {
|
||||
gid = AID_EXT_DATA_RW;
|
||||
} else if (appDir == android::vold::kAppObbDir) {
|
||||
gid = AID_EXT_OBB_RW;
|
||||
} else if (appDir == android::vold::kAppMediaDir) {
|
||||
gid = AID_MEDIA_RW;
|
||||
} else {
|
||||
gid = AID_MEDIA_RW;
|
||||
}
|
||||
}
|
||||
|
||||
return gid;
|
||||
}
|
||||
|
||||
static bool isValidAppDirRoot(const std::string& appDirRoot) {
|
||||
return appDirRoot == android::vold::kAppDataDir || appDirRoot == android::vold::kAppMediaDir ||
|
||||
appDirRoot == android::vold::kAppObbDir;
|
||||
}
|
||||
|
||||
int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot,
|
||||
int32_t appUid) {
|
||||
// Only offer to create directories for paths managed by vold
|
||||
|
@ -868,14 +893,25 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi
|
|||
const std::string lowerAppDirRoot =
|
||||
volume->getInternalPath() + appDirRoot.substr(volume->getPath().length());
|
||||
|
||||
// First create the root which holds app dirs, if needed.
|
||||
int ret = PrepareDirsFromRoot(lowerAppDirRoot, volume->getInternalPath(), 0771, AID_MEDIA_RW,
|
||||
AID_MEDIA_RW);
|
||||
// Do some sanity checking on the app dir (relative from root)
|
||||
const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0
|
||||
|
||||
// eg, if lowerAppDirRoot = /data/media/0/Android/data, this is /Android/data
|
||||
const std::string relativeAppRoot = lowerAppDirRoot.substr(volumeRoot.length());
|
||||
if (!isValidAppDirRoot(relativeAppRoot)) {
|
||||
LOG(ERROR) << path << " is not a valid application directory.";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Make sure the Android/ directories exist and are setup correctly
|
||||
int ret = PrepareAndroidDirs(volumeRoot);
|
||||
if (ret != 0) {
|
||||
LOG(ERROR) << "Failed to prepare Android/ directories.";
|
||||
return ret;
|
||||
}
|
||||
// Then, create app-specific dirs with the correct UID/GID
|
||||
return PrepareDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, AID_MEDIA_RW);
|
||||
|
||||
gid_t gid = getAppDirGid(relativeAppRoot);
|
||||
return PrepareAppDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, gid);
|
||||
}
|
||||
|
||||
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
|
||||
|
|
|
@ -73,17 +73,8 @@ std::string EmulatedVolume::getLabel() {
|
|||
}
|
||||
}
|
||||
|
||||
// Creates a bind mount from source to target, creating the source (!) directory
|
||||
// if not yet present.
|
||||
// Creates a bind mount from source to target
|
||||
static status_t doFuseBindMount(const std::string& source, const std::string& target) {
|
||||
if (access(source.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(source.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) {
|
||||
PLOG(ERROR) << "Failed to create " << source;
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
LOG(INFO) << "Bind mounting " << source << " on " << target;
|
||||
auto status = BindMount(source, target);
|
||||
if (status != OK) {
|
||||
|
@ -232,11 +223,19 @@ status_t EmulatedVolume::doMount() {
|
|||
LOG(INFO) << "Mounting emulated fuse volume";
|
||||
android::base::unique_fd fd;
|
||||
int user_id = getMountUserId();
|
||||
int result = MountUserFuse(user_id, getInternalPath(), label, &fd);
|
||||
auto volumeRoot = getRootPath();
|
||||
|
||||
if (result != 0) {
|
||||
// Make sure Android/ dirs exist for bind mounting
|
||||
status_t res = PrepareAndroidDirs(volumeRoot);
|
||||
if (res != OK) {
|
||||
LOG(ERROR) << "Failed to prepare Android/ directories";
|
||||
return res;
|
||||
}
|
||||
|
||||
res = MountUserFuse(user_id, getInternalPath(), label, &fd);
|
||||
if (res != 0) {
|
||||
PLOG(ERROR) << "Failed to mount emulated fuse volume";
|
||||
return -result;
|
||||
return res;
|
||||
}
|
||||
|
||||
mFuseMounted = true;
|
||||
|
@ -252,7 +251,7 @@ status_t EmulatedVolume::doMount() {
|
|||
}
|
||||
|
||||
// Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path.
|
||||
status_t res = mountFuseBindMounts();
|
||||
res = mountFuseBindMounts();
|
||||
if (res != OK) {
|
||||
fd.reset();
|
||||
doUnmount();
|
||||
|
@ -317,5 +316,12 @@ status_t EmulatedVolume::doUnmount() {
|
|||
return OK;
|
||||
}
|
||||
|
||||
std::string EmulatedVolume::getRootPath() const {
|
||||
int user_id = getMountUserId();
|
||||
std::string volumeRoot = StringPrintf("%s/%d", getInternalPath().c_str(), user_id);
|
||||
|
||||
return volumeRoot;
|
||||
}
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
|
|
@ -40,6 +40,7 @@ class EmulatedVolume : public VolumeBase {
|
|||
explicit EmulatedVolume(const std::string& rawPath, int userId);
|
||||
EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, int userId);
|
||||
virtual ~EmulatedVolume();
|
||||
std::string getRootPath() const override;
|
||||
|
||||
protected:
|
||||
status_t doMount() override;
|
||||
|
|
|
@ -274,6 +274,11 @@ status_t VolumeBase::doFormat(const std::string& fsType) {
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
std::string VolumeBase::getRootPath() const {
|
||||
// Usually the same as the internal path, except for emulated volumes.
|
||||
return getInternalPath();
|
||||
}
|
||||
|
||||
std::ostream& VolumeBase::operator<<(std::ostream& stream) const {
|
||||
return stream << " VolumeBase{id=" << mId << ",mountFlags=" << mMountFlags
|
||||
<< ",mountUserId=" << mMountUserId << "}";
|
||||
|
|
|
@ -110,6 +110,8 @@ class VolumeBase {
|
|||
status_t unmount();
|
||||
status_t format(const std::string& fsType);
|
||||
|
||||
virtual std::string getRootPath() const;
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream) const;
|
||||
|
||||
protected:
|
||||
|
|
Loading…
Reference in a new issue