summaryrefslogtreecommitdiff
path: root/cmds/installd/dexopt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/installd/dexopt.cpp')
-rw-r--r--cmds/installd/dexopt.cpp964
1 files changed, 296 insertions, 668 deletions
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index ffa87249e2..d678281b6e 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -36,25 +36,30 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <async_safe/log.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
-#include <dex2oat_return_codes.h>
#include <log/log.h> // TODO: Move everything to base/logging.
#include <openssl/sha.h>
#include <private/android_filesystem_config.h>
-#include <processgroup/sched_policy.h>
+#include <processgroup/processgroup.h>
#include <selinux/android.h>
#include <server_configurable_flags/get_flags.h>
#include <system/thread_defs.h>
#include "dexopt.h"
#include "dexopt_return_codes.h"
+#include "execv_helper.h"
#include "globals.h"
#include "installd_deps.h"
+#include "installd_constants.h"
#include "otapreopt_utils.h"
+#include "run_dex2oat.h"
+#include "unique_file.h"
#include "utils.h"
+using android::base::Basename;
using android::base::EndsWith;
using android::base::GetBoolProperty;
using android::base::GetProperty;
@@ -67,16 +72,6 @@ using android::base::unique_fd;
namespace android {
namespace installd {
-// Should minidebug info be included in compiled artifacts? Even if this value is
-// "true," usage might still be conditional to other constraints, e.g., system
-// property overrides.
-static constexpr bool kEnableMinidebugInfo = true;
-
-static constexpr const char* kMinidebugInfoSystemProperty = "dalvik.vm.dex2oat-minidebuginfo";
-static constexpr bool kMinidebugInfoSystemPropertyDefault = false;
-static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
-static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
-
// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
struct FreeDelete {
@@ -186,93 +181,6 @@ bool clear_primary_current_profile(const std::string& package_name, const std::s
return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false);
}
-static std::vector<std::string> SplitBySpaces(const std::string& str) {
- if (str.empty()) {
- return {};
- }
- return android::base::Split(str, " ");
-}
-
-static const char* get_location_from_path(const char* path) {
- static constexpr char kLocationSeparator = '/';
- const char *location = strrchr(path, kLocationSeparator);
- if (location == nullptr) {
- return path;
- } else {
- // Skip the separator character.
- return location + 1;
- }
-}
-
-// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
-// need to be performed between the fork and exec.
-class ExecVHelper {
- public:
- // Store a placeholder for the binary name.
- ExecVHelper() : args_(1u, std::string()) {}
-
- void PrepareArgs(const std::string& bin) {
- CHECK(!args_.empty());
- CHECK(args_[0].empty());
- args_[0] = bin;
- // Write char* into array.
- for (const std::string& arg : args_) {
- argv_.push_back(arg.c_str());
- }
- argv_.push_back(nullptr); // Add null terminator.
- }
-
- [[ noreturn ]]
- void Exec(int exit_code) {
- execv(argv_[0], (char * const *)&argv_[0]);
- PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
- exit(exit_code);
- }
-
- // Add an arg if it's not empty.
- void AddArg(const std::string& arg) {
- if (!arg.empty()) {
- args_.push_back(arg);
- }
- }
-
- // Add a runtime arg if it's not empty.
- void AddRuntimeArg(const std::string& arg) {
- if (!arg.empty()) {
- args_.push_back("--runtime-arg");
- args_.push_back(arg);
- }
- }
-
- protected:
- // Holder arrays for backing arg storage.
- std::vector<std::string> args_;
-
- // Argument poiners.
- std::vector<const char*> argv_;
-};
-
-static std::string MapPropertyToArg(const std::string& property,
- const std::string& format,
- const std::string& default_value = "") {
- std::string prop = GetProperty(property, default_value);
- if (!prop.empty()) {
- return StringPrintf(format.c_str(), prop.c_str());
- }
- return "";
-}
-
-static std::string MapPropertyToArgWithBackup(const std::string& property,
- const std::string& backupProperty,
- const std::string& format,
- const std::string& default_value = "") {
- std::string value = GetProperty(property, default_value);
- if (!value.empty()) {
- return StringPrintf(format.c_str(), value.c_str());
- }
- return MapPropertyToArg(backupProperty, format, default_value);
-}
-
// Determines which binary we should use for execution (the debug or non-debug version).
// e.g. dex2oatd vs dex2oat
static const char* select_execution_binary(const char* binary, const char* debug_binary,
@@ -311,9 +219,6 @@ const char* select_execution_binary(
static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
// Feature flag name for running the JIT in Zygote experiment, b/119800099.
static const char* ENABLE_JITZYGOTE_IMAGE = "enable_apex_image";
-// Location of the JIT Zygote image.
-static const char* kJitZygoteImage =
- "boot.art:/nonx/boot-framework.art!/system/etc/boot-image.prof";
// Phenotype property name for enabling profiling the boot class path.
static const char* PROFILE_BOOT_CLASS_PATH = "profilebootclasspath";
@@ -328,288 +233,11 @@ static bool IsBootClassPathProfilingEnable() {
return profile_boot_class_path == "true";
}
-class RunDex2Oat : public ExecVHelper {
- public:
- RunDex2Oat(int zip_fd,
- int oat_fd,
- int input_vdex_fd,
- int output_vdex_fd,
- int image_fd,
- const char* input_file_name,
- const char* output_file_name,
- int swap_fd,
- const char* instruction_set,
- const char* compiler_filter,
- bool debuggable,
- bool post_bootcomplete,
- bool for_restore,
- bool background_job_compile,
- int profile_fd,
- const char* class_loader_context,
- const std::string& class_loader_context_fds,
- int target_sdk_version,
- bool enable_hidden_api_checks,
- bool generate_compact_dex,
- int dex_metadata_fd,
- const char* compilation_reason) {
- // Get the relative path to the input file.
- const char* relative_input_file_name = get_location_from_path(input_file_name);
-
- std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
- std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
-
- std::string threads_format = "-j%s";
- std::string dex2oat_threads_arg = post_bootcomplete
- ? (for_restore
- ? MapPropertyToArgWithBackup(
- "dalvik.vm.restore-dex2oat-threads",
- "dalvik.vm.dex2oat-threads",
- threads_format)
- : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))
- : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format);
- std::string cpu_set_format = "--cpu-set=%s";
- std::string dex2oat_cpu_set_arg = post_bootcomplete
- ? (for_restore
- ? MapPropertyToArgWithBackup(
- "dalvik.vm.restore-dex2oat-cpu-set",
- "dalvik.vm.dex2oat-cpu-set",
- cpu_set_format)
- : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))
- : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format);
-
- std::string bootclasspath;
- char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
- if (dex2oat_bootclasspath != nullptr) {
- bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
- }
- // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
- // BOOTCLASSPATH.
-
- const std::string dex2oat_isa_features_key =
- StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
- std::string instruction_set_features_arg =
- MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
-
- const std::string dex2oat_isa_variant_key =
- StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
- std::string instruction_set_variant_arg =
- MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
-
- const char* dex2oat_norelocation = "-Xnorelocate";
-
- const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
- std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
- ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
-
- // If we are booting without the real /data, don't spend time compiling.
- std::string vold_decrypt = GetProperty("vold.decrypt", "");
- bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
- vold_decrypt == "1";
-
- std::string updatable_bcp_packages =
- MapPropertyToArg("dalvik.vm.dex2oat-updatable-bcp-packages-file",
- "--updatable-bcp-packages-file=%s");
- if (updatable_bcp_packages.empty()) {
- // Make dex2oat fail by providing non-existent file name.
- updatable_bcp_packages = "--updatable-bcp-packages-file=/nonx/updatable-bcp-packages.txt";
- }
-
- std::string resolve_startup_string_arg =
- MapPropertyToArg("persist.device_config.runtime.dex2oat_resolve_startup_strings",
- "--resolve-startup-const-strings=%s");
- if (resolve_startup_string_arg.empty()) {
- // If empty, fall back to system property.
- resolve_startup_string_arg =
- MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
- "--resolve-startup-const-strings=%s");
- }
-
- const std::string image_block_size_arg =
- MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size",
- "--max-image-block-size=%s");
-
- const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
-
- std::string image_format_arg;
- if (image_fd >= 0) {
- image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
- }
-
- std::string dex2oat_large_app_threshold_arg =
- MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
-
-
-
- // Decide whether to use dex2oat64.
- bool use_dex2oat64 = false;
- // Check whether the device even supports 64-bit ABIs.
- if (!GetProperty("ro.product.cpu.abilist64", "").empty()) {
- use_dex2oat64 = GetBoolProperty("dalvik.vm.dex2oat64.enabled", false);
- }
- const char* dex2oat_bin = select_execution_binary(
- (use_dex2oat64 ? kDex2oat64Path : kDex2oat32Path),
- (use_dex2oat64 ? kDex2oatDebug64Path : kDex2oatDebug32Path),
- background_job_compile);
-
- bool generate_minidebug_info = kEnableMinidebugInfo &&
- GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
-
- std::string boot_image;
- std::string use_jitzygote_image =
- server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
- ENABLE_JITZYGOTE_IMAGE,
- /*default_value=*/ "");
-
- if (use_jitzygote_image == "true" || IsBootClassPathProfilingEnable()) {
- boot_image = StringPrintf("--boot-image=%s", kJitZygoteImage);
- } else {
- boot_image = MapPropertyToArg("dalvik.vm.boot-image", "--boot-image=%s");
- }
-
- // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
- // use arraysize instead.
- std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
- std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
- std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
- std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
- std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
- std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
- std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
- std::string dex2oat_compiler_filter_arg;
- std::string dex2oat_swap_fd;
- std::string dex2oat_image_fd;
- std::string target_sdk_version_arg;
- if (target_sdk_version != 0) {
- target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
- }
- std::string class_loader_context_arg;
- std::string class_loader_context_fds_arg;
- if (class_loader_context != nullptr) {
- class_loader_context_arg = StringPrintf("--class-loader-context=%s",
- class_loader_context);
- if (!class_loader_context_fds.empty()) {
- class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
- class_loader_context_fds.c_str());
- }
- }
-
- if (swap_fd >= 0) {
- dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
- }
- if (image_fd >= 0) {
- dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
- }
-
- // Compute compiler filter.
- bool have_dex2oat_relocation_skip_flag = false;
- if (skip_compilation) {
- dex2oat_compiler_filter_arg = "--compiler-filter=extract";
- have_dex2oat_relocation_skip_flag = true;
- } else if (compiler_filter != nullptr) {
- dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
- }
-
- if (dex2oat_compiler_filter_arg.empty()) {
- dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
- "--compiler-filter=%s");
- }
-
- // Check whether all apps should be compiled debuggable.
- if (!debuggable) {
- debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
- }
- std::string profile_arg;
- if (profile_fd != -1) {
- profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
- }
-
- // Get the directory of the apk to pass as a base classpath directory.
- std::string base_dir;
- std::string apk_dir(input_file_name);
- unsigned long dir_index = apk_dir.rfind('/');
- bool has_base_dir = dir_index != std::string::npos;
- if (has_base_dir) {
- apk_dir = apk_dir.substr(0, dir_index);
- base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
- }
-
- std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
- std::string compilation_reason_arg = compilation_reason == nullptr
- ? ""
- : std::string("--compilation-reason=") + compilation_reason;
-
- ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
- // Disable cdex if update input vdex is true since this combination of options is not
- // supported.
- const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
- AddArg(zip_fd_arg);
- AddArg(zip_location_arg);
- AddArg(input_vdex_fd_arg);
- AddArg(output_vdex_fd_arg);
- AddArg(oat_fd_arg);
- AddArg(oat_location_arg);
- AddArg(instruction_set_arg);
-
- AddArg(instruction_set_variant_arg);
- AddArg(instruction_set_features_arg);
-
- AddArg(boot_image);
-
- AddRuntimeArg(bootclasspath);
- AddRuntimeArg(dex2oat_Xms_arg);
- AddRuntimeArg(dex2oat_Xmx_arg);
-
- AddArg(updatable_bcp_packages);
- AddArg(resolve_startup_string_arg);
- AddArg(image_block_size_arg);
- AddArg(dex2oat_compiler_filter_arg);
- AddArg(dex2oat_threads_arg);
- AddArg(dex2oat_cpu_set_arg);
- AddArg(dex2oat_swap_fd);
- AddArg(dex2oat_image_fd);
-
- if (generate_debug_info) {
- AddArg("--generate-debug-info");
- }
- if (debuggable) {
- AddArg("--debuggable");
- }
- AddArg(image_format_arg);
- AddArg(dex2oat_large_app_threshold_arg);
-
- if (have_dex2oat_relocation_skip_flag) {
- AddRuntimeArg(dex2oat_norelocation);
- }
- AddArg(profile_arg);
- AddArg(base_dir);
- AddArg(class_loader_context_arg);
- AddArg(class_loader_context_fds_arg);
- if (generate_minidebug_info) {
- AddArg(kMinidebugDex2oatFlag);
- }
- if (disable_cdex) {
- AddArg(kDisableCompactDexFlag);
- }
- AddRuntimeArg(target_sdk_version_arg);
- if (enable_hidden_api_checks) {
- AddRuntimeArg("-Xhidden-api-policy:enabled");
- }
-
- if (dex_metadata_fd > -1) {
- AddArg(dex_metadata_fd_arg);
- }
-
- AddArg(compilation_reason_arg);
-
- // Do not add args after dex2oat_flags, they should override others for debugging.
- args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
-
- PrepareArgs(dex2oat_bin);
+static void UnlinkIgnoreResult(const std::string& path) {
+ if (unlink(path.c_str()) < 0) {
+ PLOG(ERROR) << "Failed to unlink " << path;
}
-};
+}
/*
* Whether dexopt should use a swap file when compiling an APK.
@@ -654,8 +282,8 @@ static bool ShouldUseSwapFileForDexopt() {
static void SetDex2OatScheduling(bool set_to_bg) {
if (set_to_bg) {
- if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- PLOG(ERROR) << "set_sched_policy failed";
+ if (!SetTaskProfiles(0, {"Dex2OatBootComplete"})) {
+ LOG(ERROR) << "Failed to set dex2oat task profile";
exit(DexoptReturnCodes::kSetSchedPolicy);
}
if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
@@ -665,8 +293,8 @@ static void SetDex2OatScheduling(bool set_to_bg) {
}
}
-static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags) {
- unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, 0600)));
+static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags, mode_t mode) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, mode)));
if (fd.get() < 0) {
if (errno != EEXIST) {
PLOG(ERROR) << "Failed to create profile " << profile;
@@ -683,7 +311,7 @@ static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t f
return fd;
}
-static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags) {
+static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags, mode_t mode) {
// Do not follow symlinks when opening a profile:
// - primary profiles should not contain symlinks in their paths
// - secondary dex paths should have been already resolved and validated
@@ -693,7 +321,7 @@ static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t fla
// Reference profiles and snapshots are created on the fly; so they might not exist beforehand.
unique_fd fd;
if ((flags & O_CREAT) != 0) {
- fd = create_profile(uid, profile, flags);
+ fd = create_profile(uid, profile, flags, mode);
} else {
fd.reset(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
}
@@ -709,6 +337,16 @@ static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t fla
PLOG(ERROR) << "Failed to open profile " << profile;
}
return invalid_unique_fd();
+ } else {
+ // If we just create the file we need to set its mode because on Android
+ // open has a mask that only allows owner access.
+ if ((flags & O_CREAT) != 0) {
+ if (fchmod(fd.get(), mode) != 0) {
+ PLOG(ERROR) << "Could not set mode " << std::hex << mode << std::dec
+ << " on profile" << profile;
+ // Not a terminal failure.
+ }
+ }
}
return fd;
@@ -718,19 +356,38 @@ static unique_fd open_current_profile(uid_t uid, userid_t user, const std::strin
const std::string& location, bool is_secondary_dex) {
std::string profile = create_current_profile_path(user, package_name, location,
is_secondary_dex);
- return open_profile(uid, profile, O_RDONLY);
+ return open_profile(uid, profile, O_RDONLY, /*mode=*/ 0);
}
static unique_fd open_reference_profile(uid_t uid, const std::string& package_name,
const std::string& location, bool read_write, bool is_secondary_dex) {
std::string profile = create_reference_profile_path(package_name, location, is_secondary_dex);
- return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
+ return open_profile(
+ uid,
+ profile,
+ read_write ? (O_CREAT | O_RDWR) : O_RDONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP); // so that ART can also read it when apps run.
+}
+
+static UniqueFile open_reference_profile_as_unique_file(uid_t uid, const std::string& package_name,
+ const std::string& location, bool read_write, bool is_secondary_dex) {
+ std::string profile_path = create_reference_profile_path(package_name, location,
+ is_secondary_dex);
+ unique_fd ufd = open_profile(
+ uid,
+ profile_path,
+ read_write ? (O_CREAT | O_RDWR) : O_RDONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP); // so that ART can also read it when apps run.
+
+ return UniqueFile(ufd.release(), profile_path, [](const std::string& path) {
+ clear_profile(path);
+ });
}
static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name,
const std::string& location) {
std::string profile = create_snapshot_profile_path(package_name, location);
- return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC);
+ return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
}
static void open_profile_files(uid_t uid, const std::string& package_name,
@@ -760,11 +417,12 @@ static void open_profile_files(uid_t uid, const std::string& package_name,
static constexpr int PROFMAN_BIN_RETURN_CODE_SUCCESS = 0;
static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 1;
-static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 2;
+static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_NOT_ENOUGH_DELTA = 2;
static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 4;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 5;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_DIFFERENT_VERSIONS = 6;
+static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_EMPTY_PROFILES = 7;
class RunProfman : public ExecVHelper {
public:
@@ -814,6 +472,26 @@ class RunProfman : public ExecVHelper {
AddArg("--boot-image-merge");
}
+ // The percent won't exceed 100, otherwise, don't set it and use the
+ // default one set in profman.
+ uint32_t min_new_classes_percent_change = ::android::base::GetUintProperty<uint32_t>(
+ "dalvik.vm.bgdexopt.new-classes-percent",
+ /*default*/std::numeric_limits<uint32_t>::max());
+ if (min_new_classes_percent_change <= 100) {
+ AddArg("--min-new-classes-percent-change=" +
+ std::to_string(min_new_classes_percent_change));
+ }
+
+ // The percent won't exceed 100, otherwise, don't set it and use the
+ // default one set in profman.
+ uint32_t min_new_methods_percent_change = ::android::base::GetUintProperty<uint32_t>(
+ "dalvik.vm.bgdexopt.new-methods-percent",
+ /*default*/std::numeric_limits<uint32_t>::max());
+ if (min_new_methods_percent_change <= 100) {
+ AddArg("--min-new-methods-percent-change=" +
+ std::to_string(min_new_methods_percent_change));
+ }
+
// Do not add after dex2oat_flags, they should override others for debugging.
PrepareArgs(profman_bin);
}
@@ -868,6 +546,7 @@ class RunProfman : public ExecVHelper {
/*for_boot_image*/false);
}
+ using ExecVHelper::Exec; // To suppress -Wno-overloaded-virtual
void Exec() {
ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
}
@@ -878,15 +557,7 @@ class RunProfman : public ExecVHelper {
std::vector<unique_fd> apk_fds_;
};
-
-
-// Decides if profile guided compilation is needed or not based on existing profiles.
-// The location is the package name for primary apks or the dex path for secondary dex files.
-// Returns true if there is enough information in the current profiles that makes it
-// worth to recompile the given location.
-// If the return value is true all the current profiles would have been merged into
-// the reference profiles accessible with open_reference_profile().
-static bool analyze_profiles(uid_t uid, const std::string& package_name,
+static int analyze_profiles(uid_t uid, const std::string& package_name,
const std::string& location, bool is_secondary_dex) {
std::vector<unique_fd> profiles_fd;
unique_fd reference_profile_fd;
@@ -895,7 +566,7 @@ static bool analyze_profiles(uid_t uid, const std::string& package_name,
if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
// Skip profile guided compilation because no profiles were found.
// Or if the reference profile info couldn't be opened.
- return false;
+ return PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES;
}
RunProfman profman_merge;
@@ -917,6 +588,7 @@ static bool analyze_profiles(uid_t uid, const std::string& package_name,
/* parent */
int return_code = wait_child(pid);
bool need_to_compile = false;
+ bool empty_profiles = false;
bool should_clear_current_profiles = false;
bool should_clear_reference_profile = false;
if (!WIFEXITED(return_code)) {
@@ -929,11 +601,17 @@ static bool analyze_profiles(uid_t uid, const std::string& package_name,
should_clear_current_profiles = true;
should_clear_reference_profile = false;
break;
- case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
+ case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_NOT_ENOUGH_DELTA:
need_to_compile = false;
should_clear_current_profiles = false;
should_clear_reference_profile = false;
break;
+ case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION_EMPTY_PROFILES:
+ need_to_compile = false;
+ empty_profiles = true;
+ should_clear_current_profiles = false;
+ should_clear_reference_profile = false;
+ break;
case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
LOG(WARNING) << "Bad profiles for location " << location;
need_to_compile = false;
@@ -976,16 +654,29 @@ static bool analyze_profiles(uid_t uid, const std::string& package_name,
if (should_clear_reference_profile) {
clear_reference_profile(package_name, location, is_secondary_dex);
}
- return need_to_compile;
+ int result = 0;
+ if (need_to_compile) {
+ result = PROFILES_ANALYSIS_OPTIMIZE;
+ } else if (empty_profiles) {
+ result = PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES;
+ } else {
+ result = PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA;
+ }
+ return result;
}
// Decides if profile guided compilation is needed or not based on existing profiles.
-// The analysis is done for the primary apks of the given package.
-// Returns true if there is enough information in the current profiles that makes it
-// worth to recompile the package.
-// If the return value is true all the current profiles would have been merged into
-// the reference profiles accessible with open_reference_profile().
-bool analyze_primary_profiles(uid_t uid, const std::string& package_name,
+// The analysis is done for a single profile name (which corresponds to a single code path).
+//
+// Returns PROFILES_ANALYSIS_OPTIMIZE if there is enough information in the current profiles
+// that makes it worth to recompile the package.
+// If the return value is PROFILES_ANALYSIS_OPTIMIZE all the current profiles would have been
+// merged into the reference profiles accessible with open_reference_profile().
+//
+// Return PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA if the package should not optimize.
+// As a special case returns PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES if all profiles are
+// empty.
+int analyze_primary_profiles(uid_t uid, const std::string& package_name,
const std::string& profile_name) {
return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
}
@@ -1022,7 +713,7 @@ bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& p
PLOG(ERROR) << "installd cannot open " << code_path.c_str();
return false;
}
- dex_locations.push_back(get_location_from_path(code_path.c_str()));
+ dex_locations.push_back(Basename(code_path));
apk_fds.push_back(std::move(apk_fd));
@@ -1070,7 +761,8 @@ bool copy_system_profile(const std::string& system_profile,
if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
if (errno != EWOULDBLOCK) {
- PLOG(WARNING) << "Error locking profile " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error locking profile %s: %d",
+ package_name.c_str(), errno);
}
// This implies that the app owning this profile is running
// (and has acquired the lock).
@@ -1078,13 +770,15 @@ bool copy_system_profile(const std::string& system_profile,
// The app never acquires the lock for the reference profiles of primary apks.
// Only dex2oat from installd will do that. Since installd is single threaded
// we should not see this case. Nevertheless be prepared for it.
- PLOG(WARNING) << "Failed to flock " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Failed to flock %s: %d",
+ package_name.c_str(), errno);
return false;
}
bool truncated = ftruncate(out_fd.get(), 0) == 0;
if (!truncated) {
- PLOG(WARNING) << "Could not truncate " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Could not truncate %s: %d",
+ package_name.c_str(), errno);
}
// Copy over data.
@@ -1098,7 +792,8 @@ bool copy_system_profile(const std::string& system_profile,
write(out_fd.get(), buffer, bytes);
}
if (flock(out_fd.get(), LOCK_UN) != 0) {
- PLOG(WARNING) << "Error unlocking profile " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error unlocking profile %s: %d",
+ package_name.c_str(), errno);
}
// Use _exit since we don't want to run the global destructors in the child.
// b/62597429
@@ -1216,118 +911,14 @@ static bool create_oat_out_path(const char* apk_path, const char* instruction_se
return true;
}
-// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
-// on destruction. It will also run the given cleanup (unless told not to) after closing.
-//
-// Usage example:
-//
-// Dex2oatFileWrapper file(open(...),
-// [name]() {
-// unlink(name.c_str());
-// });
-// // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
-// wrapper if captured as a reference.
-//
-// if (file.get() == -1) {
-// // Error opening...
-// }
-//
-// ...
-// if (error) {
-// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
-// // and delete the file (after the fd is closed).
-// return -1;
-// }
-//
-// (Success case)
-// file.SetCleanup(false);
-// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
-// // (leaving the file around; after the fd is closed).
-//
-class Dex2oatFileWrapper {
- public:
- Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true), auto_close_(true) {
- }
-
- Dex2oatFileWrapper(int value, std::function<void ()> cleanup)
- : value_(value), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
-
- Dex2oatFileWrapper(Dex2oatFileWrapper&& other) {
- value_ = other.value_;
- cleanup_ = other.cleanup_;
- do_cleanup_ = other.do_cleanup_;
- auto_close_ = other.auto_close_;
- other.release();
- }
-
- Dex2oatFileWrapper& operator=(Dex2oatFileWrapper&& other) {
- value_ = other.value_;
- cleanup_ = other.cleanup_;
- do_cleanup_ = other.do_cleanup_;
- auto_close_ = other.auto_close_;
- other.release();
- return *this;
- }
-
- ~Dex2oatFileWrapper() {
- reset(-1);
- }
-
- int get() {
- return value_;
- }
-
- void SetCleanup(bool cleanup) {
- do_cleanup_ = cleanup;
- }
-
- void reset(int new_value) {
- if (auto_close_ && value_ >= 0) {
- close(value_);
- }
- if (do_cleanup_ && cleanup_ != nullptr) {
- cleanup_();
- }
-
- value_ = new_value;
- }
-
- void reset(int new_value, std::function<void ()> new_cleanup) {
- if (auto_close_ && value_ >= 0) {
- close(value_);
- }
- if (do_cleanup_ && cleanup_ != nullptr) {
- cleanup_();
- }
-
- value_ = new_value;
- cleanup_ = new_cleanup;
- }
-
- void DisableAutoClose() {
- auto_close_ = false;
- }
-
- private:
- void release() {
- value_ = -1;
- do_cleanup_ = false;
- cleanup_ = nullptr;
- }
- int value_;
- std::function<void ()> cleanup_;
- bool do_cleanup_;
- bool auto_close_;
-};
-
// (re)Creates the app image if needed.
-Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path,
+UniqueFile maybe_open_app_image(const std::string& out_oat_path,
bool generate_app_image, bool is_public, int uid, bool is_secondary_dex) {
const std::string image_path = create_image_filename(out_oat_path);
if (image_path.empty()) {
// Happens when the out_oat_path has an unknown extension.
- return Dex2oatFileWrapper();
+ return UniqueFile();
}
// In case there is a stale image, remove it now. Ignore any error.
@@ -1335,18 +926,19 @@ Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path,
// Not enabled, exit.
if (!generate_app_image) {
- return Dex2oatFileWrapper();
+ return UniqueFile();
}
std::string app_image_format = GetProperty("dalvik.vm.appimageformat", "");
if (app_image_format.empty()) {
- return Dex2oatFileWrapper();
+ return UniqueFile();
}
// Recreate is true since we do not want to modify a mapped image. If the app is
// already running and we modify the image file, it can cause crashes (b/27493510).
- Dex2oatFileWrapper wrapper_fd(
+ UniqueFile image_file(
open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
- [image_path]() { unlink(image_path.c_str()); });
- if (wrapper_fd.get() < 0) {
+ image_path,
+ UnlinkIgnoreResult);
+ if (image_file.fd() < 0) {
// Could not create application image file. Go on since we can compile without it.
LOG(ERROR) << "installd could not create '" << image_path
<< "' for image file during dexopt";
@@ -1357,21 +949,21 @@ Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path,
}
}
} else if (!set_permissions_and_ownership(
- wrapper_fd.get(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
+ image_file.fd(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
- wrapper_fd.reset(-1);
+ image_file.reset();
}
- return wrapper_fd;
+ return image_file;
}
// Creates the dexopt swap file if necessary and return its fd.
// Returns -1 if there's no need for a swap or in case of errors.
-unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+unique_fd maybe_open_dexopt_swap_file(const std::string& out_oat_path) {
if (!ShouldUseSwapFileForDexopt()) {
return invalid_unique_fd();
}
- auto swap_file_name = std::string(out_oat_path) + ".swap";
+ auto swap_file_name = out_oat_path + ".swap";
unique_fd swap_fd(open_output_file(
swap_file_name.c_str(), /*recreate*/true, /*permissions*/0600));
if (swap_fd.get() < 0) {
@@ -1389,13 +981,13 @@ unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
// Opens the reference profiles if needed.
// Note that the reference profile might not exist so it's OK if the fd will be -1.
-Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
+UniqueFile maybe_open_reference_profile(const std::string& pkgname,
const std::string& dex_path, const char* profile_name, bool profile_guided,
bool is_public, int uid, bool is_secondary_dex) {
// If we are not profile guided compilation, or we are compiling system server
// do not bother to open the profiles; we won't be using them.
if (!profile_guided || (pkgname[0] == '*')) {
- return Dex2oatFileWrapper();
+ return UniqueFile();
}
// If this is a secondary dex path which is public do not open the profile.
@@ -1407,7 +999,7 @@ Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
// compiling with a public profile from the .dm file the PackageManager will
// set is_public toghether with the profile guided compilation.
if (is_secondary_dex && is_public) {
- return Dex2oatFileWrapper();
+ return UniqueFile();
}
// Open reference profile in read only mode as dex2oat does not get write permissions.
@@ -1417,33 +1009,28 @@ Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
} else {
if (profile_name == nullptr) {
// This path is taken for system server re-compilation lunched from ZygoteInit.
- return Dex2oatFileWrapper();
+ return UniqueFile();
} else {
location = profile_name;
}
}
- unique_fd ufd = open_reference_profile(uid, pkgname, location, /*read_write*/false,
- is_secondary_dex);
- const auto& cleanup = [pkgname, location, is_secondary_dex]() {
- clear_reference_profile(pkgname, location, is_secondary_dex);
- };
- return Dex2oatFileWrapper(ufd.release(), cleanup);
+ return open_reference_profile_as_unique_file(uid, pkgname, location, /*read_write*/false,
+ is_secondary_dex);
}
-// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
-// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
+// Opens the vdex files and assigns the input fd to in_vdex_wrapper and the output fd to
+// out_vdex_wrapper. Returns true for success or false in case of errors.
bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path, int dexopt_needed,
const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
- bool profile_guided, Dex2oatFileWrapper* in_vdex_wrapper_fd,
- Dex2oatFileWrapper* out_vdex_wrapper_fd) {
- CHECK(in_vdex_wrapper_fd != nullptr);
- CHECK(out_vdex_wrapper_fd != nullptr);
+ bool profile_guided, UniqueFile* in_vdex_wrapper,
+ UniqueFile* out_vdex_wrapper) {
+ CHECK(in_vdex_wrapper != nullptr);
+ CHECK(out_vdex_wrapper != nullptr);
// Open the existing VDEX. We do this before creating the new output VDEX, which will
// unlink the old one.
char in_odex_path[PKG_PATH_MAX];
int dexopt_action = abs(dexopt_needed);
bool is_odex_location = dexopt_needed < 0;
- std::string in_vdex_path_str;
// Infer the name of the output VDEX.
const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
@@ -1465,7 +1052,7 @@ bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path,
} else {
path = out_oat_path;
}
- in_vdex_path_str = create_vdex_filename(path);
+ std::string in_vdex_path_str = create_vdex_filename(path);
if (in_vdex_path_str.empty()) {
ALOGE("installd cannot compute input vdex location for '%s'\n", path);
return false;
@@ -1483,13 +1070,15 @@ bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path,
!profile_guided;
if (update_vdex_in_place) {
// Open the file read-write to be able to update it.
- in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
- if (in_vdex_wrapper_fd->get() == -1) {
+ in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0),
+ in_vdex_path_str);
+ if (in_vdex_wrapper->fd() == -1) {
// If we failed to open the file, we cannot update it in place.
update_vdex_in_place = false;
}
} else {
- in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+ in_vdex_wrapper->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0),
+ in_vdex_path_str);
}
}
@@ -1498,22 +1087,24 @@ bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path,
if (update_vdex_in_place) {
// We unlink the file in case the invocation of dex2oat fails, to ensure we don't
// have bogus stale vdex files.
- out_vdex_wrapper_fd->reset(
- in_vdex_wrapper_fd->get(),
- [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
+ out_vdex_wrapper->reset(
+ in_vdex_wrapper->fd(),
+ out_vdex_path_str,
+ UnlinkIgnoreResult);
// Disable auto close for the in wrapper fd (it will be done when destructing the out
// wrapper).
- in_vdex_wrapper_fd->DisableAutoClose();
+ in_vdex_wrapper->DisableAutoClose();
} else {
- out_vdex_wrapper_fd->reset(
+ out_vdex_wrapper->reset(
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_wrapper_fd->get() < 0) {
+ out_vdex_path_str,
+ UnlinkIgnoreResult);
+ if (out_vdex_wrapper->fd() < 0) {
ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
return false;
}
}
- if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
+ if (!set_permissions_and_ownership(out_vdex_wrapper->fd(), is_public, uid,
out_vdex_path_str.c_str(), is_secondary_dex)) {
ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
return false;
@@ -1524,25 +1115,24 @@ bool open_vdex_files_for_dex2oat(const char* apk_path, const char* out_oat_path,
}
// Opens the output oat file for the given apk.
-// If successful it stores the output path into out_oat_path and returns true.
-Dex2oatFileWrapper open_oat_out_file(const char* apk_path, const char* oat_dir,
- bool is_public, int uid, const char* instruction_set, bool is_secondary_dex,
- char* out_oat_path) {
+UniqueFile open_oat_out_file(const char* apk_path, const char* oat_dir,
+ bool is_public, int uid, const char* instruction_set, bool is_secondary_dex) {
+ char out_oat_path[PKG_PATH_MAX];
if (!create_oat_out_path(apk_path, instruction_set, oat_dir, is_secondary_dex, out_oat_path)) {
- return Dex2oatFileWrapper();
+ return UniqueFile();
}
- const std::string out_oat_path_str(out_oat_path);
- Dex2oatFileWrapper wrapper_fd(
+ UniqueFile oat(
open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
- [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
- if (wrapper_fd.get() < 0) {
+ out_oat_path,
+ UnlinkIgnoreResult);
+ if (oat.fd() < 0) {
PLOG(ERROR) << "installd cannot open output during dexopt" << out_oat_path;
} else if (!set_permissions_and_ownership(
- wrapper_fd.get(), is_public, uid, out_oat_path, is_secondary_dex)) {
+ oat.fd(), is_public, uid, out_oat_path, is_secondary_dex)) {
ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
- wrapper_fd.reset(-1);
+ oat.reset();
}
- return wrapper_fd;
+ return oat;
}
// Creates RDONLY fds for oat and vdex files, if exist.
@@ -1578,23 +1168,6 @@ bool maybe_open_oat_and_vdex_file(const std::string& apk_path,
return true;
}
-// Updates the access times of out_oat_path based on those from apk_path.
-void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
- struct stat input_stat;
- memset(&input_stat, 0, sizeof(input_stat));
- if (stat(apk_path, &input_stat) != 0) {
- PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
- return;
- }
-
- struct utimbuf ut;
- ut.actime = input_stat.st_atime;
- ut.modtime = input_stat.st_mtime;
- if (utime(out_oat_path, &ut) != 0) {
- PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
- }
-}
-
// Runs (execv) dexoptanalyzer on the given arguments.
// The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
// If this is for a profile guided compilation, profile_was_updated will tell whether or not
@@ -1607,7 +1180,7 @@ class RunDexoptAnalyzer : public ExecVHelper {
int zip_fd,
const std::string& instruction_set,
const std::string& compiler_filter,
- bool profile_was_updated,
+ int profile_analysis_result,
bool downgrade,
const char* class_loader_context,
const std::string& class_loader_context_fds) {
@@ -1623,7 +1196,8 @@ class RunDexoptAnalyzer : public ExecVHelper {
std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
std::string isa_arg = "--isa=" + instruction_set;
std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
- const char* assume_profile_changed = "--assume-profile-changed";
+ std::string profile_analysis_arg = "--profile-analysis-result="
+ + std::to_string(profile_analysis_result);
const char* downgrade_flag = "--downgrade";
std::string class_loader_context_arg = "--class-loader-context=";
if (class_loader_context != nullptr) {
@@ -1645,9 +1219,8 @@ class RunDexoptAnalyzer : public ExecVHelper {
AddArg(vdex_fd_arg);
}
AddArg(zip_fd_arg);
- if (profile_was_updated) {
- AddArg(assume_profile_changed);
- }
+ AddArg(profile_analysis_arg);
+
if (downgrade) {
AddArg(downgrade_flag);
}
@@ -1658,6 +1231,14 @@ class RunDexoptAnalyzer : public ExecVHelper {
}
}
+ // On-device signing related. odsign sets the system property odsign.verification.success if
+ // AOT artifacts have the expected signatures.
+ const bool trust_art_apex_data_files =
+ ::android::base::GetBoolProperty("odsign.verification.success", false);
+ if (!trust_art_apex_data_files) {
+ AddRuntimeArg("-Xdeny-art-apex-data-files");
+ }
+
PrepareArgs(dexoptanalyzer_bin);
}
@@ -1790,10 +1371,12 @@ static SecondaryDexAccess check_secondary_dex_access(const std::string& dex_path
return kSecondaryDexAccessReadOk;
} else {
if (errno == ENOENT) {
- LOG(INFO) << "Secondary dex does not exist: " << dex_path;
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+ "Secondary dex does not exist: %s", dex_path.c_str());
return kSecondaryDexAccessDoesNotExist;
} else {
- PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not access secondary dex: %s (%d)", dex_path.c_str(), errno);
return errno == EACCES
? kSecondaryDexAccessPermissionError
: kSecondaryDexAccessIOError;
@@ -1978,7 +1561,8 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
// Validate the path structure.
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
}
@@ -2018,7 +1602,7 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
}
// Analyze profiles.
- bool profile_was_updated = analyze_profiles(uid, pkgname, dex_path,
+ int profile_analysis_result = analyze_profiles(uid, pkgname, dex_path,
/*is_secondary_dex*/true);
// Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
@@ -2029,7 +1613,8 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
oat_file_fd.get(),
zip_fd.get(),
instruction_set,
- compiler_filter, profile_was_updated,
+ compiler_filter,
+ profile_analysis_result,
downgrade,
class_loader_context,
join_fds(context_zip_fds));
@@ -2149,8 +1734,8 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
}
// Open the input file.
- unique_fd input_fd(open(dex_path, O_RDONLY, 0));
- if (input_fd.get() < 0) {
+ UniqueFile in_dex(open(dex_path, O_RDONLY, 0), dex_path);
+ if (in_dex.fd() < 0) {
*error_msg = StringPrintf("installd cannot open '%s' for input during dexopt", dex_path);
LOG(ERROR) << *error_msg;
return -1;
@@ -2164,19 +1749,19 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
}
// Create the output OAT file.
- char out_oat_path[PKG_PATH_MAX];
- Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
- instruction_set, is_secondary_dex, out_oat_path);
- if (out_oat_fd.get() < 0) {
+ UniqueFile out_oat = open_oat_out_file(dex_path, oat_dir, is_public, uid,
+ instruction_set, is_secondary_dex);
+ if (out_oat.fd() < 0) {
*error_msg = "Could not open out oat file.";
return -1;
}
// Open vdex files.
- Dex2oatFileWrapper in_vdex_fd;
- Dex2oatFileWrapper out_vdex_fd;
- if (!open_vdex_files_for_dex2oat(dex_path, out_oat_path, dexopt_needed, instruction_set,
- is_public, uid, is_secondary_dex, profile_guided, &in_vdex_fd, &out_vdex_fd)) {
+ UniqueFile in_vdex;
+ UniqueFile out_vdex;
+ if (!open_vdex_files_for_dex2oat(dex_path, out_oat.path().c_str(), dexopt_needed,
+ instruction_set, is_public, uid, is_secondary_dex, profile_guided, &in_vdex,
+ &out_vdex)) {
*error_msg = "Could not open vdex files.";
return -1;
}
@@ -2196,63 +1781,86 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
}
// Create a swap file if necessary.
- unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
+ unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat.path());
// Open the reference profile if needed.
- Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
+ UniqueFile reference_profile = maybe_open_reference_profile(
pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex);
- if (reference_profile_fd.get() == -1) {
+ if (reference_profile.fd() == -1) {
// We don't create an app image without reference profile since there is no speedup from
// loading it in that case and instead will be a small overhead.
generate_app_image = false;
}
// Create the app image file if needed.
- Dex2oatFileWrapper image_fd = maybe_open_app_image(
- out_oat_path, generate_app_image, is_public, uid, is_secondary_dex);
+ UniqueFile out_image = maybe_open_app_image(
+ out_oat.path(), generate_app_image, is_public, uid, is_secondary_dex);
- unique_fd dex_metadata_fd;
+ UniqueFile dex_metadata;
if (dex_metadata_path != nullptr) {
- dex_metadata_fd.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)));
- if (dex_metadata_fd.get() < 0) {
+ dex_metadata.reset(TEMP_FAILURE_RETRY(open(dex_metadata_path, O_RDONLY | O_NOFOLLOW)),
+ dex_metadata_path);
+ if (dex_metadata.fd() < 0) {
PLOG(ERROR) << "Failed to open dex metadata file " << dex_metadata_path;
}
}
+ std::string jitzygote_flag = server_configurable_flags::GetServerConfigurableFlag(
+ RUNTIME_NATIVE_BOOT_NAMESPACE,
+ ENABLE_JITZYGOTE_IMAGE,
+ /*default_value=*/ "");
+ bool use_jitzygote_image = jitzygote_flag == "true" || IsBootClassPathProfilingEnable();
+
+ // Decide whether to use dex2oat64.
+ bool use_dex2oat64 = false;
+ // Check whether the device even supports 64-bit ABIs.
+ if (!GetProperty("ro.product.cpu.abilist64", "").empty()) {
+ use_dex2oat64 = GetBoolProperty("dalvik.vm.dex2oat64.enabled", false);
+ }
+ const char* dex2oat_bin = select_execution_binary(
+ (use_dex2oat64 ? kDex2oat64Path : kDex2oat32Path),
+ (use_dex2oat64 ? kDex2oatDebug64Path : kDex2oatDebug32Path),
+ background_job_compile);
+
+ auto execv_helper = std::make_unique<ExecVHelper>();
+
LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
- RunDex2Oat runner(input_fd.get(),
- out_oat_fd.get(),
- in_vdex_fd.get(),
- out_vdex_fd.get(),
- image_fd.get(),
- dex_path,
- out_oat_path,
+ RunDex2Oat runner(dex2oat_bin, execv_helper.get());
+ runner.Initialize(out_oat,
+ out_vdex,
+ out_image,
+ in_dex,
+ in_vdex,
+ dex_metadata,
+ reference_profile,
+ class_loader_context,
+ join_fds(context_input_fds),
swap_fd.get(),
instruction_set,
compiler_filter,
debuggable,
boot_complete,
for_restore,
- background_job_compile,
- reference_profile_fd.get(),
- class_loader_context,
- join_fds(context_input_fds),
target_sdk_version,
enable_hidden_api_checks,
generate_compact_dex,
- dex_metadata_fd.get(),
+ use_jitzygote_image,
compilation_reason);
pid_t pid = fork();
if (pid == 0) {
+ // Need to set schedpolicy before dropping privileges
+ // for cgroup migration. See details at b/175178520.
+ SetDex2OatScheduling(boot_complete);
+
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- SetDex2OatScheduling(boot_complete);
- if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
- PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
+ if (flock(out_oat.fd(), LOCK_EX | LOCK_NB) != 0) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "flock(%s) failed",
+ out_oat.path().c_str());
_exit(DexoptReturnCodes::kFlock);
}
@@ -2269,13 +1877,11 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
}
}
- update_out_oat_access_times(dex_path, out_oat_path);
-
// We've been successful, don't delete output.
- out_oat_fd.SetCleanup(false);
- out_vdex_fd.SetCleanup(false);
- image_fd.SetCleanup(false);
- reference_profile_fd.SetCleanup(false);
+ out_oat.DisableCleanup();
+ out_vdex.DisableCleanup();
+ out_image.DisableCleanup();
+ reference_profile.DisableCleanup();
return 0;
}
@@ -2325,7 +1931,7 @@ enum ReconcileSecondaryDexResult {
// out_secondary_dex_exists will be set to false.
bool reconcile_secondary_dex_file(const std::string& dex_path,
const std::string& pkgname, int uid, const std::vector<std::string>& isas,
- const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+ const std::optional<std::string>& volume_uuid, int storage_flag,
/*out*/bool* out_secondary_dex_exists) {
*out_secondary_dex_exists = false; // start by assuming the file does not exist.
if (isas.size() == 0) {
@@ -2346,10 +1952,11 @@ bool reconcile_secondary_dex_file(const std::string& dex_path,
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+ const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr;
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(kReconcileSecondaryDexValidationError);
}
@@ -2362,7 +1969,8 @@ bool reconcile_secondary_dex_file(const std::string& dex_path,
case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
default:
- LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Unexpected result from check_secondary_dex_access: %d", access_check);
_exit(kReconcileSecondaryDexValidationError);
}
@@ -2375,7 +1983,7 @@ bool reconcile_secondary_dex_file(const std::string& dex_path,
std::string error_msg;
if (!create_secondary_dex_oat_layout(
dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
- LOG(ERROR) << error_msg;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "%s", error_msg.c_str());
_exit(kReconcileSecondaryDexValidationError);
}
@@ -2402,7 +2010,8 @@ bool reconcile_secondary_dex_file(const std::string& dex_path,
result = rmdir_if_empty(oat_dir) && result;
}
if (!result) {
- PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
}
_exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
}
@@ -2447,11 +2056,11 @@ bool reconcile_secondary_dex_file(const std::string& dex_path,
// the app.
// For any other errors (e.g. if any of the parameters are invalid) returns false.
bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkgname, int uid,
- const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+ const std::optional<std::string>& volume_uuid, int storage_flag,
std::vector<uint8_t>* out_secondary_dex_hash) {
out_secondary_dex_hash->clear();
- const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+ const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr;
if (storage_flag != FLAG_STORAGE_CE && storage_flag != FLAG_STORAGE_DE) {
LOG(ERROR) << "hash_secondary_dex_file called with invalid storage_flag: "
@@ -2475,7 +2084,8 @@ bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkg
pipe_read.reset();
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(DexoptReturnCodes::kHashValidatePath);
}
@@ -2486,6 +2096,8 @@ bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkg
_exit(0);
}
PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Failed to open secondary dex %s: %d", dex_path.c_str(), errno);
_exit(DexoptReturnCodes::kHashOpenPath);
}
@@ -2498,7 +2110,8 @@ bool hash_secondary_dex_file(const std::string& dex_path, const std::string& pkg
if (bytes_read == 0) {
break;
} else if (bytes_read == -1) {
- PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Failed to read secondary dex %s: %d", dex_path.c_str(), errno);
_exit(DexoptReturnCodes::kHashReadDex);
}
@@ -2557,8 +2170,9 @@ static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
{
struct stat s;
if (stat(b_path.c_str(), &s) != 0) {
- // Silently ignore for now. The service calling this isn't smart enough to understand
- // lack of artifacts at the moment.
+ // Ignore for now. The service calling this isn't smart enough to
+ // understand lack of artifacts at the moment.
+ LOG(VERBOSE) << "A/B artifact " << b_path << " does not exist!";
return false;
}
if (!S_ISREG(s.st_mode)) {
@@ -2648,38 +2262,52 @@ bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_
return success;
}
-bool delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+int64_t delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
// Delete the oat/odex file.
char out_path[PKG_PATH_MAX];
if (!create_oat_out_path(apk_path, instruction_set, oat_dir,
/*is_secondary_dex*/false, out_path)) {
- return false;
+ LOG(ERROR) << "Cannot create apk path for " << apk_path;
+ return -1;
}
// In case of a permission failure report the issue. Otherwise just print a warning.
- auto unlink_and_check = [](const char* path) -> bool {
- int result = unlink(path);
- if (result != 0) {
- if (errno == EACCES || errno == EPERM) {
+ auto unlink_and_check = [](const char* path) -> int64_t {
+ struct stat file_stat;
+ if (stat(path, &file_stat) != 0) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Could not stat " << path;
+ return -1;
+ }
+ return 0;
+ }
+
+ if (unlink(path) != 0) {
+ if (errno != ENOENT) {
PLOG(ERROR) << "Could not unlink " << path;
- return false;
+ return -1;
}
- PLOG(WARNING) << "Could not unlink " << path;
}
- return true;
+ return static_cast<int64_t>(file_stat.st_size);
};
// Delete the oat/odex file.
- bool return_value_oat = unlink_and_check(out_path);
+ int64_t return_value_oat = unlink_and_check(out_path);
// Derive and delete the app image.
- bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
+ int64_t return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
// Derive and delete the vdex file.
- bool return_value_vdex = unlink_and_check(create_vdex_filename(out_path).c_str());
+ int64_t return_value_vdex = unlink_and_check(create_vdex_filename(out_path).c_str());
+
+ // Report result
+ if (return_value_oat == -1
+ || return_value_art == -1
+ || return_value_vdex == -1) {
+ return -1;
+ }
- // Report success.
- return return_value_oat && return_value_art && return_value_vdex;
+ return return_value_oat + return_value_art + return_value_vdex;
}
static bool is_absolute_path(const std::string& path) {
@@ -2914,7 +2542,7 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name,
for (size_t i = 0; i < profiles.size(); ) {
std::vector<unique_fd> profiles_fd;
for (size_t k = 0; k < kAggregationBatchSize && i < profiles.size(); k++, i++) {
- unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY);
+ unique_fd fd = open_profile(AID_SYSTEM, profiles[i], O_RDONLY, /*mode=*/ 0);
if (fd.get() >= 0) {
profiles_fd.push_back(std::move(fd));
}
@@ -2978,7 +2606,7 @@ bool prepare_app_profile(const std::string& package_name,
appid_t app_id,
const std::string& profile_name,
const std::string& code_path,
- const std::unique_ptr<std::string>& dex_metadata) {
+ const std::optional<std::string>& dex_metadata) {
// Prepare the current profile.
std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name,
/*is_secondary_dex*/ false);
@@ -2989,7 +2617,7 @@ bool prepare_app_profile(const std::string& package_name,
}
// Check if we need to install the profile from the dex metadata.
- if (dex_metadata == nullptr) {
+ if (!dex_metadata) {
return true;
}