OSDN Git Service

am 6c14f0ad: Merge "Runtime resource overlay, iteration 2"
authorDianne Hackborn <hackbod@android.com>
Fri, 7 Mar 2014 02:27:06 +0000 (02:27 +0000)
committerAndroid Git Automerger <android-git-automerger@android.com>
Fri, 7 Mar 2014 02:27:06 +0000 (02:27 +0000)
* commit '6c14f0ad82be418c742e56fe586657ea0f394b05':
  Runtime resource overlay, iteration 2

cmds/installd/commands.c
cmds/installd/installd.c
cmds/installd/installd.h

index 6fed798..e4f63e2 100644 (file)
@@ -618,14 +618,11 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
     ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
 }
 
-static int wait_dexopt(pid_t pid, const char* apk_path)
+static int wait_child(pid_t pid)
 {
     int status;
     pid_t got_pid;
 
-    /*
-     * Wait for the optimization process to finish.
-     */
     while (1) {
         got_pid = waitpid(pid, &status, 0);
         if (got_pid == -1 && errno == EINTR) {
@@ -641,11 +638,8 @@ static int wait_dexopt(pid_t pid, const char* apk_path)
     }
 
     if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
-        ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
         return 0;
     } else {
-        ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
-            apk_path, status);
         return status;      /* always nonzero */
     }
 }
@@ -747,9 +741,11 @@ int dexopt(const char *apk_path, uid_t uid, int is_public)
         }
         exit(68);   /* only get here on exec failure */
     } else {
-        res = wait_dexopt(pid, apk_path);
-        if (res != 0) {
-            ALOGE("dexopt in='%s' out='%s' res=%d\n", apk_path, out_path, res);
+        res = wait_child(pid);
+        if (res == 0) {
+            ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
+        } else {
+            ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res);
             goto fail;
         }
     }
@@ -1103,3 +1099,115 @@ out:
 
     return rc;
 }
+
+static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
+{
+    static const char *IDMAP_BIN = "/system/bin/idmap";
+    static const size_t MAX_INT_LEN = 32;
+    char idmap_str[MAX_INT_LEN];
+
+    snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd);
+
+    execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL);
+    ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno));
+}
+
+// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
+// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
+static int flatten_path(const char *prefix, const char *suffix,
+        const char *overlay_path, char *idmap_path, size_t N)
+{
+    if (overlay_path == NULL || idmap_path == NULL) {
+        return -1;
+    }
+    const size_t len_overlay_path = strlen(overlay_path);
+    // will access overlay_path + 1 further below; requires absolute path
+    if (len_overlay_path < 2 || *overlay_path != '/') {
+        return -1;
+    }
+    const size_t len_idmap_root = strlen(prefix);
+    const size_t len_suffix = strlen(suffix);
+    if (SIZE_MAX - len_idmap_root < len_overlay_path ||
+            SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
+        // additions below would cause overflow
+        return -1;
+    }
+    if (N < len_idmap_root + len_overlay_path + len_suffix) {
+        return -1;
+    }
+    memset(idmap_path, 0, N);
+    snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
+    char *ch = idmap_path + len_idmap_root;
+    while (*ch != '\0') {
+        if (*ch == '/') {
+            *ch = '@';
+        }
+        ++ch;
+    }
+    return 0;
+}
+
+int idmap(const char *target_apk, const char *overlay_apk, uid_t uid)
+{
+    ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
+
+    int idmap_fd = -1;
+    char idmap_path[PATH_MAX];
+
+    if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
+                idmap_path, sizeof(idmap_path)) == -1) {
+        ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
+        goto fail;
+    }
+
+    unlink(idmap_path);
+    idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
+    if (idmap_fd < 0) {
+        ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno));
+        goto fail;
+    }
+    if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) {
+        ALOGE("idmap cannot chown '%s'\n", idmap_path);
+        goto fail;
+    }
+    if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
+        ALOGE("idmap cannot chmod '%s'\n", idmap_path);
+        goto fail;
+    }
+
+    pid_t pid;
+    pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        if (setgid(uid) != 0) {
+            ALOGE("setgid(%d) failed during idmap\n", uid);
+            exit(1);
+        }
+        if (setuid(uid) != 0) {
+            ALOGE("setuid(%d) failed during idmap\n", uid);
+            exit(1);
+        }
+        if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
+            ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno));
+            exit(1);
+        }
+
+        run_idmap(target_apk, overlay_apk, idmap_fd);
+        exit(1); /* only if exec call to idmap failed */
+    } else {
+        int status = wait_child(pid);
+        if (status != 0) {
+            ALOGE("idmap failed, status=0x%04x\n", status);
+            goto fail;
+        }
+    }
+
+    close(idmap_fd);
+    return 0;
+fail:
+    if (idmap_fd >= 0) {
+        close(idmap_fd);
+        unlink(idmap_path);
+    }
+    return -1;
+}
index 0c80dac..9c66f2d 100644 (file)
@@ -124,6 +124,11 @@ static int do_linklib(char **arg, char reply[REPLY_MAX])
     return linklib(arg[0], arg[1], atoi(arg[2]));
 }
 
+static int do_idmap(char **arg, char reply[REPLY_MAX])
+{
+    return idmap(arg[0], arg[1], atoi(arg[2]));
+}
+
 struct cmdinfo {
     const char *name;
     unsigned numargs;
@@ -147,6 +152,7 @@ struct cmdinfo cmds[] = {
     { "linklib",              3, do_linklib },
     { "mkuserdata",           4, do_mk_user_data },
     { "rmuser",               1, do_rm_user },
+    { "idmap",                3, do_idmap },
 };
 
 static int readx(int s, void *_buf, int count)
@@ -515,6 +521,7 @@ static void drop_privileges() {
     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;
index 9ca2f86..cab5cb7 100644 (file)
@@ -75,6 +75,9 @@
 
 #define UPDATE_COMMANDS_DIR_PREFIX  "/system/etc/updatecmds/"
 
+#define IDMAP_PREFIX           "/data/resource-cache/"
+#define IDMAP_SUFFIX           "@idmap"
+
 #define PKG_NAME_MAX  128   /* largest allowed package name */
 #define PKG_PATH_MAX  256   /* max size of any path we use */
 
@@ -207,3 +210,4 @@ int free_cache(int64_t free_size);
 int dexopt(const char *apk_path, uid_t uid, int is_public);
 int movefiles();
 int linklib(const char* target, const char* source, int userId);
+int idmap(const char *target_path, const char *overlay_path, uid_t uid);