blob: 98344c633c0ce85cbc3a0ce5fb041e2b15bef687 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// 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/chrome_hints_manager.h"
#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/navigation_predictor/navigation_predictor_keyed_service.h"
#include "chrome/browser/navigation_predictor/navigation_predictor_keyed_service_factory.h"
#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
#include "chrome/browser/optimization_guide/optimization_guide_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "components/google/core/common/google_util.h"
#include "components/optimization_guide/core/hint_cache.h"
#include "components/optimization_guide/core/optimization_guide_features.h"
#include "components/optimization_guide/core/push_notification_manager.h"
#include "content/public/browser/browser_thread.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace {
// Returns true if we can make a request for hints for |prediction|.
bool IsAllowedToFetchForNavigationPrediction(
const absl::optional<NavigationPredictorKeyedService::Prediction>
prediction) {
DCHECK(prediction);
if (prediction->prediction_source() !=
NavigationPredictorKeyedService::PredictionSource::
kAnchorElementsParsedFromWebPage) {
// We only support predictions from page anchors.
return false;
}
const absl::optional<GURL> source_document_url =
prediction->source_document_url();
if (!source_document_url || source_document_url->is_empty())
return false;
// We only extract next predicted navigations from Google SRP URLs.
return google_util::IsGoogleSearchUrl(*source_document_url);
}
} // namespace
namespace optimization_guide {
ChromeHintsManager::ChromeHintsManager(
Profile* profile,
PrefService* pref_service,
base::WeakPtr<optimization_guide::OptimizationGuideStore> hint_store,
optimization_guide::TopHostProvider* top_host_provider,
optimization_guide::TabUrlProvider* tab_url_provider,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
std::unique_ptr<optimization_guide::PushNotificationManager>
push_notification_manager,
OptimizationGuideLogger* optimization_guide_logger)
: HintsManager(profile->IsOffTheRecord(),
g_browser_process->GetApplicationLocale(),
pref_service,
hint_store,
top_host_provider,
tab_url_provider,
url_loader_factory,
std::move(push_notification_manager),
optimization_guide_logger),
profile_(profile) {
if (!optimization_guide::features::IsSRPFetchingEnabled()) {
return;
}
NavigationPredictorKeyedService* navigation_predictor_service =
NavigationPredictorKeyedServiceFactory::GetForProfile(profile);
if (navigation_predictor_service)
navigation_predictor_service->AddObserver(this);
}
ChromeHintsManager::~ChromeHintsManager() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
void ChromeHintsManager::Shutdown() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
HintsManager::Shutdown();
NavigationPredictorKeyedService* navigation_predictor_service =
NavigationPredictorKeyedServiceFactory::GetForProfile(profile_);
if (navigation_predictor_service)
navigation_predictor_service->RemoveObserver(this);
}
void ChromeHintsManager::OnPredictionUpdated(
const absl::optional<NavigationPredictorKeyedService::Prediction>
prediction) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(prediction);
if (!IsAllowedToFetchForNavigationPrediction(prediction))
return;
// Per comments in NavigationPredictorKeyedService::Prediction, this pointer
// should be valid while OnPredictionUpdated is on the call stack.
content::WebContents* web_contents = prediction->web_contents();
CHECK(web_contents);
auto* observer =
OptimizationGuideWebContentsObserver::FromWebContents(web_contents);
if (!observer) {
return;
}
std::vector<GURL> urls_to_fetch;
for (const auto& url : prediction->sorted_predicted_urls()) {
if (!IsAllowedToFetchNavigationHints(url))
continue;
// Don't prefetch hints for SRP links that point back to Google.
if (google_util::IsGoogleSearchUrl(url))
continue;
if (hint_cache()->HasURLKeyedEntryForURL(url))
continue;
urls_to_fetch.push_back(url);
}
observer->AddURLsToBatchFetchBasedOnPrediction(std::move(urls_to_fetch),
web_contents);
}
} // namespace optimization_guide