am a36a43b3: am c200d20e: am dfc30ae3: Merge "Command to move private app data between volumes."

* commit 'a36a43b354b248cef9407de42fb6b87e1c7085f6':
  Command to move private app data between volumes.
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 2171f4d..6dec7f6 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -12,7 +12,10 @@
 LOCAL_MODULE_TAGS := eng tests
 LOCAL_SRC_FILES := $(common_src_files)
 LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SHARED_LIBRARIES := libbase
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    liblogwrap \
+
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 LOCAL_CLANG := true
 include $(BUILD_STATIC_LIBRARY)
@@ -30,6 +33,7 @@
     libbase \
     libcutils \
     liblog \
+    liblogwrap \
     libselinux \
 
 LOCAL_STATIC_LIBRARIES := libdiskusage
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 32a03f4..de6fd96 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -16,15 +16,18 @@
 
 #include "installd.h"
 
+#include <base/stringprintf.h>
+#include <base/logging.h>
+#include <cutils/sched_policy.h>
+#include <diskusage/dirsize.h>
+#include <logwrap/logwrap.h>
+#include <system/thread_defs.h>
+#include <selinux/android.h>
+
 #include <inttypes.h>
 #include <sys/capability.h>
 #include <sys/file.h>
-#include <cutils/sched_policy.h>
-#include <diskusage/dirsize.h>
-#include <selinux/android.h>
-#include <system/thread_defs.h>
-#include <base/stringprintf.h>
-#include <base/logging.h>
+#include <unistd.h>
 
 using android::base::StringPrintf;
 
@@ -38,6 +41,8 @@
 dir_rec_t android_mnt_expand_dir;
 dir_rec_array_t android_system_dirs;
 
+static const char* kCpPath = "/system/bin/cp";
+
 int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
 {
     if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
@@ -172,6 +177,80 @@
     return 0;
 }
 
+int move_user_data(const char *from_uuid, const char *to_uuid,
+        const char *package_name, appid_t appid, const char* seinfo) {
+    std::vector<userid_t> users = get_known_users(from_uuid);
+
+    // Copy package private data for all known users
+    for (auto user : users) {
+        std::string from(create_package_data_path(from_uuid, package_name, user));
+        std::string to(create_package_data_path(to_uuid, package_name, user));
+        std::string to_user(create_data_user_path(to_uuid, user));
+
+        // Data source may not exist for all users; that's okay
+        if (access(from.c_str(), F_OK) != 0) {
+            LOG(INFO) << "Missing source " << from;
+            continue;
+        }
+
+        std::string user_path(create_data_user_path(to_uuid, user));
+        if (fs_prepare_dir(user_path.c_str(), 0771, AID_SYSTEM, AID_SYSTEM) != 0) {
+            LOG(ERROR) << "Failed to prepare user target " << user_path;
+            goto fail;
+        }
+
+        uid_t uid = multiuser_get_uid(user, appid);
+        if (make_user_data(to_uuid, package_name, uid, user, seinfo) != 0) {
+            LOG(ERROR) << "Failed to create package target " << to;
+            goto fail;
+        }
+
+        char *argv[] = {
+            (char*) kCpPath,
+            (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+            (char*) "-p", /* preserve timestamps, ownership, and permissions */
+            (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+            (char*) "-P", /* Do not follow symlinks [default] */
+            (char*) "-d", /* don't dereference symlinks */
+            (char*) from.c_str(),
+            (char*) to_user.c_str()
+        };
+
+        LOG(DEBUG) << "Copying " << from << " to " << to;
+        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+
+        if (rc != 0) {
+            LOG(ERROR) << "Failed copying " << from << " to " << to
+                    << ": status " << rc;
+            goto fail;
+        }
+
+        if (restorecon_data(to_uuid, package_name, seinfo, uid) != 0) {
+            LOG(ERROR) << "Failed to restorecon " << to;
+            goto fail;
+        }
+    }
+
+    // Copy successful, so delete old data
+    for (auto user : users) {
+        std::string from(create_package_data_path(from_uuid, package_name, user));
+        if (delete_dir_contents(from.c_str(), 1, NULL) != 0) {
+            LOG(WARNING) << "Failed to delete " << from;
+        }
+    }
+    return 0;
+
+fail:
+    // Nuke everything we might have already copied
+    for (auto user : users) {
+        std::string to(create_package_data_path(to_uuid, package_name, user));
+        if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            LOG(WARNING) << "Failed to rollback " << to;
+        }
+    }
+    return -1;
+}
+
 int make_user_config(userid_t userid)
 {
     if (ensure_config_user_dirs(userid) == -1) {
@@ -1592,7 +1671,7 @@
             continue;
         }
 
-        std::string pkgdir(StringPrintf("%s/%s/%s", userdir.c_str(), user, pkgName));
+        std::string pkgdir(StringPrintf("%s%s/%s", userdir.c_str(), user, pkgName));
         if (stat(pkgdir.c_str(), &s) < 0) {
             continue;
         }
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 0f035d0..3a86181 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -14,14 +14,15 @@
 ** limitations under the License.
 */
 
+#include "installd.h"
+
+#include <base/logging.h>
+
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <selinux/android.h>
 #include <selinux/avc.h>
 
-#include "installd.h"
-
-
 #define BUFFER_MAX    1024  /* input buffer for commands */
 #define TOKEN_MAX     16    /* max number of arguments in buffer */
 #define REPLY_MAX     256   /* largest reply allowed */
@@ -123,6 +124,12 @@
     return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
 }
 
+static int do_mv_user_data(char **arg, char reply[REPLY_MAX] __unused)
+{
+    // from_uuid, to_uuid, pkgname, appid, seinfo
+    return move_user_data(parse_null(arg[0]), parse_null(arg[1]), arg[2], atoi(arg[3]), arg[4]);
+}
+
 static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused)
 {
     return make_user_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4]);
