summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dex2oat/dex2oat_test.cc25
-rw-r--r--libartbase/base/common_art_test.cc9
-rw-r--r--libdexfile/dex/art_dex_file_loader.cc82
-rw-r--r--libdexfile/dex/art_dex_file_loader.h27
-rw-r--r--libdexfile/dex/art_dex_file_loader_test.cc65
-rw-r--r--libdexfile/dex/dex_file.cc2
-rw-r--r--libdexfile/dex/dex_file_loader.cc69
-rw-r--r--libdexfile/dex/dex_file_loader.h48
-rw-r--r--odrefresh/odrefresh.cc21
-rw-r--r--odrefresh/odrefresh_main.cc2
-rw-r--r--runtime/class_loader_context.cc53
-rw-r--r--runtime/class_loader_context_test.cc90
-rw-r--r--runtime/dex2oat_environment_test.h11
-rw-r--r--runtime/gc/space/image_space.cc96
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/oat_file.h6
-rw-r--r--runtime/oat_file_assistant.cc82
-rw-r--r--runtime/oat_file_assistant.h12
-rw-r--r--runtime/oat_file_assistant_context.cc34
-rw-r--r--runtime/runtime.cc9
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;
}