diff options
-rw-r--r-- | dex2oat/dex2oat_test.cc | 25 | ||||
-rw-r--r-- | libartbase/base/common_art_test.cc | 9 | ||||
-rw-r--r-- | libdexfile/dex/art_dex_file_loader.cc | 82 | ||||
-rw-r--r-- | libdexfile/dex/art_dex_file_loader.h | 27 | ||||
-rw-r--r-- | libdexfile/dex/art_dex_file_loader_test.cc | 65 | ||||
-rw-r--r-- | libdexfile/dex/dex_file.cc | 2 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_loader.cc | 69 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_loader.h | 48 | ||||
-rw-r--r-- | odrefresh/odrefresh.cc | 21 | ||||
-rw-r--r-- | odrefresh/odrefresh_main.cc | 2 | ||||
-rw-r--r-- | runtime/class_loader_context.cc | 53 | ||||
-rw-r--r-- | runtime/class_loader_context_test.cc | 90 | ||||
-rw-r--r-- | runtime/dex2oat_environment_test.h | 11 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 96 | ||||
-rw-r--r-- | runtime/oat.h | 4 | ||||
-rw-r--r-- | runtime/oat_file.h | 6 | ||||
-rw-r--r-- | runtime/oat_file_assistant.cc | 82 | ||||
-rw-r--r-- | runtime/oat_file_assistant.h | 12 | ||||
-rw-r--r-- | runtime/oat_file_assistant_context.cc | 34 | ||||
-rw-r--r-- | runtime/runtime.cc | 9 |
20 files changed, 367 insertions, 380 deletions
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index be442075e4..56d14a7143 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -19,6 +19,7 @@ #include <algorithm> #include <iterator> +#include <optional> #include <regex> #include <sstream> #include <string> @@ -1089,9 +1090,11 @@ TEST_F(Dex2oatClassLoaderContextTest, ContextWithTheSourceDexFiles) { TEST_F(Dex2oatClassLoaderContextTest, ContextWithOtherDexFiles) { std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Nested"); + uint32_t expected_checksum = DexFileLoader::GetMultiDexChecksum(dex_files); + std::string context = "PCL[" + dex_files[0]->GetLocation() + "]"; - std::string expected_classpath_key = "PCL[" + dex_files[0]->GetLocation() + "*" + - std::to_string(dex_files[0]->GetLocationChecksum()) + "]"; + std::string expected_classpath_key = + "PCL[" + dex_files[0]->GetLocation() + "*" + std::to_string(expected_checksum) + "]"; RunTest(context.c_str(), expected_classpath_key.c_str(), true); } @@ -2215,21 +2218,9 @@ TEST_F(Dex2oatClassLoaderContextTest, StoredClassLoaderContext) { const std::string odex_location = out_dir + "/base.odex"; const std::string valid_context = "PCL[" + dex_files[0]->GetLocation() + "]"; const std::string stored_context = "PCL[/system/not_real_lib.jar]"; - std::string expected_stored_context = "PCL["; - size_t index = 1; - for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { - const bool is_first = index == 1u; - if (!is_first) { - expected_stored_context += ":"; - } - expected_stored_context += "/system/not_real_lib.jar"; - if (!is_first) { - expected_stored_context += "!classes" + std::to_string(index) + ".dex"; - } - expected_stored_context += "*" + std::to_string(dex_file->GetLocationChecksum()); - ++index; - } - expected_stored_context += "]"; + uint32_t checksum = DexFileLoader::GetMultiDexChecksum(dex_files); + std::string expected_stored_context = + "PCL[/system/not_real_lib.jar*" + std::to_string(checksum) + "]"; // The class path should not be valid and should fail being stored. EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"), odex_location, diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc index db0e1c157f..e83cc0d967 100644 --- a/libartbase/base/common_art_test.cc +++ b/libartbase/base/common_art_test.cc @@ -582,13 +582,8 @@ std::string CommonArtTestImpl::CreateClassPath( std::string CommonArtTestImpl::CreateClassPathWithChecksums( const std::vector<std::unique_ptr<const DexFile>>& dex_files) { CHECK(!dex_files.empty()); - std::string classpath = dex_files[0]->GetLocation() + "*" + - std::to_string(dex_files[0]->GetLocationChecksum()); - for (size_t i = 1; i < dex_files.size(); i++) { - classpath += ":" + dex_files[i]->GetLocation() + "*" + - std::to_string(dex_files[i]->GetLocationChecksum()); - } - return classpath; + uint32_t checksum = DexFileLoader::GetMultiDexChecksum(dex_files); + return dex_files[0]->GetLocation() + "*" + std::to_string(checksum); } CommonArtTestImpl::ForkAndExecResult CommonArtTestImpl::ForkAndExec( diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc index ac52ca04e3..056d2fb261 100644 --- a/libdexfile/dex/art_dex_file_loader.cc +++ b/libdexfile/dex/art_dex_file_loader.cc @@ -37,88 +37,6 @@ namespace art { -using android::base::StringPrintf; - -bool ArtDexFileLoader::GetMultiDexChecksums(const char* filename, - std::vector<uint32_t>* checksums, - std::vector<std::string>* dex_locations, - std::string* error_msg, - int zip_fd, - bool* zip_file_only_contains_uncompressed_dex) { - CHECK(checksums != nullptr); - uint32_t magic; - - File fd; - if (zip_fd != -1) { - if (ReadMagicAndReset(zip_fd, &magic, error_msg)) { - fd = File(DupCloexec(zip_fd), /* check_usage= */ false); - } - } else { - fd = OpenAndReadMagic(filename, &magic, error_msg); - } - if (fd.Fd() == -1) { - DCHECK(!error_msg->empty()); - return false; - } - if (IsZipMagic(magic)) { - std::unique_ptr<ZipArchive> zip_archive( - ZipArchive::OpenFromFd(fd.Release(), filename, error_msg)); - if (zip_archive.get() == nullptr) { - *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename, - error_msg->c_str()); - return false; - } - - if (zip_file_only_contains_uncompressed_dex != nullptr) { - // Start by assuming everything is uncompressed. - *zip_file_only_contains_uncompressed_dex = true; - } - - uint32_t idx = 0; - std::string zip_entry_name = GetMultiDexClassesDexName(idx); - std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg)); - if (zip_entry.get() == nullptr) { - // A zip file with no dex code should be accepted. It's likely a config split APK, which we - // are currently passing from higher levels. - VLOG(dex) << StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", - filename, - zip_entry_name.c_str(), - error_msg->c_str()); - return true; - } - - do { - if (zip_file_only_contains_uncompressed_dex != nullptr) { - if (!(zip_entry->IsUncompressed() && zip_entry->IsAlignedTo(alignof(DexFile::Header)))) { - *zip_file_only_contains_uncompressed_dex = false; - } - } - checksums->push_back(zip_entry->GetCrc32()); - dex_locations->push_back(GetMultiDexLocation(idx, filename)); - zip_entry_name = GetMultiDexClassesDexName(++idx); - zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg)); - } while (zip_entry.get() != nullptr); - return true; - } - if (IsMagicValid(magic)) { - ArtDexFileLoader loader(fd.Release(), filename); - std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!loader.Open(/* verify= */ false, - /* verify_checksum= */ false, - error_msg, - &dex_files)) { - return false; - } - for (auto& dex_file : dex_files) { - checksums->push_back(dex_file->GetHeader().checksum_); - dex_locations->push_back(dex_file->GetLocation()); - } - return true; - } - *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename); - return false; -} - std::unique_ptr<const DexFile> ArtDexFileLoader::Open( const uint8_t* base, size_t size, diff --git a/libdexfile/dex/art_dex_file_loader.h b/libdexfile/dex/art_dex_file_loader.h index 9f2ae82e72..2fbc2cb794 100644 --- a/libdexfile/dex/art_dex_file_loader.h +++ b/libdexfile/dex/art_dex_file_loader.h @@ -36,31 +36,8 @@ class ZipArchive; // Class that is used to open dex files and deal with corresponding multidex and location logic. class ArtDexFileLoader : public DexFileLoader { public: - using DexFileLoader::DexFileLoader; - virtual ~ArtDexFileLoader() { } - - // Returns the checksums of a file for comparison with GetLocationChecksum(). - // For .dex files, this is the single header checksum. - // For zip files, this is the zip entry CRC32 checksum for classes.dex and - // each additional multidex entry classes2.dex, classes3.dex, etc. - // If a valid zip_fd is provided the file content will be read directly from - // the descriptor and `filename` will be used as alias for error logging. If - // zip_fd is -1, the method will try to open the `filename` and read the - // content from it. - // - // The dex_locations vector will be populated with the corresponding multidex - // locations. - // - // Return true if the checksums could be found, false otherwise. - static bool GetMultiDexChecksums(const char* filename, - std::vector<uint32_t>* checksums, - std::vector<std::string>* dex_locations, - std::string* error_msg, - int zip_fd = -1, - bool* only_contains_uncompressed_dex = nullptr); - - // Don't shadow overloads from base class. - using DexFileLoader::Open; + using DexFileLoader::DexFileLoader; // Use constructors from base class. + using DexFileLoader::Open; // Don't shadow overloads from base class. // Old signature preserved for app-compat. std::unique_ptr<const DexFile> Open(const uint8_t* base, diff --git a/libdexfile/dex/art_dex_file_loader_test.cc b/libdexfile/dex/art_dex_file_loader_test.cc index d8911ece78..4663a02ff0 100644 --- a/libdexfile/dex/art_dex_file_loader_test.cc +++ b/libdexfile/dex/art_dex_file_loader_test.cc @@ -19,6 +19,8 @@ #include <sys/mman.h> #include <memory> +#include <optional> +#include <vector> #include "base/common_art_test.h" #include "base/mem_map.h" @@ -29,8 +31,8 @@ #include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/descriptors_names.h" -#include "dex/dex_file.h" #include "dex/dex_file-inl.h" +#include "dex/dex_file.h" #include "dex/dex_file_loader.h" namespace art { @@ -95,65 +97,50 @@ TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) { } TEST_F(ArtDexFileLoaderTest, GetChecksum) { - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations; + std::optional<uint32_t> checksum; std::string error_msg; - EXPECT_TRUE(ArtDexFileLoader::GetMultiDexChecksums( - GetLibCoreDexFileNames()[0].c_str(), &checksums, &dex_locations, &error_msg)) - << error_msg; - ASSERT_EQ(1U, checksums.size()); - ASSERT_EQ(1U, dex_locations.size()); - EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]); - EXPECT_EQ(java_lang_dex_file_->GetLocation(), dex_locations[0]); + ArtDexFileLoader dex_loader(GetLibCoreDexFileNames()[0]); + ASSERT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; + ASSERT_TRUE(checksum.has_value()); + + std::vector<const DexFile*> dex_files{java_lang_dex_file_}; + uint32_t expected_checksum = DexFileLoader::GetMultiDexChecksum(dex_files); + EXPECT_EQ(expected_checksum, checksum.value()); } -TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksums) { +TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksum) { std::string error_msg; - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations; + std::optional<uint32_t> checksum; std::string multidex_file = GetTestDexFileName("MultiDex"); - EXPECT_TRUE(ArtDexFileLoader::GetMultiDexChecksums( - multidex_file.c_str(), &checksums, &dex_locations, &error_msg)) - << error_msg; + ArtDexFileLoader dex_loader(multidex_file); + EXPECT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex"); ASSERT_EQ(2U, dexes.size()); - ASSERT_EQ(2U, checksums.size()); - ASSERT_EQ(2U, dex_locations.size()); + ASSERT_TRUE(checksum.has_value()); + uint32_t expected_checksum = DexFileLoader::GetMultiDexChecksum(dexes); EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str())); - EXPECT_EQ(dexes[0]->GetLocation(), dex_locations[0]); - EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]); - EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str())); - EXPECT_EQ(dexes[1]->GetLocation(), dex_locations[1]); - EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]); + EXPECT_EQ(expected_checksum, checksum.value()); } TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksumsEmptyZip) { std::string error_msg; - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations; + std::optional<uint32_t> checksum; std::string multidex_file = GetTestDexFileName("MainEmptyUncompressed"); - EXPECT_TRUE(ArtDexFileLoader::GetMultiDexChecksums( - multidex_file.c_str(), &checksums, &dex_locations, &error_msg)) - << error_msg; - - EXPECT_EQ(dex_locations.size(), 0); - EXPECT_EQ(checksums.size(), 0); + ArtDexFileLoader dex_loader(multidex_file); + EXPECT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; + EXPECT_FALSE(checksum.has_value()); } TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksumsDexFile) { std::string error_msg; - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations; + std::optional<uint32_t> checksum; std::string multidex_file = GetTestDexFileName("VerifierDeps"); // This is a .dex file. - EXPECT_TRUE(ArtDexFileLoader::GetMultiDexChecksums( - multidex_file.c_str(), &checksums, &dex_locations, &error_msg)) - << error_msg; - - EXPECT_EQ(dex_locations.size(), 1); - EXPECT_EQ(checksums.size(), 1); + DexFileLoader loader(multidex_file); + EXPECT_TRUE(loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; + EXPECT_TRUE(checksum.has_value()); } TEST_F(ArtDexFileLoaderTest, ClassDefs) { diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index 080e381fe0..8179559337 100644 --- a/libdexfile/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc @@ -23,12 +23,12 @@ #include <zlib.h> #include <memory> +#include <optional> #include <ostream> #include <sstream> #include <type_traits> #include "android-base/stringprintf.h" - #include "base/enums.h" #include "base/hiddenapi_domain.h" #include "base/leb128.h" diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc index d375aac17b..9b54c15d9e 100644 --- a/libdexfile/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc @@ -148,9 +148,72 @@ std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) { } std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) { - return (index == 0) - ? dex_location - : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1); + if (index == 0) { + return dex_location; + } + DCHECK(!IsMultiDexLocation(dex_location)); + return StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1); +} + +bool DexFileLoader::GetMultiDexChecksum(std::optional<uint32_t>* checksum, + std::string* error_msg, + bool* only_contains_uncompressed_dex) { + CHECK(checksum != nullptr); + checksum->reset(); // Return nullopt for an empty zip archive. + + uint32_t magic; + if (!InitAndReadMagic(&magic, error_msg)) { + return false; + } + + if (IsZipMagic(magic)) { + std::unique_ptr<ZipArchive> zip_archive( + file_.has_value() ? + ZipArchive::OpenFromOwnedFd(file_->Fd(), location_.c_str(), error_msg) : + ZipArchive::OpenFromMemory( + root_container_->Begin(), root_container_->Size(), location_.c_str(), error_msg)); + if (zip_archive.get() == nullptr) { + DCHECK(!error_msg->empty()); + return false; + } + if (only_contains_uncompressed_dex != nullptr) { + *only_contains_uncompressed_dex = true; + } + for (size_t i = 0;; ++i) { + std::string name = GetMultiDexClassesDexName(i); + std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(name.c_str(), error_msg)); + if (zip_entry == nullptr) { + break; + } + if (only_contains_uncompressed_dex != nullptr) { + if (!(zip_entry->IsUncompressed() && zip_entry->IsAlignedTo(alignof(DexFile::Header)))) { + *only_contains_uncompressed_dex = false; + } + } + *checksum = checksum->value_or(kEmptyMultiDexChecksum) ^ zip_entry->GetCrc32(); + } + return true; + } + if (!MapRootContainer(error_msg)) { + return false; + } + const uint8_t* begin = root_container_->Begin(); + const uint8_t* end = root_container_->End(); + for (const uint8_t* ptr = begin; ptr < end;) { + const auto* header = reinterpret_cast<const DexFile::Header*>(ptr); + size_t size = dchecked_integral_cast<size_t>(end - ptr); + if (size < sizeof(*header) || !IsMagicValid(ptr)) { + *error_msg = StringPrintf("Invalid dex header: '%s'", filename_.c_str()); + return false; + } + if (size < header->file_size_) { + *error_msg = StringPrintf("Truncated dex file: '%s'", filename_.c_str()); + return false; + } + *checksum = checksum->value_or(kEmptyMultiDexChecksum) ^ header->checksum_; + ptr += header->file_size_; + } + return true; } std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) { diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h index 532445acf9..14cbdadaad 100644 --- a/libdexfile/dex/dex_file_loader.h +++ b/libdexfile/dex/dex_file_loader.h @@ -32,7 +32,6 @@ namespace art { class MemMap; class OatDexFile; -class ScopedTrace; class ZipArchive; enum class DexFileLoaderErrorCode { @@ -72,6 +71,53 @@ class DexFileLoader { // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else. static std::string GetMultiDexLocation(size_t index, const char* dex_location); + // Returns combined checksum of one or more dex files (one checksum for the whole multidex set). + // + // This uses the source path provided to DexFileLoader constructor. + // + // Returns false on error. Sets *checksum to nullopt for an empty set. + bool GetMultiDexChecksum(/*out*/ std::optional<uint32_t>* checksum, + /*out*/ std::string* error_msg, + /*out*/ bool* only_contains_uncompressed_dex = nullptr); + + // Returns combined checksum of one or more dex files (one checksum for the whole multidex set). + // + // This uses already open dex files. + // + // It starts iteration at index 'i', which must be a primary dex file, + // and it sets 'i' to the next primary dex file or to end of the array. + template <typename DexFilePtrVector> // array|vector<unique_ptr|DexFile|OatDexFile*>. + static uint32_t GetMultiDexChecksum(const DexFilePtrVector& dex_files, + /*inout*/ size_t* i) { + CHECK_LT(*i, dex_files.size()) << "No dex files"; + std::optional<uint32_t> checksum; + for (; *i < dex_files.size(); ++(*i)) { + const char* location = dex_files[*i]->GetLocation().c_str(); + if (!checksum.has_value()) { // First dex file. + CHECK(!IsMultiDexLocation(location)) << location; // Expect primary dex. + } else if (!IsMultiDexLocation(location)) { // Later dex file. + break; // Found another primary dex file, terminate iteration. + } + checksum = checksum.value_or(kEmptyMultiDexChecksum) ^ dex_files[*i]->GetLocationChecksum(); + } + CHECK(checksum.has_value()); + return checksum.value(); + } + + // Calculate checksum of dex files in a vector, starting at index 0. + // It will CHECK that the whole vector is consumed (i.e. there is just one primary dex file). + template <typename DexFilePtrVector> + static uint32_t GetMultiDexChecksum(const DexFilePtrVector& dex_files) { + size_t i = 0; + uint32_t checksum = GetMultiDexChecksum(dex_files, &i); + CHECK_EQ(i, dex_files.size()); + return checksum; + } + + // Non-zero initial value for multi-dex to catch bugs if multi-dex checksum is compared + // directly to DexFile::GetLocationChecksum without going through GetMultiDexChecksum. + static constexpr uint32_t kEmptyMultiDexChecksum = 1; + // Returns the canonical form of the given dex location. // // There are different flavors of "dex locations" as follows: diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc index 7bc1a04441..e925f856ef 100644 --- a/odrefresh/odrefresh.cc +++ b/odrefresh/odrefresh.cc @@ -316,25 +316,18 @@ std::vector<T> GenerateComponents( return {}; } - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations; + std::optional<uint32_t> checksum; std::string error_msg; - if (!ArtDexFileLoader::GetMultiDexChecksums( - actual_path.c_str(), &checksums, &dex_locations, &error_msg)) { - LOG(ERROR) << "Failed to get multi-dex checksums: " << error_msg; + ArtDexFileLoader dex_loader(actual_path); + if (!dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) { + LOG(ERROR) << "Failed to get multi-dex checksum: " << error_msg; return {}; } - std::ostringstream oss; - for (size_t i = 0; i < checksums.size(); ++i) { - if (i != 0) { - oss << ';'; - } - oss << StringPrintf("%08x", checksums[i]); - } - const std::string checksum = oss.str(); + const std::string checksum_str = + checksum.has_value() ? StringPrintf("%08x", checksum.value()) : std::string(); - Result<T> component = custom_generator(path, static_cast<uint64_t>(sb.st_size), checksum); + Result<T> component = custom_generator(path, static_cast<uint64_t>(sb.st_size), checksum_str); if (!component.ok()) { LOG(ERROR) << "Failed to generate component: " << component.error(); return {}; diff --git a/odrefresh/odrefresh_main.cc b/odrefresh/odrefresh_main.cc index c0e5adeec9..07ea060eec 100644 --- a/odrefresh/odrefresh_main.cc +++ b/odrefresh/odrefresh_main.cc @@ -27,6 +27,7 @@ #include "arch/instruction_set.h" #include "base/file_utils.h" #include "base/globals.h" +#include "base/mem_map.h" #include "base/stl_util.h" #include "odr_common.h" #include "odr_compilation_log.h" @@ -268,6 +269,7 @@ int main(int argc, char** argv) { if (!config.GetCompilationOsMode()) { android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM)); } + art::MemMap::Init(); // Needed by DexFileLoader. argv += n; argc -= n; diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc index 2f34f04f5b..1b14449684 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -17,6 +17,7 @@ #include "class_loader_context.h" #include <algorithm> +#include <optional> #include "android-base/file.h" #include "android-base/parseint.h" @@ -473,14 +474,12 @@ bool ClassLoaderContext::OpenDexFiles(const std::string& classpath_dir, } std::string error_msg; + ArtDexFileLoader dex_file_loader(fd, location); + std::optional<uint32_t> dex_checksum; if (only_read_checksums) { bool zip_file_only_contains_uncompress_dex; - if (!ArtDexFileLoader::GetMultiDexChecksums(location.c_str(), - &dex_checksums, - &dex_locations, - &error_msg, - fd, - &zip_file_only_contains_uncompress_dex)) { + if (!dex_file_loader.GetMultiDexChecksum( + &dex_checksum, &error_msg, &zip_file_only_contains_uncompress_dex)) { LOG(WARNING) << "Could not get dex checksums for location " << location << ", fd=" << fd; dex_files_state_ = kDexFilesOpenFailed; } @@ -489,8 +488,7 @@ bool ClassLoaderContext::OpenDexFiles(const std::string& classpath_dir, // contents. So pass true to verify_checksum. // We don't need to do structural dex file verification, we only need to // check the checksum, so pass false to verify. - size_t opened_dex_files_index = info->opened_dex_files.size(); - ArtDexFileLoader dex_file_loader(location.c_str(), fd, location); + size_t i = info->opened_dex_files.size(); if (!dex_file_loader.Open(/*verify=*/false, /*verify_checksum=*/true, &error_msg, @@ -498,13 +496,14 @@ bool ClassLoaderContext::OpenDexFiles(const std::string& classpath_dir, LOG(WARNING) << "Could not open dex files for location " << location << ", fd=" << fd; dex_files_state_ = kDexFilesOpenFailed; } else { - for (size_t k = opened_dex_files_index; k < info->opened_dex_files.size(); k++) { - std::unique_ptr<const DexFile>& dex = info->opened_dex_files[k]; - dex_locations.push_back(dex->GetLocation()); - dex_checksums.push_back(dex->GetLocationChecksum()); - } + dex_checksum = DexFileLoader::GetMultiDexChecksum(info->opened_dex_files, &i); + DCHECK_EQ(i, info->opened_dex_files.size()); } } + if (dex_checksum.has_value()) { + dex_locations.push_back(location); + dex_checksums.push_back(dex_checksum.value()); + } } // We finished opening the dex files from the classpath. @@ -518,8 +517,8 @@ bool ClassLoaderContext::OpenDexFiles(const std::string& classpath_dir, // Note that this will also remove the paths that could not be opened. info->original_classpath = std::move(info->classpath); DCHECK(dex_locations.size() == dex_checksums.size()); - info->classpath = dex_locations; - info->checksums = dex_checksums; + info->classpath = std::move(dex_locations); + info->checksums = std::move(dex_checksums); AddToWorkList(info, work_list); } @@ -692,16 +691,16 @@ void ClassLoaderContext::EncodeContextInternal(const ClassLoaderInfo& info, } } - for (size_t k = 0; k < info.opened_dex_files.size(); k++) { + for (size_t k = 0; k < info.opened_dex_files.size();) { const std::unique_ptr<const DexFile>& dex_file = info.opened_dex_files[k]; + uint32_t checksum = DexFileLoader::GetMultiDexChecksum(info.opened_dex_files, &k); + if (for_dex2oat) { // dex2oat only needs the base location. It cannot accept multidex locations. // So ensure we only add each file once. bool new_insert = seen_locations.insert(DexFileLoader::GetBaseLocation(dex_file->GetLocation())).second; - if (!new_insert) { - continue; - } + CHECK(new_insert); } std::string location = dex_file->GetLocation(); @@ -716,7 +715,7 @@ void ClassLoaderContext::EncodeContextInternal(const ClassLoaderInfo& info, // dex2oat does not need the checksums. if (!for_dex2oat) { - checksums.push_back(dex_file->GetLocationChecksum()); + checksums.push_back(checksum); } } EncodeClassPath(base_dir, locations, checksums, info.type, out); @@ -1155,13 +1154,17 @@ bool ClassLoaderContext::CreateInfoFromClassLoader( } // Now that `info` is in the chain, populate dex files. - for (const DexFile* dex_file : dex_files_loaded) { + for (size_t i = 0; i < dex_files_loaded.size();) { + const DexFile* dex_file = dex_files_loaded[i]; + uint32_t checksum = DexFileLoader::GetMultiDexChecksum(dex_files_loaded, &i); // Dex location of dex files loaded with InMemoryDexClassLoader is always bogus. // Use a magic value for the classpath instead. info->classpath.push_back((type == kInMemoryDexClassLoader) ? kInMemoryDexClassLoaderDexLocationMagic : dex_file->GetLocation()); - info->checksums.push_back(dex_file->GetLocationChecksum()); + info->checksums.push_back(checksum); + } + for (auto* dex_file : dex_files_loaded) { info->opened_dex_files.emplace_back(dex_file); } @@ -1477,8 +1480,10 @@ std::set<const DexFile*> ClassLoaderContext::CheckForDuplicateDexFiles( // in the Android world) - and as such we decide not to warn on them. ClassLoaderInfo* info = class_loader_chain_.get(); for (size_t k = 0; k < info->classpath.size(); k++) { - for (const DexFile* dex_file : dex_files_to_check) { - if (info->checksums[k] == dex_file->GetLocationChecksum() && + for (size_t i = 0; i < dex_files_to_check.size();) { + const DexFile* dex_file = dex_files_to_check[i]; + uint32_t checksum = DexFileLoader::GetMultiDexChecksum(dex_files_to_check, &i); + if (info->checksums[k] == checksum && AreDexNameMatching(info->classpath[k], dex_file->GetLocation())) { result.insert(dex_file); } diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc index ce9780a74e..98b8eed5d5 100644 --- a/runtime/class_loader_context_test.cc +++ b/runtime/class_loader_context_test.cc @@ -20,6 +20,8 @@ #include <filesystem> #include <fstream> +#include <optional> +#include <vector> #include "android-base/stringprintf.h" #include "android-base/strings.h" @@ -27,6 +29,7 @@ #include "art_method-alloc-inl.h" #include "base/dchecked_vector.h" #include "base/stl_util.h" +#include "base/string_view_cpp20.h" #include "class_linker.h" #include "class_root-inl.h" #include "common_runtime_test.h" @@ -184,41 +187,62 @@ class ClassLoaderContextTest : public CommonRuntimeTest { ClassLoaderContext::ContextDexFilesState::kDexFilesOpened); } ClassLoaderContext::ClassLoaderInfo& info = *context->GetParent(index); - ASSERT_EQ(all_dex_files->size(), info.classpath.size()); - ASSERT_EQ(all_dex_files->size(), info.checksums.size()); + + std::vector<const DexFile*> primary_dex_files; + std::vector<std::optional<uint32_t>> primary_checksums; + for (size_t i = 0; i < all_dex_files->size();) { + primary_dex_files.push_back((*all_dex_files)[i].get()); + primary_checksums.push_back(DexFileLoader::GetMultiDexChecksum(*all_dex_files, &i)); + } + ASSERT_EQ(primary_dex_files.size(), info.classpath.size()); + ASSERT_EQ(primary_dex_files.size(), info.checksums.size()); + if (only_read_checksums) { ASSERT_EQ(0u, info.opened_dex_files.size()); + for (size_t k = 0; k < primary_dex_files.size(); k++) { + const std::string& opened_location = info.classpath[k]; + uint32_t opened_checksum = info.checksums[k]; + + const DexFile* expected_dex_file = primary_dex_files[k]; + std::string expected_location = expected_dex_file->GetLocation(); + + if (!IsAbsoluteLocation(opened_location)) { + // If the opened location is relative (it was open from a relative path without a + // classpath_dir) it might not match the expected location which is absolute in tests). + // So we compare the endings (the checksum will validate it's actually the same file). + ASSERT_TRUE(EndsWith(expected_location, opened_location)) + << expected_location << " " << opened_location; + } else { + ASSERT_EQ(expected_location, opened_location); + } + ASSERT_EQ(primary_checksums[k], opened_checksum); + if (classpath_matches_dex_location) { + ASSERT_EQ(info.classpath[k], opened_location); + } + } } else { ASSERT_EQ(all_dex_files->size(), info.opened_dex_files.size()); - } - for (size_t k = 0, cur_open_dex_index = 0; - k < all_dex_files->size(); - k++, cur_open_dex_index++) { - const std::string& opened_location = only_read_checksums - ? info.classpath[cur_open_dex_index] - : info.opened_dex_files[cur_open_dex_index]->GetLocation(); - uint32_t opened_checksum = only_read_checksums - ? info.checksums[cur_open_dex_index] - : info.opened_dex_files[cur_open_dex_index]->GetLocationChecksum(); - - std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k]; - std::string expected_location = expected_dex_file->GetLocation(); - - if (!IsAbsoluteLocation(opened_location)) { - // If the opened location is relative (it was open from a relative path without a - // classpath_dir) it might not match the expected location which is absolute in tests). - // So we compare the endings (the checksum will validate it's actually the same file). - ASSERT_EQ(0, expected_location.compare( - expected_location.length() - opened_location.length(), - opened_location.length(), - opened_location)); - } else { - ASSERT_EQ(expected_location, opened_location); - } - ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_checksum); - if (classpath_matches_dex_location) { - ASSERT_EQ(info.classpath[k], opened_location); + for (size_t k = 0; k < all_dex_files->size(); k++) { + const std::string& opened_location = info.opened_dex_files[k]->GetLocation(); + uint32_t opened_checksum = info.opened_dex_files[k]->GetLocationChecksum(); + + std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k]; + std::string expected_location = expected_dex_file->GetLocation(); + + if (!IsAbsoluteLocation(opened_location)) { + // If the opened location is relative (it was open from a relative path without a + // classpath_dir) it might not match the expected location which is absolute in tests). + // So we compare the endings (the checksum will validate it's actually the same file). + ASSERT_TRUE(EndsWith(expected_location, opened_location)) + << expected_location << " " << opened_location; + } else { + ASSERT_EQ(expected_location, opened_location); + } + ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_checksum); + if (classpath_matches_dex_location) { + ASSERT_EQ(info.classpath[k], opened_location); + } } } } @@ -1202,9 +1226,11 @@ TEST_F(ClassLoaderContextTest, EncodeInOatFileIMC) { std::vector<std::unique_ptr<const DexFile>> dex2 = OpenTestDexFiles("MyClass"); ASSERT_EQ(dex2.size(), 1u); + uint32_t expected_checksum = DexFileLoader::GetMultiDexChecksum(dex2); + std::string encoding = context->EncodeContextForOatFile(""); - std::string expected_encoding = "IMC[<unknown>*" + std::to_string(dex2[0]->GetLocationChecksum()) - + "];PCL[" + CreateClassPathWithChecksums(dex1) + "]"; + std::string expected_encoding = "IMC[<unknown>*" + std::to_string(expected_checksum) + "];PCL[" + + CreateClassPathWithChecksums(dex1) + "]"; ASSERT_EQ(expected_encoding, context->EncodeContextForOatFile("")); } diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h index c7febcd4fb..43e1bf816e 100644 --- a/runtime/dex2oat_environment_test.h +++ b/runtime/dex2oat_environment_test.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ #include <fstream> +#include <optional> #include <string> #include <vector> @@ -98,8 +99,7 @@ class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTe Dex2oatScratchDirs::SetUp(android_data_); // Verify the environment is as we expect - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations; + std::optional<uint32_t> checksum; std::string error_msg; ASSERT_TRUE(OS::FileExists(GetSystemImageFile().c_str())) << "Expected pre-compiled boot image to be at: " << GetSystemImageFile(); @@ -107,8 +107,8 @@ class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTe << "Expected dex file to be at: " << GetDexSrc1(); ASSERT_TRUE(OS::FileExists(GetResourceOnlySrc1().c_str())) << "Expected stripped dex file to be at: " << GetResourceOnlySrc1(); - ASSERT_TRUE(ArtDexFileLoader::GetMultiDexChecksums( - GetResourceOnlySrc1().c_str(), &checksums, &dex_locations, &error_msg)) + ArtDexFileLoader dex_file_loader0(GetResourceOnlySrc1()); + ASSERT_TRUE(dex_file_loader0.GetMultiDexChecksum(&checksum, &error_msg)) << "Expected stripped dex file to be stripped: " << GetResourceOnlySrc1(); ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str())) << "Expected dex file to be at: " << GetDexSrc2(); @@ -128,6 +128,9 @@ class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTe << error_msg; ASSERT_GT(multi2.size(), 1u); + ASSERT_EQ(multi1[0]->GetHeader().checksum_, multi2[0]->GetHeader().checksum_); + ASSERT_NE(multi1[1]->GetHeader().checksum_, multi2[1]->GetHeader().checksum_); + ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum()); ASSERT_NE(multi1[1]->GetLocationChecksum(), multi2[1]->GetLocationChecksum()); } diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index f4af50f07e..ebd6681f5c 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -21,6 +21,7 @@ #include <unistd.h> #include <memory> +#include <optional> #include <random> #include <string> #include <vector> @@ -3448,66 +3449,44 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, return false; } - size_t dex_file_index = 0; - for (const OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) { - // Skip multidex locations - These will be checked when we visit their - // corresponding primary non-multidex location. - if (DexFileLoader::IsMultiDexLocation(oat_dex_file->GetDexFileLocation().c_str())) { - continue; - } - + size_t dex_file_index = 0; // Counts only primary dex files. + const std::vector<const OatDexFile*>& oat_dex_files = oat_file.GetOatDexFiles(); + for (size_t i = 0; i < oat_dex_files.size();) { DCHECK(dex_filenames.empty() || dex_file_index < dex_filenames.size()); - const std::string& dex_file_location = - dex_filenames.empty() ? oat_dex_file->GetDexFileLocation() : dex_filenames[dex_file_index]; + const std::string& dex_file_location = dex_filenames.empty() ? + oat_dex_files[i]->GetDexFileLocation() : + dex_filenames[dex_file_index]; int dex_fd = dex_file_index < dex_fds.size() ? dex_fds[dex_file_index] : -1; dex_file_index++; - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations_ignored; - if (!ArtDexFileLoader::GetMultiDexChecksums( - dex_file_location.c_str(), &checksums, &dex_locations_ignored, error_msg, dex_fd)) { - *error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' " - "referenced by oat file %s: %s", - dex_file_location.c_str(), - oat_file.GetLocation().c_str(), - error_msg->c_str()); - return false; + if (DexFileLoader::IsMultiDexLocation(oat_dex_files[i]->GetDexFileLocation().c_str())) { + return false; // Expected primary dex file. } - CHECK(!checksums.empty()); - if (checksums[0] != oat_dex_file->GetDexFileLocationChecksum()) { - *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file " - "'%s' and dex file '%s' (0x%x != 0x%x)", - oat_file.GetLocation().c_str(), - dex_file_location.c_str(), - oat_dex_file->GetDexFileLocationChecksum(), - checksums[0]); + uint32_t oat_checksum = DexFileLoader::GetMultiDexChecksum(oat_dex_files, &i); + + // Original checksum. + std::optional<uint32_t> dex_checksum; + ArtDexFileLoader dex_loader(dex_fd, dex_file_location); + if (!dex_loader.GetMultiDexChecksum(&dex_checksum, error_msg)) { + *error_msg = StringPrintf( + "ValidateOatFile failed to get checksum of dex file '%s' " + "referenced by oat file %s: %s", + dex_file_location.c_str(), + oat_file.GetLocation().c_str(), + error_msg->c_str()); return false; } + CHECK(dex_checksum.has_value()); - // Verify checksums for any related multidex entries. - for (size_t i = 1; i < checksums.size(); i++) { - std::string multi_dex_location = DexFileLoader::GetMultiDexLocation( - i, - dex_file_location.c_str()); - const OatDexFile* multi_dex = oat_file.GetOatDexFile(multi_dex_location.c_str(), - nullptr, - error_msg); - if (multi_dex == nullptr) { - *error_msg = StringPrintf("ValidateOatFile oat file '%s' is missing entry '%s'", - oat_file.GetLocation().c_str(), - multi_dex_location.c_str()); - return false; - } - - if (checksums[i] != multi_dex->GetDexFileLocationChecksum()) { - *error_msg = StringPrintf("ValidateOatFile found checksum mismatch between oat file " - "'%s' and dex file '%s' (0x%x != 0x%x)", - oat_file.GetLocation().c_str(), - multi_dex_location.c_str(), - multi_dex->GetDexFileLocationChecksum(), - checksums[i]); - return false; - } + if (oat_checksum != dex_checksum) { + *error_msg = StringPrintf( + "ValidateOatFile found checksum mismatch between oat file " + "'%s' and dex file '%s' (0x%x != 0x%x)", + oat_file.GetLocation().c_str(), + dex_file_location.c_str(), + oat_checksum, + dex_checksum.value()); + return false; } } return true; @@ -3556,14 +3535,13 @@ std::string ImageSpace::GetBootClassPathChecksums( ArrayRef<const DexFile* const>(boot_class_path).SubArray(bcp_pos); DCHECK(boot_class_path_tail.empty() || !DexFileLoader::IsMultiDexLocation(boot_class_path_tail.front()->GetLocation().c_str())); - for (const DexFile* dex_file : boot_class_path_tail) { - if (!DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str())) { - if (!boot_image_checksum.empty()) { - boot_image_checksum += ':'; - } - boot_image_checksum += kDexFileChecksumPrefix; + for (size_t i = 0; i < boot_class_path_tail.size();) { + uint32_t checksum = DexFileLoader::GetMultiDexChecksum(boot_class_path_tail, &i); + if (!boot_image_checksum.empty()) { + boot_image_checksum += ':'; } - StringAppendF(&boot_image_checksum, "/%08x", dex_file->GetLocationChecksum()); + boot_image_checksum += kDexFileChecksumPrefix; + StringAppendF(&boot_image_checksum, "/%08x", checksum); } return boot_image_checksum; } diff --git a/runtime/oat.h b/runtime/oat.h index e062baaee9..d65f19a42b 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -44,8 +44,8 @@ std::ostream& operator<<(std::ostream& stream, StubType stub_type); class PACKED(4) OatHeader { public: static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } }; - // Last oat version changed reason: ARM64: Enable implicit suspend checks; compiled code check. - static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '3', '0', '\0' } }; + // Last oat version changed reason: Reduce multidex checksum to single scalar value. + static constexpr std::array<uint8_t, 4> kOatVersion{{'2', '3', '1', '\0'}}; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; static constexpr const char* kDebuggableKey = "debuggable"; diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 68adb987c0..4fdbb75a3a 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -514,6 +514,9 @@ class OatDexFile final { return dex_file_location_; } + // Returns original path of DexFile that was the source of this OatDexFile. + const std::string& GetLocation() const { return dex_file_location_; } + // Returns the canonical location of DexFile that was the source of this OatDexFile. const std::string& GetCanonicalDexFileLocation() const { return canonical_dex_file_location_; @@ -524,6 +527,9 @@ class OatDexFile final { return dex_file_location_checksum_; } + // Returns checksum of original DexFile that was the source of this OatDexFile; + uint32_t GetLocationChecksum() const { return dex_file_location_checksum_; } + // Returns the OatClass for the class specified by the given DexFile class_def_index. OatFile::OatClass GetOatClass(uint16_t class_def_index) const; diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 9e16e49e40..cbbb31cd4f 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -453,11 +453,11 @@ bool OatFileAssistant::LoadDexFiles(const OatFile& oat_file, std::optional<bool> OatFileAssistant::HasDexFiles(std::string* error_msg) { ScopedTrace trace("HasDexFiles"); - const std::vector<std::uint32_t>* checksums = GetRequiredDexChecksums(error_msg); - if (checksums == nullptr) { + std::optional<std::uint32_t> checksum; + if (!GetRequiredDexChecksum(&checksum, error_msg)) { return std::nullopt; } - return !checksums->empty(); + return checksum.has_value(); } OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() { return odex_.Status(); } @@ -471,37 +471,35 @@ bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* err return true; } ScopedTrace trace("DexChecksumUpToDate"); - const std::vector<uint32_t>* required_dex_checksums = GetRequiredDexChecksums(error_msg); - if (required_dex_checksums == nullptr) { + std::optional<std::uint32_t> dex_checksum; + if (!GetRequiredDexChecksum(&dex_checksum, error_msg)) { return false; } - if (required_dex_checksums->empty()) { + if (!dex_checksum.has_value()) { LOG(WARNING) << "Required dex checksums not found. Assuming dex checksums are up to date."; return true; } + std::vector<const OatDexFile*> oat_dex_files; uint32_t number_of_dex_files = file.GetOatHeader().GetDexFileCount(); - if (required_dex_checksums->size() != number_of_dex_files) { - *error_msg = StringPrintf( - "expected %zu dex files but found %u", required_dex_checksums->size(), number_of_dex_files); - return false; - } - for (uint32_t i = 0; i < number_of_dex_files; i++) { std::string dex = DexFileLoader::GetMultiDexLocation(i, dex_location_.c_str()); - uint32_t expected_checksum = (*required_dex_checksums)[i]; const OatDexFile* oat_dex_file = file.GetOatDexFile(dex.c_str(), nullptr); if (oat_dex_file == nullptr) { *error_msg = StringPrintf("failed to find %s in %s", dex.c_str(), file.GetLocation().c_str()); return false; } - uint32_t actual_checksum = oat_dex_file->GetDexFileLocationChecksum(); - if (expected_checksum != actual_checksum) { - VLOG(oat) << "Dex checksum does not match for dex: " << dex - << ". Expected: " << expected_checksum << ", Actual: " << actual_checksum; - return false; - } + oat_dex_files.push_back(oat_dex_file); } + uint32_t oat_checksum = DexFileLoader::GetMultiDexChecksum(oat_dex_files); + + CHECK(dex_checksum.has_value()); + if (dex_checksum != oat_checksum) { + VLOG(oat) << "Checksum does not match: " << std::hex << file.GetLocation() << " (" + << oat_checksum << ") vs " << dex_location_ << " (" << *dex_checksum << ")"; + return false; + } + return true; } @@ -718,33 +716,36 @@ bool OatFileAssistant::DexLocationToOatFilename(const std::string& location, return GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(), oat_filename, error_msg); } -const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums(std::string* error_msg) { +bool OatFileAssistant::GetRequiredDexChecksum(std::optional<uint32_t>* checksum, + std::string* error) { if (!required_dex_checksums_attempted_) { required_dex_checksums_attempted_ = true; - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations_ignored; - if (ArtDexFileLoader::GetMultiDexChecksums(dex_location_.c_str(), - &checksums, - &dex_locations_ignored, - &cached_required_dex_checksums_error_, - zip_fd_, - &zip_file_only_contains_uncompressed_dex_)) { - if (checksums.empty()) { - // The only valid case here is for APKs without dex files. - VLOG(oat) << "No dex file found in " << dex_location_; - } - cached_required_dex_checksums_ = std::move(checksums); + ArtDexFileLoader dex_loader(zip_fd_, dex_location_); + std::optional<uint32_t> checksum2; + std::string error2; + if (dex_loader.GetMultiDexChecksum( + &checksum2, &error2, &zip_file_only_contains_uncompressed_dex_)) { + cached_required_dex_checksums_ = checksum2; + cached_required_dex_checksums_error_ = std::nullopt; + } else { + cached_required_dex_checksums_ = std::nullopt; + cached_required_dex_checksums_error_ = error2; } } - if (cached_required_dex_checksums_.has_value()) { - return &cached_required_dex_checksums_.value(); - } else { - *error_msg = cached_required_dex_checksums_error_; - DCHECK(!error_msg->empty()); - return nullptr; + if (cached_required_dex_checksums_error_.has_value()) { + *error = cached_required_dex_checksums_error_.value(); + DCHECK(!error->empty()); + return false; + } + + if (!cached_required_dex_checksums_.has_value()) { + // The only valid case here is for APKs without dex files. + VLOG(oat) << "No dex file found in " << dex_location_; } + *checksum = cached_required_dex_checksums_; + return true; } bool OatFileAssistant::ValidateBootClassPathChecksums(OatFileAssistantContext* ofa_context, @@ -1380,8 +1381,9 @@ void OatFileAssistant::GetOptimizationStatus(std::string* out_odex_location, bool OatFileAssistant::ZipFileOnlyContainsUncompressedDex() { // zip_file_only_contains_uncompressed_dex_ is only set during fetching the dex checksums. + std::optional<uint32_t> checksum; std::string error_msg; - if (GetRequiredDexChecksums(&error_msg) == nullptr) { + if (!GetRequiredDexChecksum(&checksum, &error_msg)) { LOG(ERROR) << error_msg; } return zip_file_only_contains_uncompressed_dex_; diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 54287eb5f1..922dbf3e04 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -494,11 +494,9 @@ class OatFileAssistant { // location. OatStatus GivenOatFileStatus(const OatFile& file); - // Gets the dex checksums required for an up-to-date oat file. - // Returns cached_required_dex_checksums if the required checksums were located. Returns an empty - // list if `dex_location_` refers to a zip and there is no dex file in it. Returns nullptr if an - // error occurred. The caller shouldn't clean up or free the returned pointer. - const std::vector<uint32_t>* GetRequiredDexChecksums(std::string* error_msg); + // Gets the dex checksum required for an up-to-date oat file. + // Returns cached result from GetMultiDexChecksum. + bool GetRequiredDexChecksum(std::optional<uint32_t>* checksum, std::string* error); // Returns whether there is at least one boot image usable. bool IsPrimaryBootImageUsable(); @@ -555,8 +553,8 @@ class OatFileAssistant { // Cached value of the required dex checksums. // This should be accessed only by the GetRequiredDexChecksums() method. - std::optional<std::vector<uint32_t>> cached_required_dex_checksums_; - std::string cached_required_dex_checksums_error_; + std::optional<uint32_t> cached_required_dex_checksums_; + std::optional<std::string> cached_required_dex_checksums_error_; bool required_dex_checksums_attempted_ = false; // The AOT-compiled file of an app when the APK of the app is in /data. diff --git a/runtime/oat_file_assistant_context.cc b/runtime/oat_file_assistant_context.cc index c3fb73de4b..0f9860f55d 100644 --- a/runtime/oat_file_assistant_context.cc +++ b/runtime/oat_file_assistant_context.cc @@ -17,6 +17,7 @@ #include "oat_file_assistant_context.h" #include <memory> +#include <optional> #include <string> #include <vector> @@ -76,13 +77,13 @@ OatFileAssistantContext::OatFileAssistantContext(Runtime* runtime) // Fetch BCP checksums from the runtime. size_t bcp_index = 0; std::vector<std::string>* current_bcp_checksums = nullptr; - for (const DexFile* dex_file : runtime->GetClassLinker()->GetBootClassPath()) { - if (!DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str())) { - DCHECK_LT(bcp_index, runtime_options_->boot_class_path.size()); - current_bcp_checksums = &bcp_checksums_by_index_[bcp_index++]; - } + const std::vector<const DexFile*>& bcp_dex_files = runtime->GetClassLinker()->GetBootClassPath(); + for (size_t i = 0; i < bcp_dex_files.size();) { + uint32_t checksum = DexFileLoader::GetMultiDexChecksum(bcp_dex_files, &i); + DCHECK_LT(bcp_index, runtime_options_->boot_class_path.size()); + current_bcp_checksums = &bcp_checksums_by_index_[bcp_index++]; DCHECK_NE(current_bcp_checksums, nullptr); - current_bcp_checksums->push_back(StringPrintf("/%08x", dex_file->GetLocationChecksum())); + current_bcp_checksums->push_back(StringPrintf("/%08x", checksum)); } DCHECK_EQ(bcp_index, runtime_options_->boot_class_path.size()); @@ -156,23 +157,18 @@ const std::vector<std::string>* OatFileAssistantContext::GetBcpChecksums(size_t return &it->second; } - std::vector<uint32_t> checksums; - std::vector<std::string> dex_locations; - if (!ArtDexFileLoader::GetMultiDexChecksums( - runtime_options_->boot_class_path[bcp_index].c_str(), - &checksums, - &dex_locations, - error_msg, - runtime_options_->boot_class_path_fds != nullptr ? - (*runtime_options_->boot_class_path_fds)[bcp_index] : - -1)) { + const std::vector<int>* fds = runtime_options_->boot_class_path_fds; + ArtDexFileLoader dex_loader(fds != nullptr ? (*fds)[bcp_index] : -1, + runtime_options_->boot_class_path[bcp_index]); + std::optional<uint32_t> checksum; + if (!dex_loader.GetMultiDexChecksum(&checksum, error_msg)) { return nullptr; } - DCHECK(!checksums.empty()); + DCHECK(checksum.has_value()); std::vector<std::string>& bcp_checksums = bcp_checksums_by_index_[bcp_index]; - for (uint32_t checksum : checksums) { - bcp_checksums.push_back(StringPrintf("/%08x", checksum)); + if (checksum.has_value()) { + bcp_checksums.push_back(StringPrintf("/%08x", checksum.value())); } return &bcp_checksums; } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 36c8cde802..f3bd4dd37e 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -16,6 +16,7 @@ #include "runtime.h" +#include <optional> #include <utility> #ifdef __linux__ @@ -2765,14 +2766,14 @@ void Runtime::RegisterAppInfo(const std::string& package_name, bool has_code = false; for (const std::string& path : code_paths) { std::string error_msg; - std::vector<uint32_t> checksums; + std::optional<uint32_t> checksum; std::vector<std::string> dex_locations; - if (!ArtDexFileLoader::GetMultiDexChecksums( - path.c_str(), &checksums, &dex_locations, &error_msg)) { + DexFileLoader loader(path); + if (!loader.GetMultiDexChecksum(&checksum, &error_msg)) { LOG(WARNING) << error_msg; continue; } - if (dex_locations.size() > 0) { + if (checksum.has_value()) { has_code = true; break; } |