diff options
author | 2024-08-18 16:37:00 +0100 | |
---|---|---|
committer | 2024-08-23 12:37:42 +0000 | |
commit | f797b3fabb29f93fe07ec70b9892184d599727bc (patch) | |
tree | 12996527d2dd3732d9f88d77e7890555dc25793d | |
parent | b17478f8e8f1b27dc8994d991cd0e8ec7c249c1b (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.cc | 31 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_loader.h | 10 | ||||
-rw-r--r-- | profman/profman.cc | 81 |
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; } |