Commit e72337f4 authored by Jered Gray's avatar Jered Gray Committed by Commit Bot

Reland "Eliminate unnecessary proto::Configuration copies"

This is a reland of 1b420fdb

The flakiness in the original CL with ResourceLoadingHintsBrowserTest
and PreviewsNoScriptBrowserTest has been fixed.
RetryForHistogramUntilCountReached() now flushes the task scheduler
and keeps trying until the test times out.

Original change's description:
> Eliminate unnecessary proto::Configuration copies
>
> The previous logic in OptimizationGuideService created an
> optimization_guide::proto::Configuration object on a background thread
> and then used task posting to send it on to
> PreviewsHints::CreateFromConfig(), where it was used to create a
> PreviewsHints object on another background thread. In all, there were
> two tasks posted that included the config object as a parameter, one on
> the background thread and one on the UI thread. Including it as a
> parameter in a task requires a full copy of the protobuffer. This means
> that a full copy of the config protobuf, which can be as large as 1.8MB
> (the size of the current Brazil one on Canary), was occurring on the UI
> thread.
>
> In local performance measurements, making a single copy of a 600KB
> version of the protobuf took several milliseconds (it amounted to
> roughly 60% of the time taken by the initial component string parsing
> and 60% of the time taken by PreviewHints::CreateFromConfig()). Given
> that we were incurring the cost of two copies, one of which was on an
> extremely high priority thread, it makes sense to change the logic to
> eliminate the need for the copies.
>
> The logic has been altered so that OptimizationGuideService no longer
> immediately processes the component, but instead notifies the
> observers that it is available and allows them to trigger the
> processing. This eliminates both copies of the configuration protobuf,
> as it is now created where it is used.
>
> Additionally, OptimizationGuideServiceObservers are now immediately
> notified of the hints component when they register if one is already
> available. This will enable the PreviewsOptimizationGuide to wait until
> the HintCacheLevelDBStore is fully initialized before registering for
> the component, and in the future will potentially allow it to avoid
> processing the configuration altogether when the store already has the
> latest version cached.
>
> New unittests have been added and older ones have been updated to
> accommodate the new logic.
>
> The related browser tests have also been modified to be more robust,
> where they now wait for a signal from a local histogram indicating
> that hint processing is complete.