@@ -193,6 +200,7 @@
     { "rmcodecache",          3, do_rm_code_cache },
     { "getsize",              8, do_get_size },
     { "rmuserdata",           3, do_rm_user_data },
+    { "mvuserdata",           5, do_mv_user_data },
     { "movefiles",            0, do_movefiles },
     { "linklib",              4, do_linklib },
     { "mkuserdata",           5, do_mk_user_data },
@@ -621,46 +629,6 @@
     return res;
 }
 
-static void drop_privileges() {
-    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
-        ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
-        exit(1);
-    }
-
-    if (setgid(AID_INSTALL) < 0) {
-        ALOGE("setgid() can't drop privileges; exiting.\n");
-        exit(1);
-    }
-
-    if (setuid(AID_INSTALL) < 0) {
-        ALOGE("setuid() can't drop privileges; exiting.\n");
-        exit(1);
-    }
-
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata[2];
-    memset(&capheader, 0, sizeof(capheader));
-    memset(&capdata, 0, sizeof(capdata));
-    capheader.version = _LINUX_CAPABILITY_VERSION_3;
-    capheader.pid = 0;
-
-    capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
-    capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted        |= CAP_TO_MASK(CAP_CHOWN);
-    capdata[CAP_TO_INDEX(CAP_SETUID)].permitted       |= CAP_TO_MASK(CAP_SETUID);
-    capdata[CAP_TO_INDEX(CAP_SETGID)].permitted       |= CAP_TO_MASK(CAP_SETGID);
-    capdata[CAP_TO_INDEX(CAP_FOWNER)].permitted       |= CAP_TO_MASK(CAP_FOWNER);
-
-    capdata[0].effective = capdata[0].permitted;
-    capdata[1].effective = capdata[1].permitted;
-    capdata[0].inheritable = 0;
-    capdata[1].inheritable = 0;
-
-    if (capset(&capheader, &capdata[0]) < 0) {
-        ALOGE("capset failed: %s\n", strerror(errno));
-        exit(1);
-    }
-}
-
 static int log_callback(int type, const char *fmt, ...) {
     va_list ap;
     int priority;
@@ -682,13 +650,16 @@
     return 0;
 }
 
-int main(const int argc __unused, const char *argv[] __unused) {
+int main(const int argc __unused, char *argv[]) {
     char buf[BUFFER_MAX];
     struct sockaddr addr;
     socklen_t alen;
     int lsocket, s;
     int selinux_enabled = (is_selinux_enabled() > 0);
 
+    setenv("ANDROID_LOG_TAGS", "*:v", 1);
+    android::base::InitLogging(argv);
+
     ALOGI("installd firing up\n");
 
     union selinux_callback cb;
@@ -710,8 +681,6 @@
         exit(1);
     }
 
-    drop_privileges();
-
     lsocket = android_get_control_socket(SOCKET_PATH);
     if (lsocket < 0) {
         ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 395d0ea..f31bf4f 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <string>
+#include <vector>
 
 #include <cutils/fs.h>
 #include <cutils/sockets.h>
@@ -89,6 +90,8 @@
 #define DEXOPT_PATCHOAT_NEEDED       2
 #define DEXOPT_SELF_PATCHOAT_NEEDED  3
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
 /* data structures */
 
 typedef struct {
@@ -154,6 +157,8 @@
 
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
 
+std::vector<userid_t> get_known_users(const char* volume_uuid);
+
 int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
 
 int create_move_path(char path[PKG_PATH_MAX],
@@ -214,7 +219,10 @@
 int renamepkg(const char *oldpkgname, const char *newpkgname);
 int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid);
 int delete_user_data(const char *uuid, const char *pkgname, userid_t userid);
-int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo);
+int make_user_data(const char *uuid, const char *pkgname, uid_t uid,
+        userid_t userid, const char* seinfo);
+int move_user_data(const char* from_uuid, const char *to_uuid,
+        const char *package_name, appid_t appid, const char* seinfo);
 int make_user_config(userid_t userid);
 int delete_user(const char *uuid, userid_t userid);
 int delete_cache(const char *uuid, const char *pkgname, userid_t userid);
@@ -238,3 +246,5 @@
 int rm_package_dir(const char* apk_path);
 int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
                             const char *instruction_set);
+int move_package_dir(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+                            const char *instruction_set);
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index e10116e..ba411cd 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -99,6 +99,38 @@
     return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
 }
 
+std::vector<userid_t> get_known_users(const char* volume_uuid) {
+    std::vector<userid_t> users;
+
+    // We always have an owner
+    users.push_back(0);
+
+    std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
+    DIR* dir = opendir(path.c_str());
+    if (dir == NULL) {
+        // Unable to discover other users, but at least return owner
+        PLOG(ERROR) << "Failed to opendir " << path;
+        return users;
+    }
+
+    struct dirent* ent;
+    while ((ent = readdir(dir))) {
+        if (ent->d_type != DT_DIR) {
+            continue;
+        }
+
+        char* end;
+        userid_t user = strtol(ent->d_name, &end, 10);
+        if (*end == '\0' && user != 0) {
+            LOG(DEBUG) << "Found valid user " << user;
+            users.push_back(user);
+        }
+    }
+    closedir(dir);
+
+    return users;
+}
+
 /**
  * Create the path name for config for a certain userid.
  * Returns 0 on success, and -1 on failure.