int dexopt(const char *apk_path, uid_t uid, int is_public) { struct utimbuf ut; struct stat apk_stat, dex_stat; char dex_path[PKG_PATH_MAX]; char dexopt_flags[PROPERTY_VALUE_MAX]; char *end; int res, zip_fd=-1, odex_fd=-1; /* Before anything else: is there a .odex file? If so, we have * pre-optimized the apk and there is nothing to do here. */ if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { return -1; } /* platform-specific flags affecting optimization and verification */ property_get("dalvik.vm.dexopt-flags", dexopt_flags, ""); strcpy(dex_path, apk_path); end = strrchr(dex_path, '.'); if (end != NULL) { strcpy(end, ".odex"); if (stat(dex_path, &dex_stat) == 0) { return 0; } } if (create_cache_path(dex_path, apk_path)) { return -1; } memset(&apk_stat, 0, sizeof(apk_stat)); stat(apk_path, &apk_stat); zip_fd = open(apk_path, O_RDONLY, 0); if (zip_fd < 0) { ALOGE("dexopt cannot open '%s' for input\n", apk_path); return -1; } unlink(dex_path); odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (odex_fd < 0) { ALOGE("dexopt cannot open '%s' for output\n", dex_path); goto fail; } if (fchmod(odex_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { ALOGE("dexopt cannot chmod '%s'\n", dex_path); goto fail; } if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { ALOGE("dexopt cannot chown '%s'\n", dex_path); goto fail; } ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { ALOGE("setgid(%d) failed during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { ALOGE("setuid(%d) during dexopt\n", uid); exit(65); } // drop capabilities 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; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); exit(66); } if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); exit(67); } run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags); exit(68); /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path); if (res != 0) { ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res); goto fail; } } ut.actime = apk_stat.st_atime; ut.modtime = apk_stat.st_mtime; utime(dex_path, &ut); close(odex_fd); close(zip_fd); return 0; fail: if (odex_fd >= 0) { close(odex_fd); unlink(dex_path); } if (zip_fd >= 0) { close(zip_fd); } return -1; }
int dexopt(const char *apk_path, uid_t uid, int is_public) { struct utimbuf ut; struct stat apk_stat, dex_stat; char dex_path[PKG_PATH_MAX]; char *end; int res, zip_fd=-1, odex_fd=-1; /* Before anything else: is there a .odex file? If so, we have * pre-optimized the apk and there is nothing to do here. */ if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { return -1; } strcpy(dex_path, apk_path); end = strrchr(dex_path, '.'); if (end != NULL) { strcpy(end, ".odex"); if (stat(dex_path, &dex_stat) == 0) { return 0; } } if (create_cache_path(dex_path, apk_path)) { return -1; } memset(&apk_stat, 0, sizeof(apk_stat)); stat(apk_path, &apk_stat); zip_fd = open(apk_path, O_RDONLY, 0); if (zip_fd < 0) { LOGE("dexopt cannot open '%s' for input\n", apk_path); return -1; } unlink(dex_path); odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); if (odex_fd < 0) { LOGE("dexopt cannot open '%s' for output\n", dex_path); goto fail; } if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { LOGE("dexopt cannot chown '%s'\n", dex_path); goto fail; } if (fchmod(odex_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { LOGE("dexopt cannot chmod '%s'\n", dex_path); goto fail; } LOGD("DexInv: --- BEGIN '%s' ---\n", apk_path); pid_t pid; pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { LOGE("setgid(%d) failed during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { LOGE("setuid(%d) during dexopt\n", uid); exit(65); } if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { LOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); exit(66); } run_dexopt(zip_fd, odex_fd, apk_path); /* does not return */ exit(67); } else { res = wait_dexopt(pid, apk_path); if (res != 0) { LOGE("dexopt failed on '%s' res = %d\n", dex_path, res); goto fail; } } ut.actime = apk_stat.st_atime; ut.modtime = apk_stat.st_mtime; utime(dex_path, &ut); close(odex_fd); close(zip_fd); return 0; fail: if (odex_fd >= 0) { close(odex_fd); unlink(dex_path); } if (zip_fd >= 0) { close(zip_fd); } return -1; }