summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jiakai Zhang <jiakaiz@google.com> 2024-08-18 16:37:00 +0100
committer Jiakai Zhang <jiakaiz@google.com> 2024-08-23 12:37:42 +0000
commitf797b3fabb29f93fe07ec70b9892184d599727bc (patch)
tree12996527d2dd3732d9f88d77e7890555dc25793d
parentb17478f8e8f1b27dc8994d991cd0e8ec7c249c1b (diff)
Get Multidex checksums without opening dex files.
This speeds up profman when processing compressed apks because it avoids extracting dex files into the memory. Bug: 358502198 Test: atest art_standalone_profman_tests Change-Id: I98f28653ac4e80f3e3c225bde370401c974199ae
-rw-r--r--libdexfile/dex/dex_file_loader.cc31
-rw-r--r--libdexfile/dex/dex_file_loader.h10
-rw-r--r--profman/profman.cc81
3 files changed, 80 insertions, 42 deletions
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index d524dfceb1..e92a5ac813 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -161,12 +161,10 @@ std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_loc
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.
-
+bool DexFileLoader::GetMultiDexChecksums(
+ /*out*/ std::vector<std::pair<std::string, uint32_t>>* checksums,
+ /*out*/ std::string* error_msg,
+ /*out*/ bool* only_contains_uncompressed_dex) {
uint32_t magic;
if (!InitAndReadMagic(/*header_offset=*/0, &magic, error_msg)) {
return false;
@@ -196,7 +194,7 @@ bool DexFileLoader::GetMultiDexChecksum(std::optional<uint32_t>* checksum,
*only_contains_uncompressed_dex = false;
}
}
- *checksum = checksum->value_or(kEmptyMultiDexChecksum) ^ zip_entry->GetCrc32();
+ checksums->emplace_back(GetMultiDexLocation(i, location_.c_str()), zip_entry->GetCrc32());
}
return true;
}
@@ -205,6 +203,7 @@ bool DexFileLoader::GetMultiDexChecksum(std::optional<uint32_t>* checksum,
}
const uint8_t* begin = root_container_->Begin();
const uint8_t* end = root_container_->End();
+ size_t i = 0;
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);
@@ -216,12 +215,28 @@ bool DexFileLoader::GetMultiDexChecksum(std::optional<uint32_t>* checksum,
*error_msg = StringPrintf("Truncated dex file: '%s'", filename_.c_str());
return false;
}
- *checksum = checksum->value_or(kEmptyMultiDexChecksum) ^ header->checksum_;
+ checksums->emplace_back(GetMultiDexLocation(i++, location_.c_str()), header->checksum_);
ptr += header->file_size_;
}
return true;
}
+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.
+
+ std::vector<std::pair<std::string, uint32_t>> checksums;
+ if (!GetMultiDexChecksums(&checksums, error_msg, only_contains_uncompressed_dex)) {
+ return false;
+ }
+ for (const auto& [location, current_checksum] : checksums) {
+ *checksum = checksum->value_or(kEmptyMultiDexChecksum) ^ current_checksum;
+ }
+ return true;
+}
+
std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
CHECK_NE(dex_location, static_cast<const char*>(nullptr));
std::string base_location = GetBaseLocation(dex_location);
diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h
index 9b5f7d56cd..1c7348214f 100644
--- a/libdexfile/dex/dex_file_loader.h
+++ b/libdexfile/dex/dex_file_loader.h
@@ -23,6 +23,7 @@
#include <optional>
#include <string>
#include <string_view>
+#include <utility>
#include <vector>
#include "base/os.h"
@@ -72,6 +73,15 @@ 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 the multidex location and the checksum for each dex file in a zip or a dex container.
+ //
+ // This uses the source path provided to DexFileLoader constructor.
+ //
+ // Returns false on error.
+ bool GetMultiDexChecksums(/*out*/ std::vector<std::pair<std::string, uint32_t>>* checksums,
+ /*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 the source path provided to DexFileLoader constructor.
diff --git a/profman/profman.cc b/profman/profman.cc
index 2fcb2ef72b..19d480e233 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -562,13 +562,20 @@ class ProfMan final {
}
bool GetProfileFilterKeyFromApks(std::set<ProfileFilterKey>* profile_filter_keys) {
- auto process_fn = [profile_filter_keys](std::unique_ptr<const DexFile>&& dex_file) {
- // Store the profile key of the location instead of the location itself.
- // This will make the matching in the profile filter method much easier.
- profile_filter_keys->emplace(ProfileCompilationInfo::GetProfileDexFileBaseKey(
- dex_file->GetLocation()), dex_file->GetLocationChecksum());
- };
- return OpenApkFilesFromLocations(process_fn);
+ return ForEachApkFile([&](File file, const std::string& location) {
+ ArtDexFileLoader dex_file_loader(&file, location);
+ std::vector<std::pair<std::string, uint32_t>> checksums;
+ std::string error_msg;
+ if (!dex_file_loader.GetMultiDexChecksums(&checksums, &error_msg)) {
+ LOG(ERROR) << "Open failed for '" << location << "' " << error_msg;
+ return false;
+ }
+ for (const auto& [multi_dex_location, checksum] : checksums) {
+ profile_filter_keys->emplace(
+ ProfileCompilationInfo::GetProfileDexFileBaseKey(multi_dex_location), checksum);
+ }
+ return true;
+ });
}
bool OpenApkFilesFromLocations(std::vector<std::unique_ptr<const DexFile>>* dex_files) {
@@ -580,6 +587,32 @@ class ProfMan final {
bool OpenApkFilesFromLocations(
const std::function<void(std::unique_ptr<const DexFile>&&)>& process_fn) {
+ static constexpr bool kVerifyChecksum = true;
+ std::string error_msg;
+ std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
+ bool result = ForEachApkFile([&](File file, const std::string& location) {
+ ArtDexFileLoader dex_file_loader(&file, location);
+ if (!dex_file_loader.Open(/*verify=*/false,
+ kVerifyChecksum,
+ /*allow_no_dex_files=*/true,
+ &error_msg,
+ &dex_files_for_location)) {
+ LOG(ERROR) << "Open failed for '" << location << "' " << error_msg;
+ return false;
+ }
+ return true;
+ });
+ if (!result) {
+ return false;
+ }
+ for (std::unique_ptr<const DexFile>& dex_file : dex_files_for_location) {
+ process_fn(std::move(dex_file));
+ }
+ return true;
+ }
+
+ bool ForEachApkFile(
+ const std::function<bool(File file, const std::string& location)>& process_fn) {
bool use_apk_fd_list = !apks_fd_.empty();
if (use_apk_fd_list) {
// Get the APKs from the collection of FDs.
@@ -592,7 +625,7 @@ class ProfMan final {
}
} else {
if (dex_locations_.size() != apks_fd_.size()) {
- Usage("The number of apk-fds must match the number of dex-locations.");
+ Usage("The number of apk-fds must match the number of dex-locations.");
}
}
} else if (!apk_files_.empty()) {
@@ -600,50 +633,30 @@ class ProfMan final {
// If no dex locations are specified use the apk names as locations.
dex_locations_ = apk_files_;
} else if (dex_locations_.size() != apk_files_.size()) {
- Usage("The number of apk-fds must match the number of dex-locations.");
+ Usage("The number of apk-fds must match the number of dex-locations.");
}
} else {
// No APKs were specified.
CHECK(dex_locations_.empty());
return true;
}
- static constexpr bool kVerifyChecksum = true;
for (size_t i = 0; i < dex_locations_.size(); ++i) {
- std::string error_msg;
- std::vector<std::unique_ptr<const DexFile>> dex_files_for_location;
// We do not need to verify the apk for processing profiles.
if (use_apk_fd_list) {
- File file(apks_fd_[i], /*check_usage=*/false);
- ArtDexFileLoader dex_file_loader(&file, dex_locations_[i]);
- if (dex_file_loader.Open(/*verify=*/false,
- kVerifyChecksum,
- /*allow_no_dex_files=*/true,
- &error_msg,
- &dex_files_for_location)) {
- } else {
- LOG(ERROR) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg;
- return false;
- }
+ File file(apks_fd_[i], /*check_usage=*/false);
+ if (!process_fn(std::move(file), dex_locations_[i])) {
+ return false;
+ }
} else {
File file(apk_files_[i], O_RDONLY, /*check_usage=*/false);
if (file.Fd() < 0) {
PLOG(ERROR) << "Unable to open '" << apk_files_[i] << "'";
return false;
}
- ArtDexFileLoader dex_file_loader(&file, dex_locations_[i]);
- if (dex_file_loader.Open(/*verify=*/false,
- kVerifyChecksum,
- /*allow_no_dex_files=*/true,
- &error_msg,
- &dex_files_for_location)) {
- } else {
- LOG(ERROR) << "Open failed for '" << dex_locations_[i] << "' " << error_msg;
+ if (!process_fn(std::move(file), dex_locations_[i])) {
return false;
}
}
- for (std::unique_ptr<const DexFile>& dex_file : dex_files_for_location) {
- process_fn(std::move(dex_file));
- }
}
return true;
}