Add fixupAppDir() API.
This can be used to fixup application directories in case they have been
created by some other entity besides vold; the main use case for this
API right now is OBB directories, which can be created by installers
outside of vold; on devices without sdcardfs, such directories and the
files contained therein are not setup correctly. This API will make sure
everything is setup the way it needs to be setup.
Bug: 146419093
Test: inspect OBB dir after install
Change-Id: I2e35b7ac2992dbb21cc950e53651ffc07cfca907
diff --git a/Android.bp b/Android.bp
index a420078..676c958 100644
--- a/Android.bp
+++ b/Android.bp
@@ -167,6 +167,7 @@
],
whole_static_libs: [
"com.android.sysprop.apex",
+ "libc++fs"
],
}
diff --git a/Utils.cpp b/Utils.cpp
index 35839ac..9f9b357 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -47,6 +47,7 @@
#include <sys/xattr.h>
#include <unistd.h>
+#include <filesystem>
#include <list>
#include <mutex>
#include <regex>
@@ -228,7 +229,40 @@
return ret;
}
-int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid) {
+static int FixupAppDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid, long projectId) {
+ namespace fs = std::filesystem;
+
+ // Setup the directory itself correctly
+ int ret = PrepareDirWithProjectId(path, mode, uid, gid, projectId);
+ if (ret != OK) {
+ return ret;
+ }
+
+ // Fixup all of its file entries
+ for (const auto& itEntry : fs::directory_iterator(path)) {
+ ret = lchown(itEntry.path().c_str(), uid, gid);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = chmod(itEntry.path().c_str(), mode);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (!IsFilesystemSupported("sdcardfs")) {
+ ret = SetQuotaProjectId(itEntry.path(), projectId);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+ }
+
+ return OK;
+}
+
+int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
+ bool fixupExisting) {
long projectId;
size_t pos;
int ret = 0;
@@ -302,7 +336,15 @@
} else {
projectId = uid - AID_APP_START + AID_EXT_GID_START;
}
- ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
+
+ if (fixupExisting && access(pathToCreate.c_str(), F_OK) == 0) {
+ // Fixup all files in this existing directory with the correct UID/GID
+ // and project ID.
+ ret = FixupAppDir(pathToCreate, mode, uid, gid, projectId);
+ } else {
+ ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
+ }
+
if (ret != 0) {
return ret;
}
diff --git a/Utils.h b/Utils.h
index 54b8dd8..21abc4d 100644
--- a/Utils.h
+++ b/Utils.h
@@ -57,7 +57,8 @@
* ONLY for use with app-specific data directories on external storage!
* (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.)
*/
-int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid);
+int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
+ bool fixupExisting);
/* 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);
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
index 6aa9670..08b4661 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -466,6 +466,14 @@
return translate(VolumeManager::Instance()->setupAppDir(path, appUid));
}
+binder::Status VoldNativeService::fixupAppDir(const std::string& path, int32_t appUid) {
+ ENFORCE_SYSTEM_OR_ROOT;
+ CHECK_ARGUMENT_PATH(path);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->fixupAppDir(path, appUid));
+}
+
binder::Status VoldNativeService::createObb(const std::string& sourcePath,
const std::string& sourceKey, int32_t ownerGid,
std::string* _aidl_return) {
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 6d00d2d..e04c259 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -66,6 +66,7 @@
binder::Status remountUid(int32_t uid, int32_t remountMode);
binder::Status setupAppDir(const std::string& path, int32_t appUid);
+ binder::Status fixupAppDir(const std::string& path, int32_t appUid);
binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey,
int32_t ownerGid, std::string* _aidl_return);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 6f15846..f7b36bf 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -814,7 +814,7 @@
return 0;
}
-int VolumeManager::setupAppDir(const std::string& path, int32_t appUid) {
+int VolumeManager::setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly) {
// Only offer to create directories for paths managed by vold
if (!StartsWith(path, "/storage/")) {
LOG(ERROR) << "Failed to find mounted volume for " << path;
@@ -859,8 +859,21 @@
const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0
+ if (fixupExistingOnly && (access(lowerPath.c_str(), F_OK) != 0)) {
+ // Nothing to fixup
+ return OK;
+ }
+
// Create the app paths we need from the root
- return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid);
+ return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid, fixupExistingOnly);
+}
+
+int VolumeManager::fixupAppDir(const std::string& path, int32_t appUid) {
+ if (IsFilesystemSupported("sdcardfs")) {
+ //sdcardfs magically does this for us
+ return OK;
+ }
+ return setupAppDir(path, appUid, true /* fixupExistingOnly */);
}
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
diff --git a/VolumeManager.h b/VolumeManager.h
index 765349d..afea54e 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -157,12 +157,23 @@
* requirements of the underlying filesystem and are of no concern to the
* caller.
*
+ * If fixupExistingOnly is set, we make sure to fixup any existing dirs and
+ * files in the passed in path, but only if that path exists; if it doesn't
+ * exist, this function doesn't create them.
+ *
* Validates that given paths are absolute and that they contain no relative
* "." or ".." paths or symlinks. Last path segment is treated as filename
* and ignored, unless the path ends with "/". Also ensures that path
* belongs to a volume managed by vold.
*/
- int setupAppDir(const std::string& path, int32_t appUid);
+ int setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly = false);
+
+ /**
+ * Fixes up an existing application directory, as if it was created with
+ * setupAppDir() above. This includes fixing up the UID/GID, permissions and
+ * project IDs of the contained files and directories.
+ */
+ int fixupAppDir(const std::string& path, int32_t appUid);
int createObb(const std::string& path, const std::string& key, int32_t ownerGid,
std::string* outVolId);
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index 78598b3..f1ada6c 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -55,6 +55,7 @@
void remountUid(int uid, int remountMode);
void setupAppDir(@utf8InCpp String path, int appUid);
+ void fixupAppDir(@utf8InCpp String path, int appUid);
@utf8InCpp String createObb(@utf8InCpp String sourcePath, @utf8InCpp String sourceKey,
int ownerGid);