summaryrefslogtreecommitdiffstats
path: root/cmds/installd/commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/installd/commands.c')
-rw-r--r--cmds/installd/commands.c156
1 files changed, 153 insertions, 3 deletions
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 41f070c..8d571dc 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -405,6 +405,7 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src)
char *tmp;
int srclen;
int dstlen;
+ char dexopt_data_only[PROPERTY_VALUE_MAX];
srclen = strlen(src);
@@ -417,7 +418,15 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src)
return -1;
}
- dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
+ const char *cache_path = DALVIK_CACHE_PREFIX;
+ if (!strncmp(src, "/system", 7)) {
+ property_get("dalvik.vm.dexopt-data-only", dexopt_data_only, "");
+ if (strcmp(dexopt_data_only, "1") != 0) {
+ cache_path = DALVIK_SYSTEM_CACHE_PREFIX;
+ }
+ }
+
+ dstlen = srclen + strlen(cache_path) +
strlen(DALVIK_CACHE_POSTFIX) + 1;
if (dstlen > PKG_PATH_MAX) {
@@ -425,11 +434,11 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src)
}
sprintf(path,"%s%s%s",
- DALVIK_CACHE_PREFIX,
+ cache_path,
src + 1, /* skip the leading / */
DALVIK_CACHE_POSTFIX);
- for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
+ for(tmp = path + strlen(cache_path); *tmp; tmp++) {
if (*tmp == '/') {
*tmp = '@';
}
@@ -454,6 +463,77 @@ static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
LOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
}
+static void run_check_zipalign(const char* input_file)
+{
+ static const char* ZIPALIGN_BIN = "/system/bin/zipalign";
+ execl(ZIPALIGN_BIN, ZIPALIGN_BIN, "-c", "4", input_file, (char*) NULL);
+}
+
+static void run_zipalign(const char* input_file, const char* output_file)
+{
+ static const char* ZIPALIGN_BIN = "/system/bin/zipalign";
+ execl(ZIPALIGN_BIN, ZIPALIGN_BIN, "4", input_file, output_file, (char*) NULL);
+ LOGE("execl(%s) failed: %s\n", ZIPALIGN_BIN, strerror(errno));
+}
+
+static int wait_check_zipalign(pid_t pid, const char* apk_path)
+{
+ int status;
+ pid_t got_pid;
+
+ while (1) {
+ got_pid = waitpid(pid, &status, 0);
+ if (got_pid == -1 && errno == EINTR) {
+ printf("waitpid interrupted, retrying\n");
+ } else {
+ break;
+ }
+ }
+
+ if (got_pid != pid) {
+ return 1;
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ LOGD("CheckZipAlign: --- END '%s' (not needed) ---\n", apk_path);
+ return 0;
+ } else {
+ LOGW("CheckZipAlign: --- END '%s' (needed) ---\n", apk_path);
+ return status;
+ }
+}
+
+static int wait_zipalign(pid_t pid, const char* apk_path)
+{
+ int status;
+ pid_t got_pid;
+
+ /*
+ * Wait for the zipalign process to finish.
+ */
+ while (1) {
+ got_pid = waitpid(pid, &status, 0);
+ if (got_pid == -1 && errno == EINTR) {
+ printf("waitpid interrupted, retrying\n");
+ } else {
+ break;
+ }
+ }
+ if (got_pid != pid) {
+ LOGW("waitpid failed: wanted %d, got %d: %s\n",
+ (int) pid, (int) got_pid, strerror(errno));
+ return 1;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ LOGD("ZipAlign: --- END '%s' (success) ---\n", apk_path);
+ return 0;
+ } else {
+ LOGW("ZipAlign: --- END '%s' --- status=0x%04x, process failed\n",
+ apk_path, status);
+ return status; /* always nonzero */
+ }
+}
+
static int wait_dexopt(pid_t pid, const char* apk_path)
{
int status;
@@ -486,6 +566,72 @@ static int wait_dexopt(pid_t pid, const char* apk_path)
}
}
+int zipalign(const char *apk_path, uid_t uid, int is_public)
+{
+ char za_path[PKG_PATH_MAX];
+ struct utimbuf ut;
+ struct stat za_stat, apk_stat;
+ int res;
+
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) {
+ run_check_zipalign(apk_path);
+ exit(67);
+ } else {
+ res = wait_check_zipalign(pid, apk_path);
+ if (res == 0) {
+ goto notneeded;
+ }
+ }
+
+ memset(&apk_stat, 0, sizeof(apk_stat));
+ stat(apk_path, &apk_stat);
+
+ strcpy(za_path, apk_path);
+ strcat(za_path, ".tmp");
+ LOGD("ZipAlign: --- BEGIN '%s' ---\n", apk_path);
+
+ pid = fork();
+ if (pid == 0) {
+ run_zipalign(apk_path, za_path);
+ exit(67);
+ } else {
+ res = wait_zipalign(pid, za_path);
+ if (res != 0) {
+ LOGE("zipalign failed on '%s' res = %d\n", za_path, res);
+ goto fail;
+ }
+ }
+
+ if (chown(za_path, apk_stat.st_uid, apk_stat.st_gid) < 0) {
+ LOGE("zipalign cannot chown '%s'", apk_path);
+ goto fail;
+ }
+ if (chmod(za_path, S_IRUSR|S_IWUSR|S_IRGRP |
+ (is_public ? S_IROTH : 0)) < 0) {
+ LOGE("zipalign cannot chmod '%s'\n", apk_path);
+ goto fail;
+ }
+
+ ut.actime = apk_stat.st_atime;
+ ut.modtime = apk_stat.st_mtime;
+ utime(za_path, &ut);
+
+ unlink(apk_path);
+ rename(za_path, apk_path);
+
+ return 0;
+
+notneeded:
+ return 0;
+
+fail:
+ unlink(za_path);
+ return -1;
+
+}
+
int dexopt(const char *apk_path, uid_t uid, int is_public)
{
struct utimbuf ut;
@@ -501,6 +647,10 @@ int dexopt(const char *apk_path, uid_t uid, int is_public)
if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
return -1;
}
+
+ if (strncmp(apk_path, "/system", 7) != 0) {
+ zipalign(apk_path, uid, is_public);
+ }
/* platform-specific flags affecting optimization and verification */
property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");