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, 380 insertions, 367 deletions
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 56d14a7143..be442075e4 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -19,7 +19,6 @@ #include <algorithm> #include <iterator> -#include <optional> #include <regex> #include <sstream> #include <string> @@ -1090,11 +1089,9 @@ 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(expected_checksum) + "]"; + std::string expected_classpath_key = "PCL[" + dex_files[0]->GetLocation() + "*" + + std::to_string(dex_files[0]->GetLocationChecksum()) + "]"; RunTest(context.c_str(), expected_classpath_key.c_str(), true); } @@ -2218,9 +2215,21 @@ 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]"; - uint32_t checksum = DexFileLoader::GetMultiDexChecksum(dex_files); - std::string expected_stored_context = - "PCL[/system/not_real_lib.jar*" + std::to_string(checksum) + "]"; + 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 += "]"; // 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 e83cc0d967..db0e1c157f 100644 --- a/libartbase/base/common_art_test.cc +++ b/libartbase/base/common_art_test.cc @@ -582,8 +582,13 @@ std::string CommonArtTestImpl::CreateClassPath( std::string CommonArtTestImpl::CreateClassPathWithChecksums( const std::vector<std::unique_ptr<const DexFile>>& dex_files) { CHECK(!dex_files.empty()); - uint32_t checksum = DexFileLoader::GetMultiDexChecksum(dex_files); - return dex_files[0]->GetLocation() + "*" + std::to_string(checksum); + 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; } CommonArtTestImpl::ForkAndExecResult CommonArtTestImpl::ForkAndExec( diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc index 056d2fb261..ac52ca04e3 100644 --- a/libdexfile/dex/art_dex_file_loader.cc +++ b/libdexfile/dex/art_dex_file_loader.cc @@ -37,6 +37,88 @@ 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 2fbc2cb794..9f2ae82e72 100644 --- a/libdexfile/dex/art_dex_file_loader.h +++ b/libdexfile/dex/art_dex_file_loader.h @@ -36,8 +36,31 @@ 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; // Use constructors from base class. - using DexFileLoader::Open; // Don't shadow overloads from base class. + 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; // 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 4663a02ff0..d8911ece78 100644 --- a/libdexfile/dex/art_dex_file_loader_test.cc +++ b/libdexfile/dex/art_dex_file_loader_test.cc @@ -19,8 +19,6 @@ #include <sys/mman.h> #include <memory> -#include <optional> -#include <vector> #include "base/common_art_test.h" #include "base/mem_map.h" @@ -31,8 +29,8 @@ #include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/descriptors_names.h" -#include "dex/dex_file-inl.h" #include "dex/dex_file.h" +#include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" namespace art { @@ -97,50 +95,65 @@ TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) { } TEST_F(ArtDexFileLoaderTest, GetChecksum) { - std::optional<uint32_t> checksum; + std::vector<uint32_t> checksums; + std::vector<std::string> dex_locations; std::string error_msg; - 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()); + 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]); } -TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksum) { +TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksums) { std::string error_msg; - std::optional<uint32_t> checksum; + std::vector<uint32_t> checksums; + std::vector<std::string> dex_locations; std::string multidex_file = GetTestDexFileName("MultiDex"); - ArtDexFileLoader dex_loader(multidex_file); - EXPECT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; + EXPECT_TRUE(ArtDexFileLoader::GetMultiDexChecksums( + multidex_file.c_str(), &checksums, &dex_locations, &error_msg)) + << error_msg; std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex"); ASSERT_EQ(2U, dexes.size()); - ASSERT_TRUE(checksum.has_value()); + ASSERT_EQ(2U, checksums.size()); + ASSERT_EQ(2U, dex_locations.size()); - 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(expected_checksum, checksum.value()); + EXPECT_EQ(dexes[1]->GetLocation(), dex_locations[1]); + EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]); } TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksumsEmptyZip) { std::string error_msg; - std::optional<uint32_t> checksum; + std::vector<uint32_t> checksums; + std::vector<std::string> dex_locations; std::string multidex_file = GetTestDexFileName("MainEmptyUncompressed"); - ArtDexFileLoader dex_loader(multidex_file); - EXPECT_TRUE(dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; - EXPECT_FALSE(checksum.has_value()); + 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); } TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksumsDexFile) { std::string error_msg; - std::optional<uint32_t> checksum; + std::vector<uint32_t> checksums; + std::vector<std::string> dex_locations; std::string multidex_file = GetTestDexFileName("VerifierDeps"); // This is a .dex file. - DexFileLoader loader(multidex_file); - EXPECT_TRUE(loader.GetMultiDexChecksum(&checksum, &error_msg)) << error_msg; - EXPECT_TRUE(checksum.has_value()); + 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); } TEST_F(ArtDexFileLoaderTest, ClassDefs) { diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index 8179559337..080e381fe0 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 9b54c15d9e..d375aac17b 100644 --- a/libdexfile/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc @@ -148,72 +148,9 @@ std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) { } std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) { - 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; + return (index == 0) + ? dex_location + : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1); } 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 14cbdadaad..532445acf9 100644 --- a/libdexfile/dex/dex_file_loader.h +++ b/libdexfile/dex/dex_file_loader.h @@ -32,6 +32,7 @@ namespace art { class MemMap; class OatDexFile; +class ScopedTrace; class ZipArchive; enum class DexFileLoaderErrorCode { @@ -71,53 +72,6 @@ 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 e925f856ef..7bc1a04441 100644 --- a/odrefresh/odrefresh.cc +++ b/odrefresh/odrefresh.cc @@ -316,18 +316,25 @@ std::vector<T> GenerateComponents( return {}; } - std::optional<uint32_t> checksum; + std::vector<uint32_t> checksums; + std::vector<std::string> dex_locations; std::string error_msg; - ArtDexFileLoader dex_loader(actual_path); - if (!dex_loader.GetMultiDexChecksum(&checksum, &error_msg)) { - LOG(ERROR) << "Failed to get multi-dex checksum: " << error_msg; + if (!ArtDexFileLoader::GetMultiDexChecksums( + actual_path.c_str(), &checksums, &dex_locations, &error_msg)) { + LOG(ERROR) << "Failed to get multi-dex checksums: " << error_msg; return {}; } - const std::string checksum_str = - checksum.has_value() ? StringPrintf("%08x", checksum.value()) : std::string(); + 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(); - Result<T> component = custom_generator(path, static_cast<uint64_t>(sb.st_size), checksum_str); + Result<T> component = custom_generator(path, static_cast<uint64_t>(sb.st_size), checksum); 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 07ea060eec..c0e5adeec9 100644 --- a/odrefresh/odrefresh_main.cc +++ b/odrefresh/odrefresh_main.cc @@ -27,7 +27,6 @@ #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" @@ -269,7 +268,6 @@ 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 1b14449684..2f34f04f5b 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -17,7 +17,6 @@ #include "class_loader_context.h" #include <algorithm> -#include <optional> #include "android-base/file.h" #include "android-base/parseint.h" @@ -474,12 +473,14 @@ 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 (!dex_file_loader.GetMultiDexChecksum( - &dex_checksum, &error_msg, &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)) { LOG(WARNING) << "Could not get dex checksums for location " << location << ", fd=" << fd; dex_files_state_ = kDexFilesOpenFailed; } @@ -488,7 +489,8 @@ 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 i = info->opened_dex_files.size(); + size_t opened_dex_files_index = info->opened_dex_files.size(); + ArtDexFileLoader dex_file_loader(location.c_str(), fd, location); if (!dex_file_loader.Open(/*verify=*/false, /*verify_checksum=*/true, &error_msg, @@ -496,14 +498,13 @@ 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 { - dex_checksum = DexFileLoader::GetMultiDexChecksum(info->opened_dex_files, &i); - DCHECK_EQ(i, info->opened_dex_files.size()); + 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()); + } } } - 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. @@ -517,8 +518,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 = std::move(dex_locations); - info->checksums = std::move(dex_checksums); + info->classpath = dex_locations; + info->checksums = dex_checksums; AddToWorkList(info, work_list); } @@ -691,16 +692,16 @@ void ClassLoaderContext::EncodeContextInternal(const ClassLoaderInfo& info, } } - for (size_t k = 0; k < info.opened_dex_files.size();) { + for (size_t k = 0; k < info.opened_dex_files.size(); k++) { 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; - CHECK(new_insert); + if (!new_insert) { + continue; + } } std::string location = dex_file->GetLocation(); @@ -715,7 +716,7 @@ void ClassLoaderContext::EncodeContextInternal(const ClassLoaderInfo& info, // dex2oat does not need the checksums. if (!for_dex2oat) { - checksums.push_back(checksum); + checksums.push_back(dex_file->GetLocationChecksum()); } } EncodeClassPath(base_dir, locations, checksums, info.type, out); @@ -1154,17 +1155,13 @@ bool ClassLoaderContext::CreateInfoFromClassLoader( } // Now that `info` is in the chain, populate dex files. - 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); + for (const DexFile* dex_file : dex_files_loaded) { // 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(checksum); - } - for (auto* dex_file : dex_files_loaded) { + info->checksums.push_back(dex_file->GetLocationChecksum()); info->opened_dex_files.emplace_back(dex_file); } @@ -1480,10 +1477,8 @@ 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 (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 && + for (const DexFile* dex_file : dex_files_to_check) { + if (info->checksums[k] == dex_file->GetLocationChecksum() && 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 98b8eed5d5..ce9780a74e 100644 --- a/runtime/class_loader_context_test.cc +++ b/runtime/class_loader_context_test.cc @@ -20,8 +20,6 @@ #include <filesystem> #include <fstream> -#include <optional> -#include <vector> #include "android-base/stringprintf.h" #include "android-base/strings.h" @@ -29,7 +27,6 @@ #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" @@ -187,62 +184,41 @@ class ClassLoaderContextTest : public CommonRuntimeTest { ClassLoaderContext::ContextDexFilesState::kDexFilesOpened); } ClassLoaderContext::ClassLoaderInfo& info = *context->GetParent(index); - - 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()); - + ASSERT_EQ(all_dex_files->size(), info.classpath.size()); + ASSERT_EQ(all_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; 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); - } + 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); } } } @@ -1226,11 +1202,9 @@ 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(expected_checksum) + "];PCL[" + - CreateClassPathWithChecksums(dex1) + "]"; + std::string expected_encoding = "IMC[<unknown>*" + std::to_string(dex2[0]->GetLocationChecksum()) + + "];PCL[" + CreateClassPathWithChecksums(dex1) + "]"; ASSERT_EQ(expected_encoding, context->EncodeContextForOatFile("")); } diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h index 43e1bf816e..c7febcd4fb 100644 --- a/runtime/dex2oat_environment_test.h +++ b/runtime/dex2oat_environment_test.h @@ -18,7 +18,6 @@ #define ART_RUNTIME_DEX2OAT_ENVIRONMENT_TEST_H_ #include <fstream> -#include <optional> #include <string> #include <vector> @@ -99,7 +98,8 @@ class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTe Dex2oatScratchDirs::SetUp(android_data_); // Verify the environment is as we expect - std::optional<uint32_t> checksum; + std::vector<uint32_t> checksums; + std::vector<std::string> dex_locations; 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(); - ArtDexFileLoader dex_file_loader0(GetResourceOnlySrc1()); - ASSERT_TRUE(dex_file_loader0.GetMultiDexChecksum(&checksum, &error_msg)) + ASSERT_TRUE(ArtDexFileLoader::GetMultiDexChecksums( + GetResourceOnlySrc1().c_str(), &checksums, &dex_locations, &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,9 +128,6 @@ 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 ebd6681f5c..f4af50f07e 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -21,7 +21,6 @@ #include <unistd.h> #include <memory> -#include <optional> #include <random> #include <string> #include <vector> @@ -3449,44 +3448,66 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, return false; } - 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();) { + 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; + } + DCHECK(dex_filenames.empty() || dex_file_index < dex_filenames.size()); - const std::string& dex_file_location = dex_filenames.empty() ? - oat_dex_files[i]->GetDexFileLocation() : - dex_filenames[dex_file_index]; + const std::string& dex_file_location = + dex_filenames.empty() ? oat_dex_file->GetDexFileLocation() : dex_filenames[dex_file_index]; int dex_fd = dex_file_index < dex_fds.size() ? dex_fds[dex_file_index] : -1; dex_file_index++; - if (DexFileLoader::IsMultiDexLocation(oat_dex_files[i]->GetDexFileLocation().c_str())) { - return false; // Expected primary dex file. + 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; } - 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()); + 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]); return false; } - CHECK(dex_checksum.has_value()); - 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; + // 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; + } } } return true; @@ -3535,13 +3556,14 @@ 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 (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 += ':'; + 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; } - boot_image_checksum += kDexFileChecksumPrefix; - StringAppendF(&boot_image_checksum, "/%08x", checksum); + StringAppendF(&boot_image_checksum, "/%08x", dex_file->GetLocationChecksum()); } return boot_image_checksum; } diff --git a/runtime/oat.h b/runtime/oat.h index d65f19a42b..e062baaee9 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: Reduce multidex checksum to single scalar value. - static constexpr std::array<uint8_t, 4> kOatVersion{{'2', '3', '1', '\0'}}; + // 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' } }; 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 4fdbb75a3a..68adb987c0 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -514,9 +514,6 @@ 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_; @@ -527,9 +524,6 @@ 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 cbbb31cd4f..9e16e49e40 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"); - std::optional<std::uint32_t> checksum; - if (!GetRequiredDexChecksum(&checksum, error_msg)) { + const std::vector<std::uint32_t>* checksums = GetRequiredDexChecksums(error_msg); + if (checksums == nullptr) { return std::nullopt; } - return checksum.has_value(); + return !checksums->empty(); } OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() { return odex_.Status(); } @@ -471,35 +471,37 @@ bool OatFileAssistant::DexChecksumUpToDate(const OatFile& file, std::string* err return true; } ScopedTrace trace("DexChecksumUpToDate"); - std::optional<std::uint32_t> dex_checksum; - if (!GetRequiredDexChecksum(&dex_checksum, error_msg)) { + const std::vector<uint32_t>* required_dex_checksums = GetRequiredDexChecksums(error_msg); + if (required_dex_checksums == nullptr) { return false; } - if (!dex_checksum.has_value()) { + if (required_dex_checksums->empty()) { 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; } - 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; + 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; + } } - return true; } @@ -716,36 +718,33 @@ bool OatFileAssistant::DexLocationToOatFilename(const std::string& location, return GetDalvikCacheFilename(location.c_str(), dalvik_cache.c_str(), oat_filename, error_msg); } -bool OatFileAssistant::GetRequiredDexChecksum(std::optional<uint32_t>* checksum, - std::string* error) { +const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums(std::string* error_msg) { 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_; + } - 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; + cached_required_dex_checksums_ = std::move(checksums); } } - 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_; + 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; } - *checksum = cached_required_dex_checksums_; - return true; } bool OatFileAssistant::ValidateBootClassPathChecksums(OatFileAssistantContext* ofa_context, @@ -1381,9 +1380,8 @@ 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 (!GetRequiredDexChecksum(&checksum, &error_msg)) { + if (GetRequiredDexChecksums(&error_msg) == nullptr) { 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 922dbf3e04..54287eb5f1 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -494,9 +494,11 @@ class OatFileAssistant { // location. OatStatus GivenOatFileStatus(const OatFile& file); - // 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); + // 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); // Returns whether there is at least one boot image usable. bool IsPrimaryBootImageUsable(); @@ -553,8 +555,8 @@ class OatFileAssistant { // Cached value of the required dex checksums. // This should be accessed only by the GetRequiredDexChecksums() method. - std::optional<uint32_t> cached_required_dex_checksums_; - std::optional<std::string> cached_required_dex_checksums_error_; + std::optional<std::vector<uint32_t>> cached_required_dex_checksums_; + 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 0f9860f55d..c3fb73de4b 100644 --- a/runtime/oat_file_assistant_context.cc +++ b/runtime/oat_file_assistant_context.cc @@ -17,7 +17,6 @@ #include "oat_file_assistant_context.h" #include <memory> -#include <optional> #include <string> #include <vector> @@ -77,13 +76,13 @@ OatFileAssistantContext::OatFileAssistantContext(Runtime* runtime) // Fetch BCP checksums from the runtime. size_t bcp_index = 0; std::vector<std::string>* current_bcp_checksums = nullptr; - 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++]; + 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++]; + } DCHECK_NE(current_bcp_checksums, nullptr); - current_bcp_checksums->push_back(StringPrintf("/%08x", checksum)); + current_bcp_checksums->push_back(StringPrintf("/%08x", dex_file->GetLocationChecksum())); } DCHECK_EQ(bcp_index, runtime_options_->boot_class_path.size()); @@ -157,18 +156,23 @@ const std::vector<std::string>* OatFileAssistantContext::GetBcpChecksums(size_t return &it->second; } - 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)) { + 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)) { return nullptr; } - DCHECK(checksum.has_value()); + DCHECK(!checksums.empty()); std::vector<std::string>& bcp_checksums = bcp_checksums_by_index_[bcp_index]; - if (checksum.has_value()) { - bcp_checksums.push_back(StringPrintf("/%08x", checksum.value())); + for (uint32_t checksum : checksums) { + bcp_checksums.push_back(StringPrintf("/%08x", checksum)); } return &bcp_checksums; } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index f3bd4dd37e..36c8cde802 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -16,7 +16,6 @@ #include "runtime.h" -#include <optional> #include <utility> #ifdef __linux__ @@ -2766,14 +2765,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::optional<uint32_t> checksum; + std::vector<uint32_t> checksums; std::vector<std::string> dex_locations; - DexFileLoader loader(path); - if (!loader.GetMultiDexChecksum(&checksum, &error_msg)) { + if (!ArtDexFileLoader::GetMultiDexChecksums( + path.c_str(), &checksums, &dex_locations, &error_msg)) { LOG(WARNING) << error_msg; continue; } - if (checksum.has_value()) { + if (dex_locations.size() > 0) { has_code = true; break; } |