blob: 233b164abf0a50b5ef664506cd127b606c0296dc [file] [log] [blame]
// Copyright 2020 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 "chrome/browser/optimization_guide/blink/blink_optimization_guide_inquirer.h"
#include "base/memory/ptr_util.h"
#include "chrome/browser/optimization_guide/blink/blink_optimization_guide_feature_flag_helper.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "components/optimization_guide/proto/delay_async_script_execution_metadata.pb.h"
#include "components/optimization_guide/proto/delay_competing_low_priority_requests_metadata.pb.h"
#include "components/optimization_guide/proto/hints.pb.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
namespace optimization_guide {
// static
std::unique_ptr<BlinkOptimizationGuideInquirer>
BlinkOptimizationGuideInquirer::CreateAndStart(
content::NavigationHandle& navigation_handle,
OptimizationGuideDecider& decider) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto inquirer = base::WrapUnique(new BlinkOptimizationGuideInquirer());
inquirer->InquireHints(navigation_handle, decider);
return inquirer;
}
BlinkOptimizationGuideInquirer::~BlinkOptimizationGuideInquirer() = default;
BlinkOptimizationGuideInquirer::BlinkOptimizationGuideInquirer()
: optimization_guide_hints_(
blink::mojom::BlinkOptimizationGuideHints::New()) {}
void BlinkOptimizationGuideInquirer::InquireHints(
content::NavigationHandle& navigation_handle,
OptimizationGuideDecider& decider) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::vector<proto::OptimizationType> supported_optimization_types;
if (features::ShouldUseOptimizationGuideForDelayAsyncScript()) {
supported_optimization_types.push_back(
proto::OptimizationType::DELAY_ASYNC_SCRIPT_EXECUTION);
}
if (features::
ShouldUseOptimizationGuideForDelayCompetingLowPriorityRequests()) {
supported_optimization_types.push_back(
proto::OptimizationType::DELAY_COMPETING_LOW_PRIORITY_REQUESTS);
}
for (auto optimization_type : supported_optimization_types) {
// CanApplyOptimizationAsync() synchronously runs the callback when the
// hints are already available.
decider.CanApplyOptimizationAsync(
&navigation_handle, optimization_type,
base::BindOnce(&BlinkOptimizationGuideInquirer::DidInquireHints,
weak_ptr_factory_.GetWeakPtr(), optimization_type));
}
}
void BlinkOptimizationGuideInquirer::DidInquireHints(
proto::OptimizationType optimization_type,
OptimizationGuideDecision decision,
const OptimizationMetadata& metadata) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
switch (decision) {
case OptimizationGuideDecision::kTrue:
break;
case OptimizationGuideDecision::kUnknown:
case OptimizationGuideDecision::kFalse:
// The optimization guide service decided not to provide the hints.
return;
}
switch (optimization_type) {
case proto::OptimizationType::DELAY_ASYNC_SCRIPT_EXECUTION:
PopulateHintsForDelayAsyncScriptExecution(metadata);
break;
case proto::OptimizationType::DELAY_COMPETING_LOW_PRIORITY_REQUESTS:
PopulateHintsForDelayCompetingLowPriorityRequests(metadata);
break;
default:
NOTREACHED();
break;
}
}
void BlinkOptimizationGuideInquirer::PopulateHintsForDelayAsyncScriptExecution(
const OptimizationMetadata& optimization_metadata) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Give up providing the hints when the metadata is not available.
base::Optional<proto::DelayAsyncScriptExecutionMetadata> metadata =
optimization_metadata
.ParsedMetadata<proto::DelayAsyncScriptExecutionMetadata>();
if (!metadata || !metadata->delay_type())
return;
// Populate the metadata into the hints.
using blink::mojom::DelayAsyncScriptExecutionDelayType;
auto hints = blink::mojom::DelayAsyncScriptExecutionHints::New();
switch (metadata->delay_type()) {
case proto::PerfectHeuristicsDelayType::DELAY_TYPE_UNKNOWN:
hints->delay_type = DelayAsyncScriptExecutionDelayType::kUnknown;
break;
case proto::PerfectHeuristicsDelayType::DELAY_TYPE_FINISHED_PARSING:
hints->delay_type = DelayAsyncScriptExecutionDelayType::kFinishedParsing;
break;
case proto::PerfectHeuristicsDelayType::
DELAY_TYPE_FIRST_PAINT_OR_FINISHED_PARSING:
hints->delay_type =
DelayAsyncScriptExecutionDelayType::kFirstPaintOrFinishedParsing;
break;
case proto::PerfectHeuristicsDelayType::DELAY_TYPE_FIRST_PAINT:
case proto::PerfectHeuristicsDelayType::DELAY_TYPE_FIRST_CONTENTFUL_PAINT:
// DelayAsyncScriptExecution doesn't support these milestones.
NOTREACHED();
return;
}
DCHECK(!optimization_guide_hints_->delay_async_script_execution_hints);
optimization_guide_hints_->delay_async_script_execution_hints =
std::move(hints);
}
void BlinkOptimizationGuideInquirer::
PopulateHintsForDelayCompetingLowPriorityRequests(
const OptimizationMetadata& optimization_metadata) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Give up providing the hints when the metadata is not available.
base::Optional<proto::DelayCompetingLowPriorityRequestsMetadata> metadata =
optimization_metadata
.ParsedMetadata<proto::DelayCompetingLowPriorityRequestsMetadata>();
if (!metadata || !metadata->delay_type() || !metadata->priority_threshold())
return;
// Populate the metadata into the hints.
using ProtoDelayType = proto::PerfectHeuristicsDelayType;
using MojomDelayType =
blink::mojom::DelayCompetingLowPriorityRequestsDelayType;
auto hints = blink::mojom::DelayCompetingLowPriorityRequestsHints::New();
switch (metadata->delay_type()) {
case ProtoDelayType::DELAY_TYPE_UNKNOWN:
hints->delay_type = MojomDelayType::kUnknown;
break;
case ProtoDelayType::DELAY_TYPE_FIRST_PAINT:
hints->delay_type = MojomDelayType::kFirstPaint;
break;
case ProtoDelayType::DELAY_TYPE_FIRST_CONTENTFUL_PAINT:
hints->delay_type = MojomDelayType::kFirstContentfulPaint;
break;
case ProtoDelayType::DELAY_TYPE_FINISHED_PARSING:
case ProtoDelayType::DELAY_TYPE_FIRST_PAINT_OR_FINISHED_PARSING:
// DelayCompetingLowPriorityRequests doesn't support these milestones.
NOTREACHED();
return;
}
using MojomPriorityThreshold =
blink::mojom::DelayCompetingLowPriorityRequestsPriorityThreshold;
switch (metadata->priority_threshold()) {
case proto::PriorityThreshold::PRIORITY_THRESHOLD_UNKNOWN:
hints->priority_threshold = MojomPriorityThreshold::kUnknown;
break;
case proto::PriorityThreshold::PRIORITY_THRESHOLD_MEDIUM:
hints->priority_threshold = MojomPriorityThreshold::kMedium;
break;
case proto::PriorityThreshold::PRIORITY_THRESHOLD_HIGH:
hints->priority_threshold = MojomPriorityThreshold::kHigh;
break;
}
DCHECK(
!optimization_guide_hints_->delay_competing_low_priority_requests_hints);
optimization_guide_hints_->delay_competing_low_priority_requests_hints =
std::move(hints);
}
} // namespace optimization_guide