From ea0c03875ff3e212681e0ccc2ef75478d337db9a Mon Sep 17 00:00:00 2001 From: Clark Scheff Date: Tue, 25 Nov 2014 12:04:16 -0800 Subject: [PATCH] Themes: Port to CM13 [2/3] Themes: Forward port installd Id: I5c03bdca30d55f252d486ddac0355f41623ba8d5 Themes: Remove legacy theme support Id: I6823a6f2735f07f8e4a25a9c0f6f297577a554ab Access Themed ResTables from compiled theme apk [2/2] Before this patch the ResTable for a theme/app was created and accessed seperate from the compiled APK. Since the compiled APK has its own copy of the resources.arsc, we can just reuse the table in the APK instead Id: Ib7916eba5663db5d077d33fc02623748e8a9f10c Send target sdk version to aapt [2/2] If vector drawables are used in a theme we must have a minSdkVersion of 21 passed to aapt or else aapt will Segfault. Id: Ib5ffa6d12c91d465f3a603e03b09ab03b02715c7 Change-Id: Ie14322b7efb40b270abd3d4ca1b7c5f97bf4b5ca --- cmds/installd/commands.cpp | 209 +++++++++++++++++++++++++++++++++---- cmds/installd/installd.cpp | 16 ++- cmds/installd/installd.h | 5 +- 3 files changed, 208 insertions(+), 22 deletions(-) diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp index 7090b3677..57b8c2e4f 100644 --- a/cmds/installd/commands.cpp +++ b/cmds/installd/commands.cpp @@ -1601,43 +1601,58 @@ out: return rc; } -static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) +static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd, + uint32_t target_hash, uint32_t overlay_hash) { static const char *IDMAP_BIN = "/system/bin/idmap"; static const size_t MAX_INT_LEN = 32; char idmap_str[MAX_INT_LEN]; + char target_hash_str[MAX_INT_LEN]; + char overlay_hash_str[MAX_INT_LEN]; snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd); + snprintf(target_hash_str, sizeof(target_hash_str), "%d", target_hash); + snprintf(overlay_hash_str, sizeof(overlay_hash_str), "%d", overlay_hash); - execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL); + execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, + target_hash_str, overlay_hash_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 +/* Prints to idmap_path (prefix)/(flat_target)@(flat_overerlay)@(suffix) + * Note: "Flat" is a string with '/' changed to @ + * Example input: + * prefix: /data/resource-cache/ + * suffix: idmap + * overlay_path: /data/app/com.theme.apk + * target_path: /data/app/com.target.apk + * Example output: + * idmap_path: /data/resource-cache/data@app@com.target.apk@data@app@theme.apk@idmap + */ static int flatten_path(const char *prefix, const char *suffix, - const char *overlay_path, char *idmap_path, size_t N) + const char *overlay_path, const char *target_path, char *idmap_path, size_t N) { - if (overlay_path == NULL || idmap_path == NULL) { + if (overlay_path == NULL || idmap_path == NULL || target_path == NULL) { return -1; } + + const size_t len_target_path = strlen(target_path); + if (len_target_path < 2 || *target_path != '/') { + 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); + int len = snprintf(idmap_path, N, "%s%s%s%s", prefix, target_path + 1, overlay_path, suffix); + if (len < 0 || (size_t)len >= N) { + return -1; // error or truncated + } char *ch = idmap_path + len_idmap_root; while (*ch != '\0') { if (*ch == '/') { @@ -1648,14 +1663,15 @@ static int flatten_path(const char *prefix, const char *suffix, return 0; } -int idmap(const char *target_apk, const char *overlay_apk, uid_t uid) +int idmap(const char *target_apk, const char *overlay_apk, uid_t uid, + uint32_t target_hash, uint32_t overlay_hash) { 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, + if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, target_apk, idmap_path, sizeof(idmap_path)) == -1) { ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk); goto fail; @@ -1693,7 +1709,7 @@ int idmap(const char *target_apk, const char *overlay_apk, uid_t uid) exit(1); } - run_idmap(target_apk, overlay_apk, idmap_fd); + run_idmap(target_apk, overlay_apk, idmap_fd, target_hash, overlay_hash); exit(1); /* only if exec call to idmap failed */ } else { int status = wait_child(pid); @@ -1713,6 +1729,161 @@ fail: return -1; } +static void run_aapt(const char *source_apk, const char *internal_path, + int resapk_fd, int pkgId, int min_sdk_version, const char *common_res_path) +{ + static const char *AAPT_BIN = "/system/bin/aapt"; + static const char *MANIFEST = "/data/app/AndroidManifest.xml"; + static const char *FRAMEWORK_RES = "/system/framework/framework-res.apk"; + + static const size_t MAX_INT_LEN = 32; + char resapk_str[MAX_INT_LEN]; + char pkgId_str[MAX_INT_LEN]; + char minSdkVersion_str[MAX_INT_LEN]; + + snprintf(resapk_str, sizeof(resapk_str), "%d", resapk_fd); + snprintf(pkgId_str, sizeof(pkgId_str), "%d", pkgId); + snprintf(minSdkVersion_str, sizeof(minSdkVersion_str), "%d", min_sdk_version); + bool hasCommonResources = (common_res_path != NULL && common_res_path[0] != '\0'); + + if (hasCommonResources) { + execl(AAPT_BIN, AAPT_BIN, "package", + "--min-sdk-version", minSdkVersion_str, + "-M", MANIFEST, + "-S", source_apk, + "-X", internal_path, + "-I", FRAMEWORK_RES, + "-I", common_res_path, + "-r", resapk_str, + "-x", pkgId_str, + (char*)NULL); + } else { + execl(AAPT_BIN, AAPT_BIN, "package", + "--min-sdk-version", minSdkVersion_str, + "-M", MANIFEST, + "-S", source_apk, + "-X", internal_path, + "-I", FRAMEWORK_RES, + "-r", resapk_str, + "-x", pkgId_str, + (char*)NULL); + } + ALOGE("execl(%s) failed: %s\n", AAPT_BIN, strerror(errno)); +} + +int aapt(const char *source_apk, const char *internal_path, const char *out_restable, uid_t uid, + int pkgId, int min_sdk_version, const char *common_res_path) +{ + ALOGD("aapt source_apk=%s internal_path=%s out_restable=%s uid=%d, pkgId=%d, \ + min_sdk_version=%d, common_res_path=%s", + source_apk, internal_path, out_restable, uid, pkgId, min_sdk_version, common_res_path); + static const int PARENT_READ_PIPE = 0; + static const int CHILD_WRITE_PIPE = 1; + + int resapk_fd = -1; + char restable_path[PATH_MAX]; + char resapk_path[PATH_MAX]; + + int pipefd[2]; + pid_t pid = fork(); + + // get file descriptor for resources.arsc + snprintf(restable_path, PATH_MAX, "%s/resources.arsc", out_restable); + unlink(restable_path); + + // get file descriptor for resources.apk + snprintf(resapk_path, PATH_MAX, "%s/resources.apk", out_restable); + unlink(resapk_path); + resapk_fd = open(resapk_path, O_RDWR | O_CREAT | O_EXCL, 0644); + if (resapk_fd < 0) { + ALOGE("aapt cannot open '%s' for output: %s\n", resapk_path, strerror(errno)); + goto fail; + } + if (fchown(resapk_fd, AID_SYSTEM, uid) < 0) { + ALOGE("aapt cannot chown '%s'\n", resapk_path); + goto fail; + } + if (fchmod(resapk_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) { + ALOGE("aapt cannot chmod '%s'\n", resapk_path); + goto fail; + } + + if (pipe(pipefd) != 0) { + pipefd[0] = pipefd[1] = -1; + } + if (pid == 0) { + /* child -- drop privileges before continuing */ + if (setgid(uid) != 0) { + ALOGE("setgid(%d) failed during aapt\n", uid); + exit(1); + } + if (setuid(uid) != 0) { + ALOGE("setuid(%d) failed during aapt\n", uid); + exit(1); + } + + if (flock(resapk_fd, LOCK_EX | LOCK_NB) != 0) { + ALOGE("flock(%s) failed during aapt: %s\n", out_restable, strerror(errno)); + exit(1); + } + + if (pipefd[PARENT_READ_PIPE] > 0 && pipefd[CHILD_WRITE_PIPE] > 0) { + close(pipefd[PARENT_READ_PIPE]); // close unused read end + if (dup2(pipefd[CHILD_WRITE_PIPE], STDERR_FILENO) != STDERR_FILENO) { + pipefd[CHILD_WRITE_PIPE] = -1; + } + } + + run_aapt(source_apk, internal_path, resapk_fd, pkgId, min_sdk_version, common_res_path); + + if (pipefd[CHILD_WRITE_PIPE] > 0) { + close(pipefd[CHILD_WRITE_PIPE]); + } + exit(1); /* only if exec call to idmap failed */ + } else { + int status, i; + char buffer[1024]; + ssize_t readlen; + + if (pipefd[CHILD_WRITE_PIPE] > 0) { + close(pipefd[CHILD_WRITE_PIPE]); // close unused write end + } + + if (pipefd[PARENT_READ_PIPE] > 0) { + while ((readlen = read(pipefd[PARENT_READ_PIPE], buffer, sizeof(buffer) - 1)) > 0) { + // in case buffer has more than one string in it, replace '\0' with '\n' + for (i = 0; i < readlen; i++) { + if (buffer[i] == '\0') buffer[i] = '\n'; + } + // null terminate buffer at readlen + buffer[readlen] = '\0'; + ALOG(LOG_ERROR, "InstallTheme", "%s", buffer); + } + waitpid(pid, &status, 0); + + if (pipefd[PARENT_READ_PIPE] > 0) { + close(pipefd[PARENT_READ_PIPE]); + } + } else { + status = wait_child(pid); + } + + if (status != 0) { + ALOGE("aapt failed, status=0x%04x\n", status); + goto fail; + } + } + + close(resapk_fd); + return 0; +fail: + if (resapk_fd >= 0) { + close(resapk_fd); + unlink(resapk_path); + } + return -1; +} + int restorecon_data(const char* uuid, const char* pkgName, const char* seinfo, uid_t uid) { diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp index 13e316868..e0d9cdb5e 100644 --- a/cmds/installd/installd.cpp +++ b/cmds/installd/installd.cpp @@ -158,7 +158,17 @@ static int do_linklib(char **arg, char reply[REPLY_MAX] __unused) static int do_idmap(char **arg, char reply[REPLY_MAX] __unused) { - return idmap(arg[0], arg[1], atoi(arg[2])); + return idmap(arg[0], arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4])); +} + +static int do_aapt(char **arg, char reply[REPLY_MAX] __unused) +{ + return aapt(arg[0], arg[1], arg[2], atoi(arg[3]), atoi(arg[4]), atoi(arg[5]), ""); +} + +static int do_aapt_with_common(char **arg, char reply[REPLY_MAX] __unused) +{ + return aapt(arg[0], arg[1], arg[2], atoi(arg[3]), atoi(arg[4]), atoi(arg[5]), arg[6]); } static int do_restorecon_data(char **arg, char reply[REPLY_MAX] __attribute__((unused))) @@ -212,7 +222,9 @@ struct cmdinfo cmds[] = { { "mkuserdata", 5, do_mk_user_data }, { "mkuserconfig", 1, do_mk_user_config }, { "rmuser", 2, do_rm_user }, - { "idmap", 3, do_idmap }, + { "idmap", 5, do_idmap }, + { "aapt", 6, do_aapt }, + { "aapt_with_common", 7, do_aapt_with_common }, { "restorecondata", 4, do_restorecon_data }, { "createoatdir", 2, do_create_oat_dir }, { "rmpackagedir", 1, do_rm_package_dir }, diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index 7ec579382..5e4d918f0 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -247,7 +247,10 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName, int mark_boot_complete(const char *instruction_set); int movefiles(); int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId); -int idmap(const char *target_path, const char *overlay_path, uid_t uid); +int idmap(const char *target_path, const char *overlay_path, uid_t uid, + uint32_t target_hash, uint32_t overlay_hash); +int aapt(const char *source_apk, const char *internal_path, const char *out_restable, uid_t uid, + int pkgId, int min_sdk_version, const char *common_res_path); int restorecon_data(const char *uuid, const char* pkgName, const char* seinfo, uid_t uid); int create_oat_dir(const char* oat_dir, const char *instruction_set); int rm_package_dir(const char* apk_path);