diff options
-rw-r--r-- | dexoptanalyzer/dexoptanalyzer.cc | 11 | ||||
-rw-r--r-- | libartbase/base/file_utils.cc | 119 | ||||
-rw-r--r-- | libartbase/base/file_utils.h | 10 | ||||
-rw-r--r-- | test/dexpreopt/dexpreopt_test.cc | 10 |
4 files changed, 116 insertions, 34 deletions
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc index ef4315739b..b182f68a7f 100644 --- a/dexoptanalyzer/dexoptanalyzer.cc +++ b/dexoptanalyzer/dexoptanalyzer.cc @@ -239,11 +239,16 @@ class DexoptAnalyzer final { // If we don't receive the image, try to use the default one. // Tests may specify a different image (e.g. core image). std::string error_msg; - image_ = GetDefaultBootImageLocation(&error_msg); - + std::string android_root = GetAndroidRootSafe(&error_msg); + if (android_root.empty()) { + LOG(ERROR) << error_msg; + Usage("--image unspecified and ANDROID_ROOT not set."); + } + image_ = GetDefaultBootImageLocationSafe( + android_root, /*deny_art_apex_data_files=*/false, &error_msg); if (image_.empty()) { LOG(ERROR) << error_msg; - Usage("--image unspecified and ANDROID_ROOT not set or image file does not exist."); + Usage("--image unspecified and failed to get default boot image location."); } } } diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc index 239628978e..bf0422a954 100644 --- a/libartbase/base/file_utils.cc +++ b/libartbase/base/file_utils.cc @@ -40,6 +40,7 @@ #include <memory> #include <sstream> +#include <vector> #include "android-base/file.h" #include "android-base/logging.h" @@ -50,6 +51,7 @@ #include "base/os.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #if defined(__APPLE__) #include <crt_externs.h> @@ -78,6 +80,7 @@ static constexpr const char* kAndroidConscryptRootEnvVar = "ANDROID_CONSCRYPT_RO static constexpr const char* kAndroidI18nRootEnvVar = "ANDROID_I18N_ROOT"; static constexpr const char* kApexDefaultPath = "/apex/"; static constexpr const char* kArtApexDataEnvVar = "ART_APEX_DATA"; +static constexpr const char* kBootImageStem = "boot"; // Get the "root" directory containing the "lib" directory where this instance // of the libartbase library (which contains `GetRootContainingLibartbase`) is @@ -298,10 +301,73 @@ std::string GetPrebuiltPrimaryBootImageDir() { return GetPrebuiltPrimaryBootImageDir(android_root); } -std::string GetDefaultBootImageLocation(const std::string& android_root, - bool deny_art_apex_data_files) { +static std::string GetFirstMainlineFrameworkLibraryName(std::string* error_msg) { + const char* env_bcp = getenv("BOOTCLASSPATH"); + const char* env_dex2oat_bcp = getenv("DEX2OATBOOTCLASSPATH"); + if (env_bcp == nullptr || env_dex2oat_bcp == nullptr) { + *error_msg = "BOOTCLASSPATH and DEX2OATBOOTCLASSPATH must not be empty"; + return ""; + } + + // DEX2OATBOOTCLASSPATH contains core libraries and framework libraries. We used to only compile + // those libraries. Now we compile mainline framework libraries as well, and we have repurposed + // DEX2OATBOOTCLASSPATH to indicate the separation between mainline framework libraries and other + // libraries. + std::string_view mainline_bcp(env_bcp); + if (!android::base::ConsumePrefix(&mainline_bcp, env_dex2oat_bcp)) { + *error_msg = "DEX2OATBOOTCLASSPATH must be a prefix of BOOTCLASSPATH"; + return ""; + } + + std::vector<std::string_view> mainline_bcp_jars; + Split(mainline_bcp, ':', &mainline_bcp_jars); + if (mainline_bcp_jars.empty()) { + *error_msg = "No mainline framework library found"; + return ""; + } + + std::string jar_name = android::base::Basename(mainline_bcp_jars[0]); + + std::string_view library_name(jar_name); + if (!android::base::ConsumeSuffix(&library_name, ".jar")) { + *error_msg = "Invalid mainline framework jar: " + jar_name; + return ""; + } + + return std::string(library_name); +} + +// Returns true when no error occurs, even if the extension doesn't exist. +static bool MaybeAppendBootImageMainlineExtension(const std::string& android_root, + /*inout*/ std::string* location, + /*out*/ std::string* error_msg) { + if (!kIsTargetAndroid) { + return true; + } + // Due to how the runtime determines the mapping between boot images and bootclasspath jars, the + // name of the boot image extension must be in the format of + // `<primary-boot-image-stem>-<first-library-name>.art`. + std::string library_name = GetFirstMainlineFrameworkLibraryName(error_msg); + if (library_name.empty()) { + return false; + } + std::string mainline_extension_location = StringPrintf( + "%s/framework/%s-%s.art", android_root.c_str(), kBootImageStem, library_name.c_str()); + std::string mainline_extension_path = + GetSystemImageFilename(mainline_extension_location.c_str(), kRuntimeISA); + if (!OS::FileExists(mainline_extension_path.c_str(), /*check_file_type=*/true)) { + // This is expected when the ART module is preloaded on an old source tree that doesn't + // dexpreopt mainline BCP jars, so it shouldn't be considered as an error. + return true; + } + *location += ":" + mainline_extension_location; + return true; +} + +std::string GetDefaultBootImageLocationSafe(const std::string& android_root, + bool deny_art_apex_data_files, + std::string* error_msg) { constexpr static const char* kEtcBootImageProf = "etc/boot-image.prof"; - constexpr static const char* kBootImageStem = "boot"; constexpr static const char* kMinimalBootImageStem = "boot_minimal"; // If an update for the ART module has been been installed, a single boot image for the entire @@ -347,28 +413,37 @@ std::string GetDefaultBootImageLocation(const std::string& android_root, PLOG(ERROR) << "Minimal boot image check failed, could not stat: " << boot_image_filename; } } - // Boot image consists of two parts: + + // Boot image consists of three parts: // - the primary boot image (contains the Core Libraries) - // - the boot image extensions (contains framework libraries) - // Typically "/apex/com.android.art/javalib/boot.art!/apex/com.android.art/etc/boot-image.prof: - // /system/framework/boot-framework.art!/system/etc/boot-image.prof". - return StringPrintf("%s/%s.art!%s/%s:%s/framework/%s-framework.art!%s/%s", - GetPrebuiltPrimaryBootImageDir(android_root).c_str(), - kBootImageStem, - kAndroidArtApexDefaultPath, - kEtcBootImageProf, - android_root.c_str(), - kBootImageStem, - android_root.c_str(), - kEtcBootImageProf); -} - -std::string GetDefaultBootImageLocation(std::string* error_msg) { - std::string android_root = GetAndroidRootSafe(error_msg); - if (android_root.empty()) { + // - the boot image framework extension (contains framework libraries) + // - the boot image mainline extension (contains mainline framework libraries) + // Typically "/system/framework/boot.art!/apex/com.android.art/etc/boot-image.prof: + // /system/framework/boot-framework.art!/system/etc/boot-image.prof: + // /system/framework/boot-framework-adservices.art". + + std::string location = StringPrintf("%s/%s.art!%s/%s:%s/framework/%s-framework.art!%s/%s", + GetPrebuiltPrimaryBootImageDir(android_root).c_str(), + kBootImageStem, + kAndroidArtApexDefaultPath, + kEtcBootImageProf, + android_root.c_str(), + kBootImageStem, + android_root.c_str(), + kEtcBootImageProf); + if (!MaybeAppendBootImageMainlineExtension(android_root, &location, error_msg)) { return ""; } - return GetDefaultBootImageLocation(android_root, /*deny_art_apex_data_files=*/false); + return location; +} + +std::string GetDefaultBootImageLocation(const std::string& android_root, + bool deny_art_apex_data_files) { + std::string error_msg; + std::string location = + GetDefaultBootImageLocationSafe(android_root, deny_art_apex_data_files, &error_msg); + CHECK(!location.empty()) << error_msg; + return location; } std::string GetJitZygoteBootImageLocation() { diff --git a/libartbase/base/file_utils.h b/libartbase/base/file_utils.h index f539f5fd55..a8fb0064a9 100644 --- a/libartbase/base/file_utils.h +++ b/libartbase/base/file_utils.h @@ -78,11 +78,13 @@ std::string GetArtApexData(); // generated at build time). std::string GetPrebuiltPrimaryBootImageDir(); -// Returns the default boot image location (ANDROID_ROOT/framework/boot.art). -// Returns an empty string if ANDROID_ROOT is not set. -std::string GetDefaultBootImageLocation(std::string* error_msg); - // Returns the default boot image location, based on the passed `android_root`. +// Returns an empty string if an error occurs. +std::string GetDefaultBootImageLocationSafe(const std::string& android_root, + bool deny_art_apex_data_files, + std::string* error_msg); + +// Same as above, but fails if an error occurs. std::string GetDefaultBootImageLocation(const std::string& android_root, bool deny_art_apex_data_files); diff --git a/test/dexpreopt/dexpreopt_test.cc b/test/dexpreopt/dexpreopt_test.cc index 55593eae66..3fb2730cc1 100644 --- a/test/dexpreopt/dexpreopt_test.cc +++ b/test/dexpreopt/dexpreopt_test.cc @@ -46,7 +46,7 @@ namespace art { -using ::testing::IsSubsetOf; +using ::testing::IsSupersetOf; constexpr const char* kZygote32 = "zygote"; constexpr const char* kZygote64 = "zygote64"; @@ -95,9 +95,9 @@ android::base::Result<std::vector<std::pair<std::string, InstructionSet>>> GetZy } android::base::Result<std::vector<std::string>> GetZygoteExpectedArtifacts(InstructionSet isa) { - std::vector<std::string> jars = GetListFromEnv("DEX2OATBOOTCLASSPATH"); + std::vector<std::string> jars = GetListFromEnv("BOOTCLASSPATH"); if (jars.empty()) { - return Errorf("Environment variable `DEX2OATBOOTCLASSPATH` is not defined or empty"); + return Errorf("Environment variable `BOOTCLASSPATH` is not defined or empty"); } std::string art_root = GetArtRoot(); std::string android_root = GetAndroidRoot(); @@ -218,7 +218,7 @@ TEST(DexpreoptTest, ForZygote) { GetZygoteMappedOatFiles(zygote_name); ASSERT_RESULT_OK(mapped_oat_files); - EXPECT_THAT(expected_artifacts.value(), IsSubsetOf(mapped_oat_files.value())); + EXPECT_THAT(mapped_oat_files.value(), IsSupersetOf(expected_artifacts.value())); } } @@ -236,7 +236,7 @@ TEST(DexpreoptTest, ForSystemServer) { GetSystemServerArtifactsMappedOdexes(); ASSERT_RESULT_OK(mapped_odexes); - EXPECT_THAT(expected_artifacts.value(), IsSubsetOf(mapped_odexes.value())); + EXPECT_THAT(mapped_odexes.value(), IsSupersetOf(expected_artifacts.value())); } } // namespace art |