Migrate default app data on non-FBE devices.
When a system app requests "forceDeviceEncrypted" they expect their
default app storage to point at a consistent location regardless of
device FBE support. So when booting upgraded non-FBE devices, we
may need to migrate any data from CE to DE. Note that on non-FBE
devices these are just semantic locations with identical protection.
This migration *only* works for non-FBE devices; changing
forceDeviceEncrypted flags on an FBE device always requires a full
data wipe.
Bug: 26668510
Change-Id: I8bd5b8ba882e6bd067c0381041b27c35d6e47788
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index df80eb6..e54407c 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -23,6 +23,8 @@
#include <sys/file.h>
#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
#include <unistd.h>
#include <android-base/stringprintf.h>
@@ -49,7 +51,8 @@
namespace android {
namespace installd {
-static const char* kCpPath = "/system/bin/cp";
+static constexpr const char* kCpPath = "/system/bin/cp";
+static constexpr const char* kXattrDefault = "user.default";
#define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
@@ -84,6 +87,44 @@
return 0;
}
+int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
+ // This method only exists to upgrade system apps that have requested
+ // forceDeviceEncrypted, so their default storage always lives in a
+ // consistent location. This only works on non-FBE devices, since we
+ // never want to risk exposing data on a device with real CE/DE storage.
+
+ auto ce_path = create_data_user_package_path(uuid, userid, pkgname);
+ auto de_path = create_data_user_de_package_path(uuid, userid, pkgname);
+
+ // If neither directory is marked as default, assume CE is default
+ if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1
+ && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) {
+ if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) {
+ PLOG(ERROR) << "Failed to mark default storage " << ce_path;
+ return -1;
+ }
+ }
+
+ // Migrate default data location if needed
+ auto target = (flags & FLAG_STORAGE_DE) ? de_path : ce_path;
+ auto source = (flags & FLAG_STORAGE_DE) ? ce_path : de_path;
+
+ if (getxattr(target.c_str(), kXattrDefault, nullptr, 0) == -1) {
+ LOG(WARNING) << "Requested default storage " << target
+ << " is not active; migrating from " << source;
+ if (delete_dir_contents_and_dir(target) != 0) {
+ PLOG(ERROR) << "Failed to delete";
+ return -1;
+ }
+ if (rename(source.c_str(), target.c_str()) != 0) {
+ PLOG(ERROR) << "Failed to rename";
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
std::string suffix = "";
if (flags & FLAG_CLEAR_CACHE_ONLY) {