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/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index d1b7f8c..96232c4 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -13,7 +13,7 @@
 # user interface (like displaying progress and allowing user to enter details).
 # It's typically triggered by the power button or developer settings.
 service bugreportplus /system/bin/dumpstate -d -B -P -z \
-        -o /data/data/com.android.shell/files/bugreports/bugreport
+        -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
     class main
     disabled
     oneshot
@@ -25,7 +25,7 @@
 # it will disable vibrations, screenshot taking and will not track progress or
 # allow user to enter any details
 service bugreportremote /system/bin/dumpstate -d -q -B -R -z \
-        -o /data/data/com.android.shell/files/bugreports/remote/bugreport
+        -o /data/user_de/0/com.android.shell/files/bugreports/remote/bugreport
     class main
     disabled
     oneshot
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) {
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
index 53a789f..fe03397 100644
--- a/cmds/installd/commands.h
+++ b/cmds/installd/commands.h
@@ -32,6 +32,7 @@
         appid_t appid, const char* seinfo, int target_sdk_version);
 int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags,
         appid_t appid, const char* seinfo);
+int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
 int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
 int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
 
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index c0ae5b7..63290a9 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -201,6 +201,11 @@
     return restorecon_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4]), arg[5]);
 }
 
+static int do_migrate_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
+    /* const char *uuid, const char *pkgname, userid_t userid, int flags */
+    return migrate_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
+}
+
 static int do_clear_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
     /* const char *uuid, const char *pkgname, userid_t userid, int flags */
     return clear_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
@@ -342,6 +347,7 @@
 
     { "create_app_data",      7, do_create_app_data },
     { "restorecon_app_data",  6, do_restorecon_app_data },
+    { "migrate_app_data",     4, do_migrate_app_data },
     { "clear_app_data",       4, do_clear_app_data },
     { "destroy_app_data",     4, do_destroy_app_data },
     { "move_complete_app",    7, do_move_complete_app },