perf: on Windows, make Archive::HeaderIntegrity()
faster (#46509)
* perf: do not clone the map each time we call Archive::HeaderIntegrity() * perf: use absl::flat_hash_map for the integrity cache * perf: do not clone the JSON payload string * perf: preallocate capacity for the integrity cache * perf: use move variant of insert_or_assign() * refactor: simplify integrity cache building remove unnecessary std::optional<> * refactor: use base::FindOrNull() * refactor: remove unused #includes * refactor: make variable types explicit * fix: make res_size unsigned * refactor: put GetIntegrityConfigCache() in an unnamed namespace refator: put LoadIntegrityConfig() in an unnamed namespace * fix: oops, missing rel_path_utf8 key * fix: oops, fix Wunreachable-code-return
This commit is contained in:
parent
41d8f90d68
commit
c0fdf09f28
1 changed files with 26 additions and 40 deletions
|
@ -6,9 +6,10 @@
|
||||||
#include "shell/common/asar/archive.h"
|
#include "shell/common/asar/archive.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <string_view>
|
||||||
|
|
||||||
#include "base/base_paths.h"
|
#include "base/base_paths.h"
|
||||||
|
#include "base/containers/map_util.h"
|
||||||
#include "base/json/json_reader.h"
|
#include "base/json/json_reader.h"
|
||||||
#include "base/logging.h"
|
#include "base/logging.h"
|
||||||
#include "base/no_destructor.h"
|
#include "base/no_destructor.h"
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
#include "base/strings/string_util_win.h"
|
#include "base/strings/string_util_win.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "shell/common/asar/asar_util.h"
|
#include "shell/common/asar/asar_util.h"
|
||||||
|
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"
|
||||||
|
|
||||||
namespace asar {
|
namespace asar {
|
||||||
|
|
||||||
|
@ -37,19 +39,10 @@ std::optional<base::FilePath> Archive::RelativePath() const {
|
||||||
return relative_path;
|
return relative_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::unordered_map<std::string, IntegrityPayload>>
|
namespace {
|
||||||
LoadIntegrityConfigCache() {
|
|
||||||
static base::NoDestructor<
|
|
||||||
std::optional<std::unordered_map<std::string, IntegrityPayload>>>
|
|
||||||
integrity_config_cache;
|
|
||||||
|
|
||||||
// Skip loading if cache is already loaded
|
auto LoadIntegrityConfig() {
|
||||||
if (integrity_config_cache->has_value()) {
|
absl::flat_hash_map<std::string, IntegrityPayload> cache;
|
||||||
return *integrity_config_cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init cache
|
|
||||||
*integrity_config_cache = std::unordered_map<std::string, IntegrityPayload>();
|
|
||||||
|
|
||||||
// Load integrity config from exe resource
|
// Load integrity config from exe resource
|
||||||
HMODULE module_handle = ::GetModuleHandle(NULL);
|
HMODULE module_handle = ::GetModuleHandle(NULL);
|
||||||
|
@ -65,8 +58,8 @@ LoadIntegrityConfigCache() {
|
||||||
PLOG(FATAL) << "LoadResource failed.";
|
PLOG(FATAL) << "LoadResource failed.";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* res_data = static_cast<const char*>(::LockResource(rcData));
|
const auto* res_data = static_cast<const char*>(::LockResource(rcData));
|
||||||
int res_size = SizeofResource(module_handle, resource);
|
const auto res_size = SizeofResource(module_handle, resource);
|
||||||
|
|
||||||
if (!res_data) {
|
if (!res_data) {
|
||||||
PLOG(FATAL) << "Failed to integrity config from exe resource.";
|
PLOG(FATAL) << "Failed to integrity config from exe resource.";
|
||||||
|
@ -77,9 +70,8 @@ LoadIntegrityConfigCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse integrity config payload
|
// Parse integrity config payload
|
||||||
std::string integrity_config_payload = std::string(res_data, res_size);
|
|
||||||
std::optional<base::Value> root =
|
std::optional<base::Value> root =
|
||||||
base::JSONReader::Read(integrity_config_payload);
|
base::JSONReader::Read(std::string_view{res_data, res_size});
|
||||||
|
|
||||||
if (!root.has_value()) {
|
if (!root.has_value()) {
|
||||||
LOG(FATAL) << "Invalid integrity config: NOT a valid JSON.";
|
LOG(FATAL) << "Invalid integrity config: NOT a valid JSON.";
|
||||||
|
@ -91,6 +83,7 @@ LoadIntegrityConfigCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse each individual file integrity config
|
// Parse each individual file integrity config
|
||||||
|
cache.reserve(file_configs->size());
|
||||||
for (size_t i = 0; i < file_configs->size(); i++) {
|
for (size_t i = 0; i < file_configs->size(); i++) {
|
||||||
// Skip invalid file configs
|
// Skip invalid file configs
|
||||||
const base::Value::Dict* ele_dict = (*file_configs)[i].GetIfDict();
|
const base::Value::Dict* ele_dict = (*file_configs)[i].GetIfDict();
|
||||||
|
@ -122,37 +115,30 @@ LoadIntegrityConfigCache() {
|
||||||
header_integrity.algorithm = HashAlgorithm::kSHA256;
|
header_integrity.algorithm = HashAlgorithm::kSHA256;
|
||||||
header_integrity.hash = base::ToLowerASCII(*value);
|
header_integrity.hash = base::ToLowerASCII(*value);
|
||||||
|
|
||||||
integrity_config_cache->value()[base::ToLowerASCII(*file)] =
|
cache.insert_or_assign(base::ToLowerASCII(*file),
|
||||||
std::move(header_integrity);
|
std::move(header_integrity));
|
||||||
}
|
}
|
||||||
|
|
||||||
return *integrity_config_cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto& GetIntegrityConfigCache() {
|
||||||
|
static const auto cache = base::NoDestructor(LoadIntegrityConfig());
|
||||||
|
return *cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
std::optional<IntegrityPayload> Archive::HeaderIntegrity() const {
|
std::optional<IntegrityPayload> Archive::HeaderIntegrity() const {
|
||||||
std::optional<base::FilePath> relative_path = RelativePath();
|
const std::optional<base::FilePath> relative_path = RelativePath();
|
||||||
// Callers should have already asserted this
|
CHECK(relative_path);
|
||||||
CHECK(relative_path.has_value());
|
|
||||||
|
|
||||||
// Load integrity config from exe resource
|
const auto key = base::ToLowerASCII(base::WideToUTF8(relative_path->value()));
|
||||||
std::optional<std::unordered_map<std::string, IntegrityPayload>>
|
|
||||||
integrity_config = LoadIntegrityConfigCache();
|
|
||||||
if (!integrity_config.has_value()) {
|
|
||||||
LOG(WARNING) << "Failed to integrity config from exe resource.";
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert Window rel path to UTF8 lower case
|
if (const auto* payload = base::FindOrNull(GetIntegrityConfigCache(), key))
|
||||||
std::string rel_path_utf8 = base::WideToUTF8(relative_path.value().value());
|
return *payload;
|
||||||
rel_path_utf8 = base::ToLowerASCII(rel_path_utf8);
|
|
||||||
|
|
||||||
// Find file integrity config
|
LOG(FATAL) << "Failed to find file integrity info for " << key;
|
||||||
auto iter = integrity_config.value().find(rel_path_utf8);
|
|
||||||
if (iter == integrity_config.value().end()) {
|
|
||||||
LOG(FATAL) << "Failed to find file integrity info for " << rel_path_utf8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return iter->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace asar
|
} // namespace asar
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue