Shared OBB storage across users.
To avoid downloading large OBB files separately for each user,
provide a shared view of /sdcard/Android/obb to all apps. Added
upgrade step to migrate the owners existing OBB files to become
the default view.
Bug: 7008879
Change-Id: I199321552fa7d4b97d5ed7fc3b3bc41f23618601
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index d51004a..d559639 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -333,19 +333,16 @@
int initialize_directories() {
int res = -1;
- int version = 0;
- FILE* file;
// Read current filesystem layout version to handle upgrade paths
char version_path[PATH_MAX];
- if (snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path) > PATH_MAX) {
- return -1;
+ snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
+
+ int oldVersion;
+ if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
+ oldVersion = 0;
}
- file = fopen(version_path, "r");
- if (file != NULL) {
- fscanf(file, "%d", &version);
- fclose(file);
- }
+ int version = oldVersion;
// /data/user
char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
@@ -376,16 +373,12 @@
}
}
- // /data/media/0
- char owner_media_dir[PATH_MAX];
- create_persona_media_path(owner_media_dir, 0);
-
if (version == 0) {
// Introducing multi-user, so migrate /data/media contents into /data/media/0
- ALOGD("Migrating /data/media for multi-user");
+ ALOGD("Upgrading /data/media for multi-user");
// Ensure /data/media
- if (ensure_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+ if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
goto fail;
}
@@ -402,10 +395,14 @@
}
// Create /data/media again
- if (ensure_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+ if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
goto fail;
}
+ // /data/media/0
+ char owner_media_dir[PATH_MAX];
+ snprintf(owner_media_dir, PATH_MAX, "%s0", android_media_dir.path);
+
// Move any owner data into place
if (access(media_tmp_dir, F_OK) == 0) {
if (rename(media_tmp_dir, owner_media_dir) == -1) {
@@ -433,8 +430,7 @@
// /data/media/<user_id>
snprintf(user_media_dir, PATH_MAX, "%s%s", android_media_dir.path, name);
- if (ensure_dir(user_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
- ALOGE("Failed to ensure %s: %s", user_media_dir, strerror(errno));
+ if (fs_prepare_dir(user_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
goto fail;
}
}
@@ -445,20 +441,44 @@
version = 1;
}
- // Ensure /data/media/0 is always ready
- if (ensure_dir(owner_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+ // /data/media/obb
+ char media_obb_dir[PATH_MAX];
+ snprintf(media_obb_dir, PATH_MAX, "%sobb", android_media_dir.path);
+
+ if (version == 1) {
+ // Introducing /data/media/obb for sharing OBB across users; migrate
+ // any existing OBB files from owner.
+ ALOGD("Upgrading to shared /data/media/obb");
+
+ // /data/media/0/Android/obb
+ char owner_obb_path[PATH_MAX];
+ snprintf(owner_obb_path, PATH_MAX, "%s0/Android/obb", android_media_dir.path);
+
+ // Only move if target doesn't already exist
+ if (access(media_obb_dir, F_OK) != 0 && access(owner_obb_path, F_OK) == 0) {
+ if (rename(owner_obb_path, media_obb_dir) == -1) {
+ ALOGE("Failed to move OBB from owner: %s", strerror(errno));
+ goto fail;
+ }
+ }
+
+ version = 2;
+ }
+
+ if (ensure_media_user_dirs(0) == -1) {
+ ALOGE("Failed to setup media for user 0");
+ goto fail;
+ }
+ if (fs_prepare_dir(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
goto fail;
}
- // Persist our current version
- file = fopen(version_path, "w");
- if (file != NULL) {
- fprintf(file, "%d", version);
- fsync(fileno(file));
- fclose(file);
- } else {
- ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
- goto fail;
+ // Persist layout version if changed
+ if (version != oldVersion) {
+ if (fs_write_atomic_int(version_path, version) == -1) {
+ ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
+ goto fail;
+ }
}
// Success!