Bug: 908985, 910251
Change-Id: I90407db4c19dac29e10f756a6de87294a9ab683b
Reviewed-on: https://chromium-review.googlesource.com/c/1355256
Commit-Queue: Jered Gray <jegray@chromium.org>
Reviewed-by: default avatarDoug Arnett <dougarnett@chromium.org>
Reviewed-by: default avatarJoshua Pawlicki <waffles@chromium.org>
Reviewed-by: default avatarTarun Bansal <tbansal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612408}
parent ffed3636
...@@ -90,10 +90,10 @@ void OptimizationHintsComponentInstallerPolicy::ComponentReady( ...@@ -90,10 +90,10 @@ void OptimizationHintsComponentInstallerPolicy::ComponentReady(
optimization_guide::OptimizationGuideService* optimization_guide_service = optimization_guide::OptimizationGuideService* optimization_guide_service =
g_browser_process->optimization_guide_service(); g_browser_process->optimization_guide_service();
if (optimization_guide_service) { if (optimization_guide_service) {
optimization_guide::ComponentInfo component_info( optimization_guide::HintsComponentInfo info(
version, version,
install_dir.Append(optimization_guide::kUnindexedHintsFileName)); install_dir.Append(optimization_guide::kUnindexedHintsFileName));
optimization_guide_service->ProcessHints(component_info); optimization_guide_service->MaybeUpdateHintsComponent(info);
} }
} }
......
...@@ -37,18 +37,18 @@ class TestOptimizationGuideService ...@@ -37,18 +37,18 @@ class TestOptimizationGuideService
: optimization_guide::OptimizationGuideService(io_thread_task_runner) {} : optimization_guide::OptimizationGuideService(io_thread_task_runner) {}
~TestOptimizationGuideService() override {} ~TestOptimizationGuideService() override {}
void ProcessHints( void MaybeUpdateHintsComponent(
const optimization_guide::ComponentInfo& component_info) override { const optimization_guide::HintsComponentInfo& info) override {
component_info_ = hints_component_info_ =
std::make_unique<optimization_guide::ComponentInfo>(component_info); std::make_unique<optimization_guide::HintsComponentInfo>(info);
} }
optimization_guide::ComponentInfo* component_info() const { optimization_guide::HintsComponentInfo* hints_component_info() const {
return component_info_.get(); return hints_component_info_.get();
} }
private: private:
std::unique_ptr<optimization_guide::ComponentInfo> component_info_; std::unique_ptr<optimization_guide::HintsComponentInfo> hints_component_info_;
DISALLOW_COPY_AND_ASSIGN(TestOptimizationGuideService); DISALLOW_COPY_AND_ASSIGN(TestOptimizationGuideService);
}; };
...@@ -204,7 +204,7 @@ TEST_F(OptimizationHintsComponentInstallerTest, NoRulesetFormatIgnored) { ...@@ -204,7 +204,7 @@ TEST_F(OptimizationHintsComponentInstallerTest, NoRulesetFormatIgnored) {
ASSERT_NO_FATAL_FAILURE(CreateTestOptimizationHints("some hints")); ASSERT_NO_FATAL_FAILURE(CreateTestOptimizationHints("some hints"));
ASSERT_NO_FATAL_FAILURE(LoadOptimizationHints(base::Version(""))); ASSERT_NO_FATAL_FAILURE(LoadOptimizationHints(base::Version("")));
EXPECT_EQ(nullptr, service()->component_info()); EXPECT_EQ(nullptr, service()->hints_component_info());
} }
TEST_F(OptimizationHintsComponentInstallerTest, FutureRulesetFormatIgnored) { TEST_F(OptimizationHintsComponentInstallerTest, FutureRulesetFormatIgnored) {
...@@ -217,7 +217,7 @@ TEST_F(OptimizationHintsComponentInstallerTest, FutureRulesetFormatIgnored) { ...@@ -217,7 +217,7 @@ TEST_F(OptimizationHintsComponentInstallerTest, FutureRulesetFormatIgnored) {
ASSERT_NO_FATAL_FAILURE( ASSERT_NO_FATAL_FAILURE(
LoadOptimizationHints(base::Version(future_ruleset_components))); LoadOptimizationHints(base::Version(future_ruleset_components)));
EXPECT_EQ(nullptr, service()->component_info()); EXPECT_EQ(nullptr, service()->hints_component_info());
} }
TEST_F(OptimizationHintsComponentInstallerTest, LoadFileWithData) { TEST_F(OptimizationHintsComponentInstallerTest, LoadFileWithData) {
...@@ -227,12 +227,11 @@ TEST_F(OptimizationHintsComponentInstallerTest, LoadFileWithData) { ...@@ -227,12 +227,11 @@ TEST_F(OptimizationHintsComponentInstallerTest, LoadFileWithData) {
ASSERT_NO_FATAL_FAILURE(CreateTestOptimizationHints(expected_hints)); ASSERT_NO_FATAL_FAILURE(CreateTestOptimizationHints(expected_hints));
ASSERT_NO_FATAL_FAILURE(LoadOptimizationHints(ruleset_format_version())); ASSERT_NO_FATAL_FAILURE(LoadOptimizationHints(ruleset_format_version()));
auto* component_info = service()->component_info(); auto* component_info = service()->hints_component_info();
EXPECT_NE(nullptr, component_info); EXPECT_NE(nullptr, component_info);
EXPECT_EQ(base::Version(kTestHintsVersion), component_info->hints_version); EXPECT_EQ(base::Version(kTestHintsVersion), component_info->version);
std::string actual_hints; std::string actual_hints;
ASSERT_TRUE( ASSERT_TRUE(base::ReadFileToString(component_info->path, &actual_hints));
base::ReadFileToString(component_info->hints_path, &actual_hints));
EXPECT_EQ(expected_hints, actual_hints); EXPECT_EQ(expected_hints, actual_hints);
} }
......
...@@ -7,19 +7,22 @@ ...@@ -7,19 +7,22 @@
#include "base/metrics/field_trial_params.h" #include "base/metrics/field_trial_params.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task/task_scheduler/task_scheduler.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/subprocess_metrics_provider.h"
#include "chrome/browser/previews/previews_ui_tab_helper.h" #include "chrome/browser/previews/previews_ui_tab_helper.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
#include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/optimization_guide_service.h"
#include "components/optimization_guide/optimization_guide_service_observer.h"
#include "components/optimization_guide/proto/hints.pb.h" #include "components/optimization_guide/proto/hints.pb.h"
#include "components/optimization_guide/test_component_creator.h" #include "components/optimization_guide/test_hints_component_creator.h"
#include "components/previews/core/previews_constants.h"
#include "components/previews/core/previews_features.h" #include "components/previews/core/previews_features.h"
#include "components/previews/core/previews_switches.h" #include "components/previews/core/previews_switches.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
...@@ -30,32 +33,28 @@ ...@@ -30,32 +33,28 @@
namespace { namespace {
// A test observer which can be configured to wait until the server hints are // Retries fetching |histogram_name| until it contains at least |count| samples.
// processed. void RetryForHistogramUntilCountReached(base::HistogramTester* histogram_tester,
class TestOptimizationGuideServiceObserver const std::string& histogram_name,
: public optimization_guide::OptimizationGuideServiceObserver { size_t count) {
public: while (true) {
TestOptimizationGuideServiceObserver() base::TaskScheduler::GetInstance()->FlushForTesting();
: run_loop_(std::make_unique<base::RunLoop>()) {} base::RunLoop().RunUntilIdle();
~TestOptimizationGuideServiceObserver() override {}
void WaitForNotification() { content::FetchHistogramsFromChildProcesses();
run_loop_->Run(); SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
run_loop_.reset(new base::RunLoop());
}
private: const std::vector<base::Bucket> buckets =
void OnHintsProcessed( histogram_tester->GetAllSamples(histogram_name);
const optimization_guide::proto::Configuration& config, size_t total_count = 0;
const optimization_guide::ComponentInfo& component_info) override { for (const auto& bucket : buckets) {
run_loop_->Quit(); total_count += bucket.count;
}
if (total_count >= count) {
break;
}
} }
}
std::unique_ptr<base::RunLoop> run_loop_;
DISALLOW_COPY_AND_ASSIGN(TestOptimizationGuideServiceObserver);
};
} // namespace } // namespace
...@@ -213,25 +212,26 @@ class PreviewsNoScriptBrowserTest : public PreviewsBrowserTest { ...@@ -213,25 +212,26 @@ class PreviewsNoScriptBrowserTest : public PreviewsBrowserTest {
void SetUpNoScriptWhitelist( void SetUpNoScriptWhitelist(
std::vector<std::string> whitelisted_noscript_sites) { std::vector<std::string> whitelisted_noscript_sites) {
TestOptimizationGuideServiceObserver observer; const optimization_guide::HintsComponentInfo& component_info =
g_browser_process->optimization_guide_service()->AddObserver(&observer); test_hints_component_creator_.CreateHintsComponentInfoWithPageHints(
base::RunLoop().RunUntilIdle();
const optimization_guide::ComponentInfo& component_info =
test_component_creator_.CreateComponentInfoWithPageHints(
optimization_guide::proto::NOSCRIPT, whitelisted_noscript_sites, optimization_guide::proto::NOSCRIPT, whitelisted_noscript_sites,
{}); {});
g_browser_process->optimization_guide_service()->ProcessHints(
base::HistogramTester histogram_tester;
g_browser_process->optimization_guide_service()->MaybeUpdateHintsComponent(
component_info); component_info);
// Wait for hints to be processed by PreviewsOptimizationGuide. RetryForHistogramUntilCountReached(
observer.WaitForNotification(); &histogram_tester,
base::RunLoop().RunUntilIdle(); previews::kPreviewsOptimizationGuideUpdateHintsResultHistogramString,
1);
} }
private: private:
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
optimization_guide::testing::TestComponentCreator test_component_creator_; optimization_guide::testing::TestHintsComponentCreator
test_hints_component_creator_;
}; };
// Previews InfoBar (which these tests triggers) does not work on Mac. // Previews InfoBar (which these tests triggers) does not work on Mac.
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
static_library("optimization_guide") { static_library("optimization_guide") {
sources = [ sources = [
"hints_component_info.h",
"hints_component_util.cc",
"hints_component_util.h",
"optimization_guide_constants.cc", "optimization_guide_constants.cc",
"optimization_guide_constants.h", "optimization_guide_constants.h",
"optimization_guide_service.cc", "optimization_guide_service.cc",
...@@ -22,8 +25,8 @@ static_library("optimization_guide") { ...@@ -22,8 +25,8 @@ static_library("optimization_guide") {
static_library("test_support") { static_library("test_support") {
testonly = true testonly = true
sources = [ sources = [
"test_component_creator.cc", "test_hints_component_creator.cc",
"test_component_creator.h", "test_hints_component_creator.h",
] ]
deps = [ deps = [
":optimization_guide", ":optimization_guide",
...@@ -36,6 +39,7 @@ static_library("test_support") { ...@@ -36,6 +39,7 @@ static_library("test_support") {
source_set("unit_tests") { source_set("unit_tests") {
testonly = true testonly = true
sources = [ sources = [
"hints_component_util_unittest.cc",
"optimization_guide_service_unittest.cc", "optimization_guide_service_unittest.cc",
"url_pattern_with_wildcards_unittest.cc", "url_pattern_with_wildcards_unittest.cc",
] ]
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OPTIMIZATION_GUIDE_HINTS_COMPONENT_INFO_H_
#define COMPONENTS_OPTIMIZATION_GUIDE_HINTS_COMPONENT_INFO_H_
#include "base/files/file_path.h"
#include "base/version.h"
namespace optimization_guide {
// Information about a version of optimization hints data received from the
// components server.
struct HintsComponentInfo {
HintsComponentInfo(const base::Version& version, const base::FilePath& path)
: version(version), path(path) {}
// The version of the hints content.
const base::Version version;
// The path to the file containing the hints protobuf file.
const base::FilePath path;
};
} // namespace optimization_guide
#endif // COMPONENTS_OPTIMIZATION_GUIDE_HINTS_COMPONENT_INFO_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/optimization_guide/hints_component_util.h"
#include <string>
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_macros.h"
#include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/proto/hints.pb.h"
namespace optimization_guide {
namespace {
void RecordProcessHintsComponentResult(ProcessHintsComponentResult result) {
UMA_HISTOGRAM_ENUMERATION(kProcessHintsComponentResultHistogramString,
static_cast<int>(result),
static_cast<int>(ProcessHintsComponentResult::MAX));
}
} // namespace
const char kProcessHintsComponentResultHistogramString[] =
"OptimizationGuide.ProcessHintsResult";
std::unique_ptr<proto::Configuration> ProcessHintsComponent(
const HintsComponentInfo& component_info) {
if (!component_info.version.IsValid() || component_info.path.empty()) {
RecordProcessHintsComponentResult(
ProcessHintsComponentResult::FAILED_INVALID_PARAMETERS);
return nullptr;
}
std::string binary_pb;
if (!base::ReadFileToString(component_info.path, &binary_pb)) {
RecordProcessHintsComponentResult(
ProcessHintsComponentResult::FAILED_READING_FILE);
return nullptr;
}
std::unique_ptr<proto::Configuration> proto_configuration =
std::make_unique<proto::Configuration>();
if (!proto_configuration->ParseFromString(binary_pb)) {
RecordProcessHintsComponentResult(
ProcessHintsComponentResult::FAILED_INVALID_CONFIGURATION);
return nullptr;
}
RecordProcessHintsComponentResult(ProcessHintsComponentResult::SUCCESS);
return proto_configuration;
}
} // namespace optimization_guide
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OPTIMIZATION_GUIDE_HINTS_COMPONENT_UTIL_H_
#define COMPONENTS_OPTIMIZATION_GUIDE_HINTS_COMPONENT_UTIL_H_
#include <memory>
namespace optimization_guide {
struct HintsComponentInfo;
namespace proto {
class Configuration;
} // namespace proto
// The UMA histogram used to record the result of processing the hints
// component.
extern const char kProcessHintsComponentResultHistogramString[];
// Enumerates the possible outcomes of processing the hints component. Used in
// UMA histograms, so the order of enumerators should not be changed.
//
// Keep in sync with OptimizationGuideProcessHintsResult in
// tools/metrics/histograms/enums.xml.
enum class ProcessHintsComponentResult {
SUCCESS,
FAILED_INVALID_PARAMETERS,
FAILED_READING_FILE,
FAILED_INVALID_CONFIGURATION,
// Insert new values before this line.
MAX,
};
// Processes the specified hints component, records the result in a UMA
// histogram, and, if successful, returns the component's Configuration
// protobuf. If unsuccessful, returns a nullptr.
std::unique_ptr<proto::Configuration> ProcessHintsComponent(
const HintsComponentInfo& info);
} // namespace optimization_guide
#endif // COMPONENTS_OPTIMIZATION_GUIDE_HINTS_COMPONENT_UTIL_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/optimization_guide/hints_component_util.h"
#include <string>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/version.h"
#include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace optimization_guide {
const base::FilePath::CharType kFileName[] = FILE_PATH_LITERAL("somefile.pb");
class HintsComponentUtilTest : public testing::Test {
public:
HintsComponentUtilTest() {}
~HintsComponentUtilTest() override {}
void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
void WriteConfigToFile(const base::FilePath& filePath,
const proto::Configuration& config) {
std::string serialized_config;
ASSERT_TRUE(config.SerializeToString(&serialized_config));
ASSERT_EQ(static_cast<int32_t>(serialized_config.length()),
base::WriteFile(filePath, serialized_config.data(),
serialized_config.length()));
}
base::FilePath temp_dir() const { return temp_dir_.GetPath(); }
private:
base::ScopedTempDir temp_dir_;
DISALLOW_COPY_AND_ASSIGN(HintsComponentUtilTest);
};
TEST_F(HintsComponentUtilTest, ProcessHintsComponentInvalidVersion) {
base::HistogramTester histogram_tester;
std::unique_ptr<proto::Configuration> config = ProcessHintsComponent(
HintsComponentInfo(base::Version(""), base::FilePath(kFileName)));
EXPECT_FALSE(config);
histogram_tester.ExpectUniqueSample(
kProcessHintsComponentResultHistogramString,
static_cast<int>(ProcessHintsComponentResult::FAILED_INVALID_PARAMETERS),
1);
}
TEST_F(HintsComponentUtilTest, ProcessHintsComponentInvalidPath) {
base::HistogramTester histogram_tester;
std::unique_ptr<proto::Configuration> config = ProcessHintsComponent(
HintsComponentInfo(base::Version("1.0.0.0"), base::FilePath()));
EXPECT_FALSE(config);
histogram_tester.ExpectUniqueSample(
kProcessHintsComponentResultHistogramString,
static_cast<int>(ProcessHintsComponentResult::FAILED_INVALID_PARAMETERS),
1);
}
TEST_F(HintsComponentUtilTest, ProcessHintsComponentInvalidFile) {
base::HistogramTester histogram_tester;
std::unique_ptr<proto::Configuration> config = ProcessHintsComponent(
HintsComponentInfo(base::Version("1.0.0"), base::FilePath(kFileName)));
EXPECT_FALSE(config);
histogram_tester.ExpectUniqueSample(
kProcessHintsComponentResultHistogramString,
static_cast<int>(ProcessHintsComponentResult::FAILED_READING_FILE), 1);
}
TEST_F(HintsComponentUtilTest, ProcessHintsComponentNotAConfigInFile) {
base::HistogramTester histogram_tester;
const base::FilePath filePath = temp_dir().Append(kFileName);
ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(filePath, "boo", 3));
std::unique_ptr<proto::Configuration> config = ProcessHintsComponent(
HintsComponentInfo(base::Version("1.0.0"), filePath));
EXPECT_FALSE(config);
histogram_tester.ExpectUniqueSample(
kProcessHintsComponentResultHistogramString,
static_cast<int>(
ProcessHintsComponentResult::FAILED_INVALID_CONFIGURATION),
1);
}
TEST_F(HintsComponentUtilTest, ProcessHintsComponentSuccess) {
base::HistogramTester histogram_tester;
const base::FilePath filePath = temp_dir().Append(kFileName);
proto::Configuration config;
proto::Hint* hint = config.add_hints();
hint->set_key("google.com");
ASSERT_NO_FATAL_FAILURE(WriteConfigToFile(filePath, config));
std::unique_ptr<proto::Configuration> processed_config =
ProcessHintsComponent(
HintsComponentInfo(base::Version("1.0.0"), filePath));
ASSERT_TRUE(processed_config);
EXPECT_EQ(1, processed_config->hints_size());
EXPECT_EQ("google.com", processed_config->hints()[0].key());
histogram_tester.ExpectUniqueSample(
kProcessHintsComponentResultHistogramString,
static_cast<int>(ProcessHintsComponentResult::SUCCESS), 1);
}
} // namespace optimization_guide
...@@ -4,59 +4,26 @@ ...@@ -4,59 +4,26 @@
#include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/optimization_guide_service.h"
#include <string>
#include "base/bind.h" #include "base/bind.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
namespace optimization_guide { namespace optimization_guide {
namespace {
// Version "0" corresponds to no processed version. By service conventions,
// we represent it as a dotted triple.
const char kNullVersion[] = "0.0.0";
void RecordProcessHintsResult(
OptimizationGuideService::ProcessHintsResult result) {
UMA_HISTOGRAM_ENUMERATION(
"OptimizationGuide.ProcessHintsResult", static_cast<int>(result),
static_cast<int>(OptimizationGuideService::ProcessHintsResult::MAX));
}
} // namespace
ComponentInfo::ComponentInfo(const base::Version& hints_version,
const base::FilePath& hints_path)
: hints_version(hints_version), hints_path(hints_path) {}
ComponentInfo::~ComponentInfo() {}
OptimizationGuideService::OptimizationGuideService( OptimizationGuideService::OptimizationGuideService(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread_task_runner) const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread_task_runner)
: background_task_runner_(base::CreateSequencedTaskRunnerWithTraits( : ui_thread_task_runner_(ui_thread_task_runner), weak_ptr_factory_(this) {
{base::MayBlock(), base::TaskPriority::BEST_EFFORT})),
ui_thread_task_runner_(ui_thread_task_runner),
latest_processed_version_(kNullVersion) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
} }
OptimizationGuideService::~OptimizationGuideService() {} OptimizationGuideService::~OptimizationGuideService() {}
void OptimizationGuideService::SetLatestProcessedVersionForTesting(
const base::Version& version) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
latest_processed_version_ = version;
}
void OptimizationGuideService::AddObserver( void OptimizationGuideService::AddObserver(
OptimizationGuideServiceObserver* observer) { OptimizationGuideServiceObserver* observer) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
observers_.AddObserver(observer); observers_.AddObserver(observer);
if (hints_component_info_) {
observer->OnHintsComponentAvailable(*hints_component_info_);
}
} }
void OptimizationGuideService::RemoveObserver( void OptimizationGuideService::RemoveObserver(
...@@ -65,55 +32,33 @@ void OptimizationGuideService::RemoveObserver( ...@@ -65,55 +32,33 @@ void OptimizationGuideService::RemoveObserver(
observers_.RemoveObserver(observer); observers_.RemoveObserver(observer);
} }
void OptimizationGuideService::ProcessHints( void OptimizationGuideService::MaybeUpdateHintsComponent(
const ComponentInfo& component_info) { const HintsComponentInfo& info) {
background_task_runner_->PostTask( ui_thread_task_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&OptimizationGuideService::ProcessHintsInBackground, base::BindOnce(
base::Unretained(this), component_info)); &OptimizationGuideService::MaybeUpdateHintsComponentOnUIThread,
weak_ptr_factory_.GetWeakPtr(), info));
} }
void OptimizationGuideService::ProcessHintsInBackground( void OptimizationGuideService::MaybeUpdateHintsComponentOnUIThread(
const ComponentInfo& component_info) { const HintsComponentInfo& info) {
DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(info.version.IsValid());
if (!component_info.hints_version.IsValid()) { DCHECK(!info.path.empty());
RecordProcessHintsResult(ProcessHintsResult::FAILED_INVALID_PARAMETERS);
return; // Do not update the component if the version isn't newer. This differs from
} // the check in ComponentInstaller::InstallHelper(), because this rejects
if (latest_processed_version_.CompareTo(component_info.hints_version) >= 0) // version equality, whereas InstallHelper() accepts it.
return; if (hints_component_info_ &&
if (component_info.hints_path.empty()) { hints_component_info_->version.CompareTo(info.version) >= 0) {
RecordProcessHintsResult(ProcessHintsResult::FAILED_INVALID_PARAMETERS);
return;
}
std::string binary_pb;
if (!base::ReadFileToString(component_info.hints_path, &binary_pb)) {
RecordProcessHintsResult(ProcessHintsResult::FAILED_READING_FILE);
return; return;
} }
proto::Configuration new_config; hints_component_info_.emplace(info.version, info.path);
if (!new_config.ParseFromString(binary_pb)) { for (auto& observer : observers_) {
RecordProcessHintsResult(ProcessHintsResult::FAILED_INVALID_CONFIGURATION); observer.OnHintsComponentAvailable(*hints_component_info_);
return;
} }
latest_processed_version_ = component_info.hints_version;
RecordProcessHintsResult(ProcessHintsResult::SUCCESS);
ui_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&OptimizationGuideService::DispatchHintsOnUIThread,
base::Unretained(this), new_config, component_info));
}
void OptimizationGuideService::DispatchHintsOnUIThread(
const proto::Configuration& config,
const ComponentInfo& component_info) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : observers_)
observer.OnHintsProcessed(config, component_info);
} }
} // namespace optimization_guide } // namespace optimization_guide
...@@ -5,69 +5,47 @@ ...@@ -5,69 +5,47 @@
#ifndef COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_H_ #ifndef COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_H_
#define COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_H_ #define COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_H_
#include <memory>
#include "base/files/file_path.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/optional.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/version.h" #include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/optimization_guide_service_observer.h" #include "components/optimization_guide/optimization_guide_service_observer.h"
#include "components/optimization_guide/proto/hints.pb.h"
namespace optimization_guide { namespace optimization_guide {
// Processes the hints downloaded from the Component Updater as part of the // Tracks the info for the current Optimization Hints component and notifies
// Optimization Hints component. // observers of newly available hints components downloaded from the Component
// Updater.
class OptimizationGuideService { class OptimizationGuideService {
public: public:
// Enumerates the possible outcomes of processing hints. Used in UMA
// histograms, so the order of enumerators should not be changed.
//
// Keep in sync with OptimizationGuideProcessHintsResult in
// tools/metrics/histograms/enums.xml.
enum class ProcessHintsResult {
SUCCESS,
FAILED_INVALID_PARAMETERS,
FAILED_READING_FILE,
FAILED_INVALID_CONFIGURATION,
// Insert new values before this line.
MAX,
};
explicit OptimizationGuideService( explicit OptimizationGuideService(
const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread_task_runner); const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread_task_runner);
virtual ~OptimizationGuideService(); virtual ~OptimizationGuideService();
// Adds the observer and synchronously dispatches the current
// HintsComponentInfo to it if one is already available.
void AddObserver(OptimizationGuideServiceObserver* observer); void AddObserver(OptimizationGuideServiceObserver* observer);
// Virtual so it can be mocked out in tests. // Virtual so it can be mocked out in tests.
virtual void RemoveObserver(OptimizationGuideServiceObserver* observer); virtual void RemoveObserver(OptimizationGuideServiceObserver* observer);
// Processes hints from the given unindexed hints, unless its |hints_version| // Forwards the update hints component request on to the UI thread, where the
// matches that of the most recently parsed version, in which case it does // actual work occurs.
// nothing.
// //
// Virtual so it can be mocked out in tests. // Virtual so it can be mocked out in tests.
virtual void ProcessHints(const ComponentInfo& component_info); virtual void MaybeUpdateHintsComponent(const HintsComponentInfo& info);
// Sets the latest processed version for testing.
void SetLatestProcessedVersionForTesting(const base::Version& version);
private: private:
// Always called as part of a BEST_EFFORT priority task. // If the hints component version in |info| is greater than that in
void ProcessHintsInBackground(const ComponentInfo& component_info); // |hints_component_info_|, updates |hints_component_info_| and dispatches it
// to all observers. In the case where the version is not greater, it does
// Dispatches hints to listeners on UI thread. // nothing.
void DispatchHintsOnUIThread(const proto::Configuration& config, void MaybeUpdateHintsComponentOnUIThread(const HintsComponentInfo& info);
const ComponentInfo& component_info);
// Runner for indexing tasks. // Runner for indexing tasks.
scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
// Runner for UI Thread tasks. // Runner for UI Thread tasks.
...@@ -76,7 +54,12 @@ class OptimizationGuideService { ...@@ -76,7 +54,12 @@ class OptimizationGuideService {
// Observers receiving notifications on hints being processed. // Observers receiving notifications on hints being processed.
base::ObserverList<OptimizationGuideServiceObserver>::Unchecked observers_; base::ObserverList<OptimizationGuideServiceObserver>::Unchecked observers_;
base::Version latest_processed_version_; // The current HintsComponentInfo available to observers. This is unset until
// the first time MaybeUpdateHintsComponent() is called.
base::Optional<HintsComponentInfo> hints_component_info_;
// Used to get |weak_ptr_| to self.
base::WeakPtrFactory<OptimizationGuideService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(OptimizationGuideService); DISALLOW_COPY_AND_ASSIGN(OptimizationGuideService);
}; };
......
...@@ -5,35 +5,20 @@ ...@@ -5,35 +5,20 @@
#ifndef COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_OBSERVER_H_ #ifndef COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_OBSERVER_H_
#define COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_OBSERVER_H_ #define COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_SERVICE_OBSERVER_H_
#include "base/version.h"
#include "components/optimization_guide/proto/hints.pb.h"
namespace optimization_guide { namespace optimization_guide {
// Encapsulates information about a version of optimization hints data received struct HintsComponentInfo;
// from the components server.
struct ComponentInfo {
ComponentInfo(const base::Version& hints_version,
const base::FilePath& hints_path);
~ComponentInfo();
// The version of the hints content.
const base::Version hints_version;
// The path to the file containing the hints protobuf file.
const base::FilePath hints_path;
};
// Interface for objects that wish to be notified of changes in the Optimization // Interface for objects that wish to be notified of changes in the Optimization
// Guide Service. // Guide Service.
// //
// All calls will be made on the IO thread. // All calls will be made on the UI thread.
class OptimizationGuideServiceObserver { class OptimizationGuideServiceObserver {
public: public:
// Called when the hints have been processed. // Called when a new hints component is available for processing. While this
virtual void OnHintsProcessed( // is called on the UI thread, it is recommended that processing of the new
const proto::Configuration& config, // component via ProcessHintsComponent() occur on a background thread.
const optimization_guide::ComponentInfo& component_info) = 0; virtual void OnHintsComponentAvailable(const HintsComponentInfo& info) = 0;
protected: protected:
virtual ~OptimizationGuideServiceObserver() {} virtual ~OptimizationGuideServiceObserver() {}
......
...@@ -2,29 +2,28 @@ ...@@ -2,29 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "components/optimization_guide/test_component_creator.h" #include "components/optimization_guide/test_hints_component_creator.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "base/version.h" #include "base/version.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace optimization_guide { namespace optimization_guide {
namespace testing { namespace testing {
TestComponentCreator::TestComponentCreator() TestHintsComponentCreator::TestHintsComponentCreator()
: scoped_temp_dir_(std::make_unique<base::ScopedTempDir>()), : scoped_temp_dir_(std::make_unique<base::ScopedTempDir>()),
next_component_version_(1) {} next_component_version_(1) {}
TestComponentCreator::~TestComponentCreator() { TestHintsComponentCreator::~TestHintsComponentCreator() {
base::ScopedAllowBlockingForTesting allow_blocking; base::ScopedAllowBlockingForTesting allow_blocking;
scoped_temp_dir_.reset(); scoped_temp_dir_.reset();
} }
optimization_guide::ComponentInfo optimization_guide::HintsComponentInfo
TestComponentCreator::CreateComponentInfoWithPageHints( TestHintsComponentCreator::CreateHintsComponentInfoWithPageHints(
optimization_guide::proto::OptimizationType optimization_type, optimization_guide::proto::OptimizationType optimization_type,
const std::vector<std::string>& page_hint_host_suffixes, const std::vector<std::string>& page_hint_host_suffixes,
const std::vector<std::string>& resource_blocking_patterns) { const std::vector<std::string>& resource_blocking_patterns) {
...@@ -50,11 +49,11 @@ TestComponentCreator::CreateComponentInfoWithPageHints( ...@@ -50,11 +49,11 @@ TestComponentCreator::CreateComponentInfoWithPageHints(
} }
} }
return WriteConfigToFileAndReturnComponentInfo(config); return WriteConfigToFileAndReturnHintsComponentInfo(config);
} }
optimization_guide::ComponentInfo optimization_guide::HintsComponentInfo
TestComponentCreator::CreateComponentInfoWithExperimentalPageHints( TestHintsComponentCreator::CreateHintsComponentInfoWithExperimentalPageHints(
optimization_guide::proto::OptimizationType optimization_type, optimization_guide::proto::OptimizationType optimization_type,
const std::vector<std::string>& page_hint_host_suffixes, const std::vector<std::string>& page_hint_host_suffixes,
const std::vector<std::string>& experimental_resource_patterns) { const std::vector<std::string>& experimental_resource_patterns) {
...@@ -81,11 +80,11 @@ TestComponentCreator::CreateComponentInfoWithExperimentalPageHints( ...@@ -81,11 +80,11 @@ TestComponentCreator::CreateComponentInfoWithExperimentalPageHints(
} }
} }
return WriteConfigToFileAndReturnComponentInfo(config); return WriteConfigToFileAndReturnHintsComponentInfo(config);
} }
optimization_guide::ComponentInfo optimization_guide::HintsComponentInfo
TestComponentCreator::CreateComponentInfoWithMixPageHints( TestHintsComponentCreator::CreateHintsComponentInfoWithMixPageHints(
optimization_guide::proto::OptimizationType optimization_type, optimization_guide::proto::OptimizationType optimization_type,
const std::vector<std::string>& page_hint_host_suffixes, const std::vector<std::string>& page_hint_host_suffixes,
const std::vector<std::string>& experimental_resource_patterns, const std::vector<std::string>& experimental_resource_patterns,
...@@ -130,17 +129,18 @@ TestComponentCreator::CreateComponentInfoWithMixPageHints( ...@@ -130,17 +129,18 @@ TestComponentCreator::CreateComponentInfoWithMixPageHints(
} }
} }
return WriteConfigToFileAndReturnComponentInfo(config); return WriteConfigToFileAndReturnHintsComponentInfo(config);
} }
base::FilePath TestComponentCreator::GetFilePath(std::string file_path_suffix) { base::FilePath TestHintsComponentCreator::GetFilePath(
std::string file_path_suffix) {
base::ScopedAllowBlockingForTesting allow_blocking; base::ScopedAllowBlockingForTesting allow_blocking;
EXPECT_TRUE(scoped_temp_dir_->IsValid() || EXPECT_TRUE(scoped_temp_dir_->IsValid() ||
scoped_temp_dir_->CreateUniqueTempDir()); scoped_temp_dir_->CreateUniqueTempDir());
return scoped_temp_dir_->GetPath().AppendASCII(file_path_suffix); return scoped_temp_dir_->GetPath().AppendASCII(file_path_suffix);
} }
void TestComponentCreator::WriteConfigToFile( void TestHintsComponentCreator::WriteConfigToFile(
const base::FilePath& file_path, const base::FilePath& file_path,
const optimization_guide::proto::Configuration& config) { const optimization_guide::proto::Configuration& config) {
base::ScopedAllowBlockingForTesting allow_blocking; base::ScopedAllowBlockingForTesting allow_blocking;
...@@ -153,14 +153,14 @@ void TestComponentCreator::WriteConfigToFile( ...@@ -153,14 +153,14 @@ void TestComponentCreator::WriteConfigToFile(
serialized_config.length())); serialized_config.length()));
} }
optimization_guide::ComponentInfo optimization_guide::HintsComponentInfo
TestComponentCreator::WriteConfigToFileAndReturnComponentInfo( TestHintsComponentCreator::WriteConfigToFileAndReturnHintsComponentInfo(
const optimization_guide::proto::Configuration& config) { const optimization_guide::proto::Configuration& config) {
std::string version_string = base::IntToString(next_component_version_++); std::string version_string = base::IntToString(next_component_version_++);
base::FilePath file_path = GetFilePath(version_string); base::FilePath file_path = GetFilePath(version_string);
WriteConfigToFile(file_path, config); WriteConfigToFile(file_path, config);
return optimization_guide::ComponentInfo(base::Version(version_string), return optimization_guide::HintsComponentInfo(base::Version(version_string),
file_path); file_path);
} }
} // namespace testing } // namespace testing
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef COMPONENTS_OPTIMIZATION_GUIDE_TEST_COMPONENT_CREATOR_H_ #ifndef COMPONENTS_OPTIMIZATION_GUIDE_TEST_HINTS_COMPONENT_CREATOR_H_
#define COMPONENTS_OPTIMIZATION_GUIDE_TEST_COMPONENT_CREATOR_H_ #define COMPONENTS_OPTIMIZATION_GUIDE_TEST_HINTS_COMPONENT_CREATOR_H_
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/macros.h" #include "base/macros.h"
#include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/optimization_guide_service.h"
#include "components/optimization_guide/proto/hints.pb.h"
namespace optimization_guide { namespace optimization_guide {
namespace testing { namespace testing {
...@@ -23,31 +24,31 @@ static const char kFooExperimentName[] = "foo_experiment"; ...@@ -23,31 +24,31 @@ static const char kFooExperimentName[] = "foo_experiment";
// //
// All temporary files and paths are cleaned up when this instance goes out of // All temporary files and paths are cleaned up when this instance goes out of
// scope. // scope.
class TestComponentCreator { class TestHintsComponentCreator {
public: public:
TestComponentCreator(); TestHintsComponentCreator();
~TestComponentCreator(); ~TestHintsComponentCreator();
// Creates component data based on |whitelisted_host_suffixes| with page hints // Creates component data based on |whitelisted_host_suffixes| with page hints
// for type |optimization_type| blocking resources specified by // for type |optimization_type| blocking resources specified by
// |resource_patterns|, and returns the ComponentInfo for it. // |resource_patterns|, and returns the HintsComponentInfo for it.
optimization_guide::ComponentInfo CreateComponentInfoWithPageHints( optimization_guide::HintsComponentInfo CreateHintsComponentInfoWithPageHints(
optimization_guide::proto::OptimizationType optimization_type, optimization_guide::proto::OptimizationType optimization_type,
const std::vector<std::string>& whitelisted_host_suffixes, const std::vector<std::string>& whitelisted_host_suffixes,
const std::vector<std::string>& resource_patterns); const std::vector<std::string>& resource_patterns);
// Creates component data based on |whitelisted_host_suffixes| with page hints // Creates component data based on |whitelisted_host_suffixes| with page hints
// for type |optimization_type| blocking resources specified by // for type |optimization_type| blocking resources specified by
// |experimental_resource_patterns|, and returns the ComponentInfo for it. // |experimental_resource_patterns|, and returns the HintsComponentInfo for
// The loading hints are set as experimental with experiment name set to // it. The loading hints are set as experimental with experiment name set to
// kFooExperimentName. // kFooExperimentName.
// Creates component data for testing with experimental optimizations. It // Creates component data for testing with experimental optimizations. It
// creates a PageHint (with page pattern "*" for each key in // creates a PageHint (with page pattern "*" for each key in
// |whitelisted_host_suffixes| that each has resource blocking patterns from // |whitelisted_host_suffixes| that each has resource blocking patterns from
// |experimental_resource_patterns|. // |experimental_resource_patterns|.
optimization_guide::ComponentInfo optimization_guide::HintsComponentInfo
CreateComponentInfoWithExperimentalPageHints( CreateHintsComponentInfoWithExperimentalPageHints(
optimization_guide::proto::OptimizationType optimization_type, optimization_guide::proto::OptimizationType optimization_type,
const std::vector<std::string>& whitelisted_host_suffixes, const std::vector<std::string>& whitelisted_host_suffixes,
const std::vector<std::string>& experimental_resource_patterns); const std::vector<std::string>& experimental_resource_patterns);
...@@ -57,7 +58,8 @@ class TestComponentCreator { ...@@ -57,7 +58,8 @@ class TestComponentCreator {
// |whitelisted_host_suffixes| that each has resource blocking patterns from // |whitelisted_host_suffixes| that each has resource blocking patterns from
// |default_resource_patterns| and |experimental_resource_patterns|. The // |default_resource_patterns| and |experimental_resource_patterns|. The
// experimental hints are guarded behind experiment kFooExperimentName. // experimental hints are guarded behind experiment kFooExperimentName.
optimization_guide::ComponentInfo CreateComponentInfoWithMixPageHints( optimization_guide::HintsComponentInfo
CreateHintsComponentInfoWithMixPageHints(
optimization_guide::proto::OptimizationType optimization_type, optimization_guide::proto::OptimizationType optimization_type,
const std::vector<std::string>& whitelisted_host_suffixes, const std::vector<std::string>& whitelisted_host_suffixes,
const std::vector<std::string>& experimental_resource_patterns, const std::vector<std::string>& experimental_resource_patterns,
...@@ -75,17 +77,18 @@ class TestComponentCreator { ...@@ -75,17 +77,18 @@ class TestComponentCreator {
const optimization_guide::proto::Configuration& config); const optimization_guide::proto::Configuration& config);
// Writes a configuration of hints to the file path and returns the // Writes a configuration of hints to the file path and returns the
// ComponentInfo for it. // HintsComponentInfo for it.
optimization_guide::ComponentInfo WriteConfigToFileAndReturnComponentInfo( optimization_guide::HintsComponentInfo
WriteConfigToFileAndReturnHintsComponentInfo(
const optimization_guide::proto::Configuration& config); const optimization_guide::proto::Configuration& config);
std::unique_ptr<base::ScopedTempDir> scoped_temp_dir_; std::unique_ptr<base::ScopedTempDir> scoped_temp_dir_;
int next_component_version_; int next_component_version_;
DISALLOW_COPY_AND_ASSIGN(TestComponentCreator); DISALLOW_COPY_AND_ASSIGN(TestHintsComponentCreator);
}; };
} // namespace testing } // namespace testing
} // namespace optimization_guide } // namespace optimization_guide
#endif // COMPONENTS_OPTIMIZATION_GUIDE_TEST_COMPONENT_CREATOR_H_ #endif // COMPONENTS_OPTIMIZATION_GUIDE_TEST_HINTS_COMPONENT_CREATOR_H_
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "components/optimization_guide/optimization_guide_service_observer.h" #include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/hints_component_util.h"
#include "components/optimization_guide/url_pattern_with_wildcards.h" #include "components/optimization_guide/url_pattern_with_wildcards.h"
#include "components/previews/core/bloom_filter.h" #include "components/previews/core/bloom_filter.h"
#include "components/previews/core/previews_features.h" #include "components/previews/core/previews_features.h"
...@@ -39,7 +40,7 @@ const base::FilePath::CharType kSentinelFileName[] = ...@@ -39,7 +40,7 @@ const base::FilePath::CharType kSentinelFileName[] =
// Returns false if the processing should not continue because the // Returns false if the processing should not continue because the
// file exists with the same version (indicating that processing that version // file exists with the same version (indicating that processing that version
// failed previously (possibly crash or shutdown). Should be run in the // failed previously (possibly crash or shutdown). Should be run in the
// background (e.g., same task as Hints.CreateFromConfig). // background (e.g., same task as PreviewsHints::CreateFromHintsComponent()).
bool CreateSentinelFile(const base::FilePath& sentinel_path, bool CreateSentinelFile(const base::FilePath& sentinel_path,
const base::Version& version) { const base::Version& version) {
DCHECK(version.IsValid()); DCHECK(version.IsValid());
...@@ -297,12 +298,16 @@ PreviewsHints::~PreviewsHints() { ...@@ -297,12 +298,16 @@ PreviewsHints::~PreviewsHints() {
} }
// static // static
std::unique_ptr<PreviewsHints> PreviewsHints::CreateFromConfig( std::unique_ptr<PreviewsHints> PreviewsHints::CreateFromHintsComponent(
const optimization_guide::proto::Configuration& config, const optimization_guide::HintsComponentInfo& info) {
const optimization_guide::ComponentInfo& info) { std::unique_ptr<optimization_guide::proto::Configuration> config =
base::FilePath sentinel_path( ProcessHintsComponent(info);
info.hints_path.DirName().Append(kSentinelFileName)); if (!config) {
if (!CreateSentinelFile(sentinel_path, info.hints_version)) { return nullptr;
}
base::FilePath sentinel_path(info.path.DirName().Append(kSentinelFileName));
if (!CreateSentinelFile(sentinel_path, info.version)) {
std::unique_ptr<PreviewsHints> no_hints; std::unique_ptr<PreviewsHints> no_hints;
RecordProcessHintsResult( RecordProcessHintsResult(
PreviewsProcessHintsResult::kFailedFinishProcessing); PreviewsProcessHintsResult::kFailedFinishProcessing);
...@@ -323,7 +328,7 @@ std::unique_ptr<PreviewsHints> PreviewsHints::CreateFromConfig( ...@@ -323,7 +328,7 @@ std::unique_ptr<PreviewsHints> PreviewsHints::CreateFromConfig(
size_t total_page_patterns_with_resource_loading_hints_received = 0; size_t total_page_patterns_with_resource_loading_hints_received = 0;
size_t total_resource_loading_hints_received = 0; size_t total_resource_loading_hints_received = 0;
// Process hint configuration. // Process hint configuration.
for (const auto& hint : config.hints()) { for (const auto& hint : config->hints()) {
// We only support host suffixes at the moment. Skip anything else. // We only support host suffixes at the moment. Skip anything else.
// One |hint| applies to one host URL suffix. // One |hint| applies to one host URL suffix.
if (hint.key_representation() != optimization_guide::proto::HOST_SUFFIX) if (hint.key_representation() != optimization_guide::proto::HOST_SUFFIX)
...@@ -400,7 +405,7 @@ std::unique_ptr<PreviewsHints> PreviewsHints::CreateFromConfig( ...@@ -400,7 +405,7 @@ std::unique_ptr<PreviewsHints> PreviewsHints::CreateFromConfig(
} }
// Extract any supported large scale blacklists from the configuration. // Extract any supported large scale blacklists from the configuration.
hints->ParseOptimizationFilters(config); hints->ParseOptimizationFilters(*config);
// Completed processing hints data without crashing so clear sentinel. // Completed processing hints data without crashing so clear sentinel.
DeleteSentinelFile(sentinel_path); DeleteSentinelFile(sentinel_path);
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
class GURL; class GURL;
namespace optimization_guide { namespace optimization_guide {
struct ComponentInfo; struct HintsComponentInfo;
} }
namespace previews { namespace previews {
...@@ -34,10 +34,11 @@ class PreviewsHints { ...@@ -34,10 +34,11 @@ class PreviewsHints {
public: public:
~PreviewsHints(); ~PreviewsHints();
// Creates a Hints instance from the provided configuration. // Creates a Hints instance from the provided hints component. This must be
static std::unique_ptr<PreviewsHints> CreateFromConfig( // called using a background task runner as it requires a significant amount
const optimization_guide::proto::Configuration& config, // of processing.
const optimization_guide::ComponentInfo& info); static std::unique_ptr<PreviewsHints> CreateFromHintsComponent(
const optimization_guide::HintsComponentInfo& info);
static std::unique_ptr<PreviewsHints> CreateForTesting( static std::unique_ptr<PreviewsHints> CreateForTesting(
std::unique_ptr<HostFilter> lite_page_redirect_blacklist); std::unique_ptr<HostFilter> lite_page_redirect_blacklist);
......
...@@ -4,11 +4,14 @@ ...@@ -4,11 +4,14 @@
#include "components/previews/content/previews_hints.h" #include "components/previews/content/previews_hints.h"
#include <string>
#include "base/command_line.h" #include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "components/optimization_guide/optimization_guide_service_observer.h" #include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/proto/hints.pb.h" #include "components/optimization_guide/proto/hints.pb.h"
#include "components/previews/core/previews_features.h" #include "components/previews/core/previews_features.h"
#include "components/previews/core/previews_switches.h" #include "components/previews/core/previews_switches.h"
...@@ -32,17 +35,18 @@ class TestHostFilter : public previews::HostFilter { ...@@ -32,17 +35,18 @@ class TestHostFilter : public previews::HostFilter {
class PreviewsHintsTest : public testing::Test { class PreviewsHintsTest : public testing::Test {
public: public:
explicit PreviewsHintsTest() : previews_hints_(nullptr) {} PreviewsHintsTest() : previews_hints_(nullptr) {}
~PreviewsHintsTest() override {} ~PreviewsHintsTest() override {}
void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
void ParseConfig(const optimization_guide::proto::Configuration& config) { void ParseConfig(const optimization_guide::proto::Configuration& config) {
optimization_guide::ComponentInfo info( optimization_guide::HintsComponentInfo info(
base::Version("1.0"), base::Version("1.0"),
temp_dir_.GetPath().Append(FILE_PATH_LITERAL("somefile.pb"))); temp_dir_.GetPath().Append(FILE_PATH_LITERAL("somefile.pb")));
previews_hints_ = PreviewsHints::CreateFromConfig(config, info); ASSERT_NO_FATAL_FAILURE(WriteConfigToFile(config, info.path));
previews_hints_ = PreviewsHints::CreateFromHintsComponent(info);
previews_hints_->Initialize(); previews_hints_->Initialize();
} }
...@@ -53,6 +57,15 @@ class PreviewsHintsTest : public testing::Test { ...@@ -53,6 +57,15 @@ class PreviewsHintsTest : public testing::Test {
} }
private: private:
void WriteConfigToFile(const optimization_guide::proto::Configuration& config,
const base::FilePath& filePath) {
std::string serialized_config;
ASSERT_TRUE(config.SerializeToString(&serialized_config));
ASSERT_EQ(static_cast<int32_t>(serialized_config.length()),
base::WriteFile(filePath, serialized_config.data(),
serialized_config.length()));
}
base::ScopedTempDir temp_dir_; base::ScopedTempDir temp_dir_;
std::unique_ptr<PreviewsHints> previews_hints_; std::unique_ptr<PreviewsHints> previews_hints_;
}; };
......
...@@ -8,9 +8,12 @@ ...@@ -8,9 +8,12 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task_runner_util.h" #include "base/task_runner_util.h"
#include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/optimization_guide_service.h"
#include "components/optimization_guide/proto/hints.pb.h" #include "components/optimization_guide/proto/hints.pb.h"
#include "components/previews/content/previews_hints.h" #include "components/previews/content/previews_hints.h"
#include "components/previews/content/previews_user_data.h" #include "components/previews/content/previews_user_data.h"
#include "components/previews/core/previews_constants.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace previews { namespace previews {
...@@ -122,14 +125,13 @@ void PreviewsOptimizationGuide::LogHintCacheMatch( ...@@ -122,14 +125,13 @@ void PreviewsOptimizationGuide::LogHintCacheMatch(
hints_->LogHintCacheMatch(url, is_committed, ect); hints_->LogHintCacheMatch(url, is_committed, ect);
} }
void PreviewsOptimizationGuide::OnHintsProcessed( void PreviewsOptimizationGuide::OnHintsComponentAvailable(
const optimization_guide::proto::Configuration& config, const optimization_guide::HintsComponentInfo& info) {
const optimization_guide::ComponentInfo& info) {
DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(ui_task_runner_->BelongsToCurrentThread());
base::PostTaskAndReplyWithResult( base::PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE, background_task_runner_.get(), FROM_HERE,
base::BindOnce(&PreviewsHints::CreateFromConfig, config, info), base::BindOnce(&PreviewsHints::CreateFromHintsComponent, info),
base::BindOnce(&PreviewsOptimizationGuide::UpdateHints, base::BindOnce(&PreviewsOptimizationGuide::UpdateHints,
ui_weak_ptr_factory_.GetWeakPtr())); ui_weak_ptr_factory_.GetWeakPtr()));
} }
...@@ -138,8 +140,15 @@ void PreviewsOptimizationGuide::UpdateHints( ...@@ -138,8 +140,15 @@ void PreviewsOptimizationGuide::UpdateHints(
std::unique_ptr<PreviewsHints> hints) { std::unique_ptr<PreviewsHints> hints) {
DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(ui_task_runner_->BelongsToCurrentThread());
hints_ = std::move(hints); hints_ = std::move(hints);
if (hints_) if (hints_) {
hints_->Initialize(); hints_->Initialize();
}
// Record the result of updating the hints. This is used as a signal for the
// hints being fully processed in testing.
LOCAL_HISTOGRAM_BOOLEAN(
kPreviewsOptimizationGuideUpdateHintsResultHistogramString,
hints_ != NULL);
} }
} // namespace previews } // namespace previews
...@@ -13,15 +13,16 @@ ...@@ -13,15 +13,16 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "components/optimization_guide/optimization_guide_service.h"
#include "components/optimization_guide/optimization_guide_service_observer.h" #include "components/optimization_guide/optimization_guide_service_observer.h"
#include "components/previews/content/previews_optimization_guide.h" #include "components/previews/content/previews_optimization_guide.h"
#include "components/previews/core/previews_experiments.h" #include "components/previews/core/previews_experiments.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace optimization_guide { namespace optimization_guide {
struct HintsComponentInfo;
class OptimizationGuideService;
namespace proto { namespace proto {
class Configuration; class Hint;
} // namespace proto } // namespace proto
} // namespace optimization_guide } // namespace optimization_guide
...@@ -75,9 +76,8 @@ class PreviewsOptimizationGuide ...@@ -75,9 +76,8 @@ class PreviewsOptimizationGuide
net::EffectiveConnectionType ect) const; net::EffectiveConnectionType ect) const;
// optimization_guide::OptimizationGuideServiceObserver implementation: // optimization_guide::OptimizationGuideServiceObserver implementation:
void OnHintsProcessed( void OnHintsComponentAvailable(
const optimization_guide::proto::Configuration& config, const optimization_guide::HintsComponentInfo& info) override;
const optimization_guide::ComponentInfo& component_info) override;
private: private:
// Updates the hints to the latest hints sent by the Component Updater. // Updates the hints to the latest hints sent by the Component Updater.
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "components/optimization_guide/hints_component_info.h"
#include "components/optimization_guide/optimization_guide_service.h" #include "components/optimization_guide/optimization_guide_service.h"
#include "components/optimization_guide/optimization_guide_service_observer.h"
#include "components/optimization_guide/proto/hints.pb.h" #include "components/optimization_guide/proto/hints.pb.h"
#include "components/previews/content/previews_user_data.h" #include "components/previews/content/previews_user_data.h"
#include "components/previews/core/bloom_filter.h" #include "components/previews/core/bloom_filter.h"
...@@ -80,11 +80,12 @@ class PreviewsOptimizationGuideTest : public testing::Test { ...@@ -80,11 +80,12 @@ class PreviewsOptimizationGuideTest : public testing::Test {
} }
void ProcessHints(const optimization_guide::proto::Configuration& config, void ProcessHints(const optimization_guide::proto::Configuration& config,
std::string version) { const std::string& version) {
optimization_guide::ComponentInfo info( optimization_guide::HintsComponentInfo info(
base::Version(version), base::Version(version),
temp_dir().Append(FILE_PATH_LITERAL("somefile.pb"))); temp_dir().Append(FILE_PATH_LITERAL("somefile.pb")));
guide_->OnHintsProcessed(config, info); ASSERT_NO_FATAL_FAILURE(WriteConfigToFile(config, info.path));
guide_->OnHintsComponentAvailable(info);
} }
void MaybeLoadOptimizationHintsCallback( void MaybeLoadOptimizationHintsCallback(
...@@ -137,6 +138,15 @@ class PreviewsOptimizationGuideTest : public testing::Test { ...@@ -137,6 +138,15 @@ class PreviewsOptimizationGuideTest : public testing::Test {
void InitializeWithLitePageRedirectBlacklist(); void InitializeWithLitePageRedirectBlacklist();
private: private:
void WriteConfigToFile(const optimization_guide::proto::Configuration& config,
const base::FilePath& filePath) {
std::string serialized_config;
ASSERT_TRUE(config.SerializeToString(&serialized_config));
ASSERT_EQ(static_cast<int32_t>(serialized_config.length()),
base::WriteFile(filePath, serialized_config.data(),
serialized_config.length()));
}
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_;
base::ScopedTempDir temp_dir_; base::ScopedTempDir temp_dir_;
......
...@@ -10,6 +10,8 @@ static_library("core") { ...@@ -10,6 +10,8 @@ static_library("core") {
"host_filter.h", "host_filter.h",
"previews_black_list.cc", "previews_black_list.cc",
"previews_black_list.h", "previews_black_list.h",
"previews_constants.cc",
"previews_constants.h",
"previews_decider.h", "previews_decider.h",
"previews_experiments.cc", "previews_experiments.cc",
"previews_experiments.h", "previews_experiments.h",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/previews/core/previews_constants.h"
namespace previews {
const char kPreviewsOptimizationGuideUpdateHintsResultHistogramString[] =
"PreviewsOptimizationGuide.UpdateHints.Result";
} // namespace previews
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PREVIEWS_CORE_PREVIEWS_CONSTANTS_H_
#define COMPONENTS_PREVIEWS_CORE_PREVIEWS_CONSTANTS_H_
namespace previews {
// The local histogram used by PreviewsOptimizationGuide to record the result of
// UpdateHints().
extern const char kPreviewsOptimizationGuideUpdateHintsResultHistogramString[];
} // namespace previews
#endif // COMPONENTS_PREVIEWS_CORE_PREVIEWS_CONSTANTS_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment