Loading cmds/installd/commands.cpp +139 −67 Original line number Original line Diff line number Diff line Loading @@ -671,8 +671,10 @@ static int split(char *buf, const char **argv) return count; return count; } } static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, static void run_patchoat(int input_oat_fd, int input_vdex_fd, int out_oat_fd, int out_vdex_fd, const char* output_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set) const char* input_oat_file_name, const char* input_vdex_file_name, const char* output_oat_file_name, const char* output_vdex_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set) { { static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; Loading @@ -686,35 +688,44 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/ /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/ char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN]; char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN]; char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN]; char input_vdex_fd_arg[strlen("--input-vdex-fd=") + MAX_INT_LEN]; char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN]; char output_vdex_fd_arg[strlen("--output-vdex-fd=") + MAX_INT_LEN]; const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art"; const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art"; // The caller has already gotten all the locks we need. // The caller has already gotten all the locks we need. const char* no_lock_arg = "--no-lock-output"; const char* no_lock_arg = "--no-lock-output"; sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd); sprintf(output_oat_fd_arg, "--output-oat-fd=%d", out_oat_fd); sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd); sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_oat_fd); ALOGV("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n", ALOGV("Running %s isa=%s in-oat-fd=%d (%s) in-vdex-fd=%d (%s) " PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name); "out-oat-fd=%d (%s) out-vdex-fd=%d (%s)\n", PATCHOAT_BIN, instruction_set, input_oat_fd, input_oat_file_name, input_vdex_fd, input_vdex_file_name, out_oat_fd, output_oat_file_name, out_vdex_fd, output_vdex_file_name); /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */ /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */ char* argv[7]; char* argv[9]; argv[0] = (char*) PATCHOAT_BIN; argv[0] = (char*) PATCHOAT_BIN; argv[1] = (char*) patched_image_location_arg; argv[1] = (char*) patched_image_location_arg; argv[2] = (char*) no_lock_arg; argv[2] = (char*) no_lock_arg; argv[3] = instruction_set_arg; argv[3] = instruction_set_arg; argv[4] = output_oat_fd_arg; argv[4] = input_oat_fd_arg; argv[5] = input_oat_fd_arg; argv[5] = input_vdex_fd_arg; argv[6] = NULL; argv[6] = output_oat_fd_arg; argv[7] = output_vdex_fd_arg; argv[8] = NULL; execv(PATCHOAT_BIN, (char* const *)argv); execv(PATCHOAT_BIN, (char* const *)argv); ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno)); ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno)); } } static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_file_name, static void run_dex2oat(int zip_fd, int oat_fd, int vdex_fd, int image_fd, const char* output_file_name, int swap_fd, const char *instruction_set, const char* input_file_name, const char* output_file_name, int swap_fd, const char* compiler_filter, bool vm_safe_mode, bool debuggable, bool post_bootcomplete, const char *instruction_set, const char* compiler_filter, bool vm_safe_mode, int profile_fd, const char* shared_libraries) { bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) { static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { Loading Loading @@ -795,6 +806,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN]; char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN]; char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX]; char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX]; char vdex_fd_arg[strlen("--vdex-fd=") + MAX_INT_LEN]; char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX]; char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; Loading @@ -810,6 +822,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); sprintf(zip_location_arg, "--zip-location=%s", input_file_name); sprintf(zip_location_arg, "--zip-location=%s", input_file_name); sprintf(vdex_fd_arg, "--vdex-fd=%d", vdex_fd); sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); sprintf(oat_location_arg, "--oat-location=%s", output_file_name); sprintf(oat_location_arg, "--oat-location=%s", output_file_name); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); Loading Loading @@ -872,7 +885,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); const char* argv[7 // program name, mandatory arguments and the final NULL const char* argv[8 // program name, mandatory arguments and the final NULL + (have_dex2oat_isa_variant ? 1 : 0) + (have_dex2oat_isa_variant ? 1 : 0) + (have_dex2oat_isa_features ? 1 : 0) + (have_dex2oat_isa_features ? 1 : 0) + (have_dex2oat_Xms_flag ? 2 : 0) + (have_dex2oat_Xms_flag ? 2 : 0) Loading @@ -893,6 +906,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ argv[i++] = DEX2OAT_BIN; argv[i++] = DEX2OAT_BIN; argv[i++] = zip_fd_arg; argv[i++] = zip_fd_arg; argv[i++] = zip_location_arg; argv[i++] = zip_location_arg; argv[i++] = vdex_fd_arg; argv[i++] = oat_fd_arg; argv[i++] = oat_fd_arg; argv[i++] = oat_location_arg; argv[i++] = oat_location_arg; argv[i++] = instruction_set_arg; argv[i++] = instruction_set_arg; Loading Loading @@ -1350,31 +1364,40 @@ bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string) return true; return true; } } // Translate the given oat path to an art (app image) path. An empty string static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) { // denotes an error. // A standard dalvik-cache entry. Replace ".dex" with `new_ext`. static std::string create_image_filename(const std::string& oat_path) { // A standard dalvik-cache entry. Replace ".dex" with ".art." if (EndsWith(oat_path, ".dex")) { if (EndsWith(oat_path, ".dex")) { std::string art_path = oat_path; std::string new_path = oat_path; art_path.replace(art_path.length() - strlen("dex"), strlen("dex"), "art"); new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext); CHECK(EndsWith(art_path, ".art")); CHECK(EndsWith(new_path, new_ext.c_str())); return art_path; return new_path; } } // An odex entry. Not that this may not be an extension, e.g., in the OTA // An odex entry. Not that this may not be an extension, e.g., in the OTA // case (where the base name will have an extension for the B artifact). // case (where the base name will have an extension for the B artifact). size_t odex_pos = oat_path.rfind(".odex"); size_t odex_pos = oat_path.rfind(".odex"); if (odex_pos != std::string::npos) { if (odex_pos != std::string::npos) { std::string art_path = oat_path; std::string new_path = oat_path; art_path.replace(odex_pos, strlen(".odex"), ".art"); new_path.replace(odex_pos, strlen(".odex"), new_ext); CHECK_NE(art_path.find(".art"), std::string::npos); CHECK_NE(new_path.find(new_ext), std::string::npos); return art_path; return new_path; } } // Don't know how to handle this. // Don't know how to handle this. return ""; return ""; } } // Translate the given oat path to an art (app image) path. An empty string // denotes an error. static std::string create_image_filename(const std::string& oat_path) { return replace_file_extension(oat_path, ".art"); } // Translate the given oat path to a vdex path. An empty string denotes an error. static std::string create_vdex_filename(const std::string& oat_path) { return replace_file_extension(oat_path, ".vdex"); } static bool add_extension_to_file_name(char* file_name, const char* extension) { static bool add_extension_to_file_name(char* file_name, const char* extension) { if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) { if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) { return false; return false; Loading Loading @@ -1410,7 +1433,7 @@ static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const } } static bool create_oat_out_path(const char* apk_path, const char* instruction_set, static bool create_oat_out_path(const char* apk_path, const char* instruction_set, const char* oat_dir, /*out*/ char* out_path) { const char* oat_dir, /*out*/ char* out_oat_path) { // Early best-effort check whether we can fit the the path into our buffers. // Early best-effort check whether we can fit the the path into our buffers. // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run // without a swap file, if necessary. Reference profiles file also add an extra ".prof" // without a swap file, if necessary. Reference profiles file also add an extra ".prof" Loading @@ -1425,11 +1448,11 @@ static bool create_oat_out_path(const char* apk_path, const char* instruction_se ALOGE("invalid oat_dir '%s'\n", oat_dir); ALOGE("invalid oat_dir '%s'\n", oat_dir); return false; return false; } } if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) { if (!calculate_oat_file_path(out_oat_path, oat_dir, apk_path, instruction_set)) { return false; return false; } } } else { } else { if (!create_cache_path(out_path, apk_path, instruction_set)) { if (!create_cache_path(out_oat_path, apk_path, instruction_set)) { return false; return false; } } } } Loading Loading @@ -1571,8 +1594,8 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins LOG_FATAL("dexopt flags contains unknown fields\n"); LOG_FATAL("dexopt flags contains unknown fields\n"); } } char out_path[PKG_PATH_MAX]; char out_oat_path[PKG_PATH_MAX]; if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) { if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) { return false; return false; } } Loading @@ -1591,7 +1614,7 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins break; break; case DEXOPT_SELF_PATCHOAT_NEEDED: case DEXOPT_SELF_PATCHOAT_NEEDED: input_file = out_path; input_file = out_oat_path; break; break; default: default: Loading @@ -1603,21 +1626,57 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins memset(&input_stat, 0, sizeof(input_stat)); memset(&input_stat, 0, sizeof(input_stat)); stat(input_file, &input_stat); stat(input_file, &input_stat); // Open the input file. If running dex2oat, `input_file` is the APK. If running // patchoat, it is the OAT file to be relocated. base::unique_fd input_fd(open(input_file, O_RDONLY, 0)); base::unique_fd input_fd(open(input_file, O_RDONLY, 0)); if (input_fd.get() < 0) { if (input_fd.get() < 0) { ALOGE("installd cannot open '%s' for input during dexopt\n", input_file); ALOGE("installd cannot open '%s' for input during dexopt\n", input_file); return -1; return -1; } } const std::string out_path_str(out_path); // If invoking patchoat, open the VDEX associated with the OAT too. Dex2oatFileWrapper<std::function<void ()>> out_fd( std::string in_vdex_path_str; open_output_file(out_path, /*recreate*/true, /*permissions*/0644), base::unique_fd input_vdex_fd; [out_path_str]() { unlink(out_path_str.c_str()); }); if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED if (out_fd.get() < 0) { || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_path); in_vdex_path_str = create_vdex_filename(input_file); if (in_vdex_path_str.empty()) { return -1; } input_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0)); if (input_vdex_fd.get() < 0) { ALOGE("installd cannot open '%s' for input during dexopt\n", in_vdex_path_str.c_str()); return -1; } } // Create the output OAT file. const std::string out_oat_path_str(out_oat_path); Dex2oatFileWrapper<std::function<void ()>> out_oat_fd( open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644), [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); }); if (out_oat_fd.get() < 0) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path); return -1; return -1; } } if (!set_permissions_and_ownership(out_fd.get(), is_public, uid, out_path)) { if (!set_permissions_and_ownership(out_oat_fd.get(), is_public, uid, out_oat_path)) { return -1; } // Infer the name of the output VDEX and create it. const std::string out_vdex_path_str = create_vdex_filename(out_oat_path_str); if (out_vdex_path_str.empty()) { return -1; } Dex2oatFileWrapper<std::function<void ()>> out_vdex_fd( open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644), [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); }); if (out_vdex_fd.get() < 0) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_vdex_path_str.c_str()); return -1; } if (!set_permissions_and_ownership(out_vdex_fd.get(), is_public, uid, out_vdex_path_str.c_str())) { return -1; return -1; } } Loading @@ -1626,7 +1685,7 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins if (ShouldUseSwapFileForDexopt()) { if (ShouldUseSwapFileForDexopt()) { // Make sure there really is enough space. // Make sure there really is enough space. char swap_file_name[PKG_PATH_MAX]; char swap_file_name[PKG_PATH_MAX]; strcpy(swap_file_name, out_path); strcpy(swap_file_name, out_oat_path); if (add_extension_to_file_name(swap_file_name, ".swap")) { if (add_extension_to_file_name(swap_file_name, ".swap")) { swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600)); swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600)); } } Loading @@ -1644,8 +1703,8 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins // Avoid generating an app image for extract only since it will not contain any classes. // Avoid generating an app image for extract only since it will not contain any classes. Dex2oatFileWrapper<std::function<void ()>> image_fd; Dex2oatFileWrapper<std::function<void ()>> image_fd; const std::string image_path = create_image_filename(out_path); const std::string image_path = create_image_filename(out_oat_path); if (!image_path.empty()) { if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED && !image_path.empty()) { char app_image_format[kPropertyValueMax]; char app_image_format[kPropertyValueMax]; bool have_app_image_format = bool have_app_image_format = get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; Loading Loading @@ -1690,27 +1749,32 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins drop_capabilities(uid); drop_capabilities(uid); SetDex2OatAndPatchOatScheduling(boot_complete); SetDex2OatAndPatchOatScheduling(boot_complete); if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) { if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno)); ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno)); _exit(67); _exit(67); } } if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { run_patchoat(input_fd.get(), run_patchoat(input_fd.get(), out_fd.get(), input_vdex_fd.get(), out_oat_fd.get(), out_vdex_fd.get(), input_file, input_file, out_path, in_vdex_path_str.c_str(), out_oat_path, out_vdex_path_str.c_str(), pkgname, pkgname, instruction_set); instruction_set); } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) { } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) { // Pass dex2oat the relative path to the input file. // Pass dex2oat the relative path to the input file. const char *input_file_name = get_location_from_path(input_file); const char *input_file_name = get_location_from_path(input_file); run_dex2oat(input_fd.get(), run_dex2oat(input_fd.get(), out_fd.get(), out_oat_fd.get(), out_vdex_fd.get(), image_fd.get(), image_fd.get(), input_file_name, input_file_name, out_path, out_oat_path, swap_fd.get(), swap_fd.get(), instruction_set, instruction_set, compiler_filter, compiler_filter, Loading @@ -1737,10 +1801,11 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins struct utimbuf ut; struct utimbuf ut; ut.actime = input_stat.st_atime; ut.actime = input_stat.st_atime; ut.modtime = input_stat.st_mtime; ut.modtime = input_stat.st_mtime; utime(out_path, &ut); utime(out_oat_path, &ut); // We've been successful, don't delete output. // We've been successful, don't delete output. out_fd.SetCleanup(false); out_oat_fd.SetCleanup(false); out_vdex_fd.SetCleanup(false); image_fd.SetCleanup(false); image_fd.SetCleanup(false); reference_profile_fd.SetCleanup(false); reference_profile_fd.SetCleanup(false); Loading Loading @@ -2145,33 +2210,40 @@ int move_ab(const char* apk_path, const char* instruction_set, const char* oat_d if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) { if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) { return -1; return -1; } } const std::string a_vdex_path = create_vdex_filename(a_path); const std::string a_image_path = create_image_filename(a_path); const std::string a_image_path = create_image_filename(a_path); // B path = A path + slot suffix. // B path = A path + slot suffix. const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str()); const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str()); const std::string b_vdex_path = StringPrintf("%s.%s", a_vdex_path.c_str(), slot_suffix.c_str()); const std::string b_image_path = StringPrintf("%s.%s", const std::string b_image_path = StringPrintf("%s.%s", a_image_path.c_str(), a_image_path.c_str(), slot_suffix.c_str()); slot_suffix.c_str()); bool oat_success = move_ab_path(b_path, a_path); bool success = true; bool success; if (move_ab_path(b_path, a_path)) { if (move_ab_path(b_vdex_path, a_vdex_path)) { if (oat_success) { // Note: we can live without an app image. As such, ignore failure to move the image file. // Note: we can live without an app image. As such, ignore failure to move the image file. // If we decide to require the app image, or the app image being moved correctly, // If we decide to require the app image, or the app image being moved correctly, // then change accordingly. // then change accordingly. constexpr bool kIgnoreAppImageFailure = true; constexpr bool kIgnoreAppImageFailure = true; bool art_success = true; if (!a_image_path.empty()) { if (!a_image_path.empty()) { art_success = move_ab_path(b_image_path, a_image_path); if (!move_ab_path(b_image_path, a_image_path)) { if (!kIgnoreAppImageFailure) { success = false; } } } } success = art_success || kIgnoreAppImageFailure; } else { } else { // Cleanup: delete B image, ignore errors. // Cleanup: delete B image, ignore errors. unlink(b_image_path.c_str()); unlink(b_image_path.c_str()); success = false; } } else { // Cleanup: delete B image, ignore errors. unlink(b_vdex_path.c_str()); unlink(b_image_path.c_str()); success = false; success = false; } } Loading Loading
cmds/installd/commands.cpp +139 −67 Original line number Original line Diff line number Diff line Loading @@ -671,8 +671,10 @@ static int split(char *buf, const char **argv) return count; return count; } } static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, static void run_patchoat(int input_oat_fd, int input_vdex_fd, int out_oat_fd, int out_vdex_fd, const char* output_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set) const char* input_oat_file_name, const char* input_vdex_file_name, const char* output_oat_file_name, const char* output_vdex_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set) { { static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; Loading @@ -686,35 +688,44 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/ /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/ char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN]; char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN]; char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN]; char input_vdex_fd_arg[strlen("--input-vdex-fd=") + MAX_INT_LEN]; char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN]; char output_vdex_fd_arg[strlen("--output-vdex-fd=") + MAX_INT_LEN]; const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art"; const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art"; // The caller has already gotten all the locks we need. // The caller has already gotten all the locks we need. const char* no_lock_arg = "--no-lock-output"; const char* no_lock_arg = "--no-lock-output"; sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd); sprintf(output_oat_fd_arg, "--output-oat-fd=%d", out_oat_fd); sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd); sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_oat_fd); ALOGV("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n", ALOGV("Running %s isa=%s in-oat-fd=%d (%s) in-vdex-fd=%d (%s) " PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name); "out-oat-fd=%d (%s) out-vdex-fd=%d (%s)\n", PATCHOAT_BIN, instruction_set, input_oat_fd, input_oat_file_name, input_vdex_fd, input_vdex_file_name, out_oat_fd, output_oat_file_name, out_vdex_fd, output_vdex_file_name); /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */ /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */ char* argv[7]; char* argv[9]; argv[0] = (char*) PATCHOAT_BIN; argv[0] = (char*) PATCHOAT_BIN; argv[1] = (char*) patched_image_location_arg; argv[1] = (char*) patched_image_location_arg; argv[2] = (char*) no_lock_arg; argv[2] = (char*) no_lock_arg; argv[3] = instruction_set_arg; argv[3] = instruction_set_arg; argv[4] = output_oat_fd_arg; argv[4] = input_oat_fd_arg; argv[5] = input_oat_fd_arg; argv[5] = input_vdex_fd_arg; argv[6] = NULL; argv[6] = output_oat_fd_arg; argv[7] = output_vdex_fd_arg; argv[8] = NULL; execv(PATCHOAT_BIN, (char* const *)argv); execv(PATCHOAT_BIN, (char* const *)argv); ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno)); ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno)); } } static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_file_name, static void run_dex2oat(int zip_fd, int oat_fd, int vdex_fd, int image_fd, const char* output_file_name, int swap_fd, const char *instruction_set, const char* input_file_name, const char* output_file_name, int swap_fd, const char* compiler_filter, bool vm_safe_mode, bool debuggable, bool post_bootcomplete, const char *instruction_set, const char* compiler_filter, bool vm_safe_mode, int profile_fd, const char* shared_libraries) { bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) { static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { Loading Loading @@ -795,6 +806,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN]; char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN]; char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX]; char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX]; char vdex_fd_arg[strlen("--vdex-fd=") + MAX_INT_LEN]; char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX]; char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; Loading @@ -810,6 +822,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); sprintf(zip_location_arg, "--zip-location=%s", input_file_name); sprintf(zip_location_arg, "--zip-location=%s", input_file_name); sprintf(vdex_fd_arg, "--vdex-fd=%d", vdex_fd); sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); sprintf(oat_location_arg, "--oat-location=%s", output_file_name); sprintf(oat_location_arg, "--oat-location=%s", output_file_name); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); Loading Loading @@ -872,7 +885,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); const char* argv[7 // program name, mandatory arguments and the final NULL const char* argv[8 // program name, mandatory arguments and the final NULL + (have_dex2oat_isa_variant ? 1 : 0) + (have_dex2oat_isa_variant ? 1 : 0) + (have_dex2oat_isa_features ? 1 : 0) + (have_dex2oat_isa_features ? 1 : 0) + (have_dex2oat_Xms_flag ? 2 : 0) + (have_dex2oat_Xms_flag ? 2 : 0) Loading @@ -893,6 +906,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ argv[i++] = DEX2OAT_BIN; argv[i++] = DEX2OAT_BIN; argv[i++] = zip_fd_arg; argv[i++] = zip_fd_arg; argv[i++] = zip_location_arg; argv[i++] = zip_location_arg; argv[i++] = vdex_fd_arg; argv[i++] = oat_fd_arg; argv[i++] = oat_fd_arg; argv[i++] = oat_location_arg; argv[i++] = oat_location_arg; argv[i++] = instruction_set_arg; argv[i++] = instruction_set_arg; Loading Loading @@ -1350,31 +1364,40 @@ bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string) return true; return true; } } // Translate the given oat path to an art (app image) path. An empty string static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) { // denotes an error. // A standard dalvik-cache entry. Replace ".dex" with `new_ext`. static std::string create_image_filename(const std::string& oat_path) { // A standard dalvik-cache entry. Replace ".dex" with ".art." if (EndsWith(oat_path, ".dex")) { if (EndsWith(oat_path, ".dex")) { std::string art_path = oat_path; std::string new_path = oat_path; art_path.replace(art_path.length() - strlen("dex"), strlen("dex"), "art"); new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext); CHECK(EndsWith(art_path, ".art")); CHECK(EndsWith(new_path, new_ext.c_str())); return art_path; return new_path; } } // An odex entry. Not that this may not be an extension, e.g., in the OTA // An odex entry. Not that this may not be an extension, e.g., in the OTA // case (where the base name will have an extension for the B artifact). // case (where the base name will have an extension for the B artifact). size_t odex_pos = oat_path.rfind(".odex"); size_t odex_pos = oat_path.rfind(".odex"); if (odex_pos != std::string::npos) { if (odex_pos != std::string::npos) { std::string art_path = oat_path; std::string new_path = oat_path; art_path.replace(odex_pos, strlen(".odex"), ".art"); new_path.replace(odex_pos, strlen(".odex"), new_ext); CHECK_NE(art_path.find(".art"), std::string::npos); CHECK_NE(new_path.find(new_ext), std::string::npos); return art_path; return new_path; } } // Don't know how to handle this. // Don't know how to handle this. return ""; return ""; } } // Translate the given oat path to an art (app image) path. An empty string // denotes an error. static std::string create_image_filename(const std::string& oat_path) { return replace_file_extension(oat_path, ".art"); } // Translate the given oat path to a vdex path. An empty string denotes an error. static std::string create_vdex_filename(const std::string& oat_path) { return replace_file_extension(oat_path, ".vdex"); } static bool add_extension_to_file_name(char* file_name, const char* extension) { static bool add_extension_to_file_name(char* file_name, const char* extension) { if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) { if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) { return false; return false; Loading Loading @@ -1410,7 +1433,7 @@ static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const } } static bool create_oat_out_path(const char* apk_path, const char* instruction_set, static bool create_oat_out_path(const char* apk_path, const char* instruction_set, const char* oat_dir, /*out*/ char* out_path) { const char* oat_dir, /*out*/ char* out_oat_path) { // Early best-effort check whether we can fit the the path into our buffers. // Early best-effort check whether we can fit the the path into our buffers. // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run // without a swap file, if necessary. Reference profiles file also add an extra ".prof" // without a swap file, if necessary. Reference profiles file also add an extra ".prof" Loading @@ -1425,11 +1448,11 @@ static bool create_oat_out_path(const char* apk_path, const char* instruction_se ALOGE("invalid oat_dir '%s'\n", oat_dir); ALOGE("invalid oat_dir '%s'\n", oat_dir); return false; return false; } } if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) { if (!calculate_oat_file_path(out_oat_path, oat_dir, apk_path, instruction_set)) { return false; return false; } } } else { } else { if (!create_cache_path(out_path, apk_path, instruction_set)) { if (!create_cache_path(out_oat_path, apk_path, instruction_set)) { return false; return false; } } } } Loading Loading @@ -1571,8 +1594,8 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins LOG_FATAL("dexopt flags contains unknown fields\n"); LOG_FATAL("dexopt flags contains unknown fields\n"); } } char out_path[PKG_PATH_MAX]; char out_oat_path[PKG_PATH_MAX]; if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) { if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_oat_path)) { return false; return false; } } Loading @@ -1591,7 +1614,7 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins break; break; case DEXOPT_SELF_PATCHOAT_NEEDED: case DEXOPT_SELF_PATCHOAT_NEEDED: input_file = out_path; input_file = out_oat_path; break; break; default: default: Loading @@ -1603,21 +1626,57 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins memset(&input_stat, 0, sizeof(input_stat)); memset(&input_stat, 0, sizeof(input_stat)); stat(input_file, &input_stat); stat(input_file, &input_stat); // Open the input file. If running dex2oat, `input_file` is the APK. If running // patchoat, it is the OAT file to be relocated. base::unique_fd input_fd(open(input_file, O_RDONLY, 0)); base::unique_fd input_fd(open(input_file, O_RDONLY, 0)); if (input_fd.get() < 0) { if (input_fd.get() < 0) { ALOGE("installd cannot open '%s' for input during dexopt\n", input_file); ALOGE("installd cannot open '%s' for input during dexopt\n", input_file); return -1; return -1; } } const std::string out_path_str(out_path); // If invoking patchoat, open the VDEX associated with the OAT too. Dex2oatFileWrapper<std::function<void ()>> out_fd( std::string in_vdex_path_str; open_output_file(out_path, /*recreate*/true, /*permissions*/0644), base::unique_fd input_vdex_fd; [out_path_str]() { unlink(out_path_str.c_str()); }); if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED if (out_fd.get() < 0) { || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_path); in_vdex_path_str = create_vdex_filename(input_file); if (in_vdex_path_str.empty()) { return -1; } input_vdex_fd.reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0)); if (input_vdex_fd.get() < 0) { ALOGE("installd cannot open '%s' for input during dexopt\n", in_vdex_path_str.c_str()); return -1; } } // Create the output OAT file. const std::string out_oat_path_str(out_oat_path); Dex2oatFileWrapper<std::function<void ()>> out_oat_fd( open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644), [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); }); if (out_oat_fd.get() < 0) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_oat_path); return -1; return -1; } } if (!set_permissions_and_ownership(out_fd.get(), is_public, uid, out_path)) { if (!set_permissions_and_ownership(out_oat_fd.get(), is_public, uid, out_oat_path)) { return -1; } // Infer the name of the output VDEX and create it. const std::string out_vdex_path_str = create_vdex_filename(out_oat_path_str); if (out_vdex_path_str.empty()) { return -1; } Dex2oatFileWrapper<std::function<void ()>> out_vdex_fd( open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644), [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); }); if (out_vdex_fd.get() < 0) { ALOGE("installd cannot open '%s' for output during dexopt\n", out_vdex_path_str.c_str()); return -1; } if (!set_permissions_and_ownership(out_vdex_fd.get(), is_public, uid, out_vdex_path_str.c_str())) { return -1; return -1; } } Loading @@ -1626,7 +1685,7 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins if (ShouldUseSwapFileForDexopt()) { if (ShouldUseSwapFileForDexopt()) { // Make sure there really is enough space. // Make sure there really is enough space. char swap_file_name[PKG_PATH_MAX]; char swap_file_name[PKG_PATH_MAX]; strcpy(swap_file_name, out_path); strcpy(swap_file_name, out_oat_path); if (add_extension_to_file_name(swap_file_name, ".swap")) { if (add_extension_to_file_name(swap_file_name, ".swap")) { swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600)); swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600)); } } Loading @@ -1644,8 +1703,8 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins // Avoid generating an app image for extract only since it will not contain any classes. // Avoid generating an app image for extract only since it will not contain any classes. Dex2oatFileWrapper<std::function<void ()>> image_fd; Dex2oatFileWrapper<std::function<void ()>> image_fd; const std::string image_path = create_image_filename(out_path); const std::string image_path = create_image_filename(out_oat_path); if (!image_path.empty()) { if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED && !image_path.empty()) { char app_image_format[kPropertyValueMax]; char app_image_format[kPropertyValueMax]; bool have_app_image_format = bool have_app_image_format = get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; Loading Loading @@ -1690,27 +1749,32 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins drop_capabilities(uid); drop_capabilities(uid); SetDex2OatAndPatchOatScheduling(boot_complete); SetDex2OatAndPatchOatScheduling(boot_complete); if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) { if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno)); ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno)); _exit(67); _exit(67); } } if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { run_patchoat(input_fd.get(), run_patchoat(input_fd.get(), out_fd.get(), input_vdex_fd.get(), out_oat_fd.get(), out_vdex_fd.get(), input_file, input_file, out_path, in_vdex_path_str.c_str(), out_oat_path, out_vdex_path_str.c_str(), pkgname, pkgname, instruction_set); instruction_set); } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) { } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) { // Pass dex2oat the relative path to the input file. // Pass dex2oat the relative path to the input file. const char *input_file_name = get_location_from_path(input_file); const char *input_file_name = get_location_from_path(input_file); run_dex2oat(input_fd.get(), run_dex2oat(input_fd.get(), out_fd.get(), out_oat_fd.get(), out_vdex_fd.get(), image_fd.get(), image_fd.get(), input_file_name, input_file_name, out_path, out_oat_path, swap_fd.get(), swap_fd.get(), instruction_set, instruction_set, compiler_filter, compiler_filter, Loading @@ -1737,10 +1801,11 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins struct utimbuf ut; struct utimbuf ut; ut.actime = input_stat.st_atime; ut.actime = input_stat.st_atime; ut.modtime = input_stat.st_mtime; ut.modtime = input_stat.st_mtime; utime(out_path, &ut); utime(out_oat_path, &ut); // We've been successful, don't delete output. // We've been successful, don't delete output. out_fd.SetCleanup(false); out_oat_fd.SetCleanup(false); out_vdex_fd.SetCleanup(false); image_fd.SetCleanup(false); image_fd.SetCleanup(false); reference_profile_fd.SetCleanup(false); reference_profile_fd.SetCleanup(false); Loading Loading @@ -2145,33 +2210,40 @@ int move_ab(const char* apk_path, const char* instruction_set, const char* oat_d if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) { if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) { return -1; return -1; } } const std::string a_vdex_path = create_vdex_filename(a_path); const std::string a_image_path = create_image_filename(a_path); const std::string a_image_path = create_image_filename(a_path); // B path = A path + slot suffix. // B path = A path + slot suffix. const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str()); const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str()); const std::string b_vdex_path = StringPrintf("%s.%s", a_vdex_path.c_str(), slot_suffix.c_str()); const std::string b_image_path = StringPrintf("%s.%s", const std::string b_image_path = StringPrintf("%s.%s", a_image_path.c_str(), a_image_path.c_str(), slot_suffix.c_str()); slot_suffix.c_str()); bool oat_success = move_ab_path(b_path, a_path); bool success = true; bool success; if (move_ab_path(b_path, a_path)) { if (move_ab_path(b_vdex_path, a_vdex_path)) { if (oat_success) { // Note: we can live without an app image. As such, ignore failure to move the image file. // Note: we can live without an app image. As such, ignore failure to move the image file. // If we decide to require the app image, or the app image being moved correctly, // If we decide to require the app image, or the app image being moved correctly, // then change accordingly. // then change accordingly. constexpr bool kIgnoreAppImageFailure = true; constexpr bool kIgnoreAppImageFailure = true; bool art_success = true; if (!a_image_path.empty()) { if (!a_image_path.empty()) { art_success = move_ab_path(b_image_path, a_image_path); if (!move_ab_path(b_image_path, a_image_path)) { if (!kIgnoreAppImageFailure) { success = false; } } } } success = art_success || kIgnoreAppImageFailure; } else { } else { // Cleanup: delete B image, ignore errors. // Cleanup: delete B image, ignore errors. unlink(b_image_path.c_str()); unlink(b_image_path.c_str()); success = false; } } else { // Cleanup: delete B image, ignore errors. unlink(b_vdex_path.c_str()); unlink(b_image_path.c_str()); success = false; success = false; } } Loading