blob: e79e405d15882440b4cf6e110eaa8ce17a762e10 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRELOADING_PRERENDER_PRERENDER_MANAGER_H_
#define CHROME_BROWSER_PRELOADING_PRERENDER_PRERENDER_MANAGER_H_
#include <optional>
#include <string>
#include "chrome/browser/preloading/preloading_features.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "content/public/browser/preloading.h"
#include "content/public/browser/prerender_handle.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "url/gurl.h"
namespace content {
class NavigationHandle;
}
namespace internal {
extern const char kHistogramPrerenderPredictionStatusDefaultSearchEngine[];
extern const char kHistogramPrerenderPredictionStatusDirectUrlInput[];
} // namespace internal
// If you change this, please follow the process in
// go/preloading-dashboard-updates to update the mapping reflected in dashboard,
// or if you are not a Googler, please file an FYI bug on https://crbug.new with
// component Internals>Preload.
//
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(PrerenderPredictionStatus)
enum class PrerenderPredictionStatus {
// The prerender was not started at all for this omnibox interaction.
kNotStarted = 0,
// The prerender was cancelled since the prediction is updated.
kCancelled = 1,
// The prerender was unused.
kUnused = 2,
// The predicted URL was used.
kHitFinished = 3,
kMaxValue = kHitFinished,
};
// LINT.ThenChange()
// Manages running prerenders in the //chrome.
// Chrome manages running prerenders separately, as it prioritizes the latest
// prerender requests, while the //content prioritizes the earliest requests.
class PrerenderManager : public content::WebContentsObserver,
public content::WebContentsUserData<PrerenderManager> {
public:
PrerenderManager(const PrerenderManager&) = delete;
PrerenderManager& operator=(const PrerenderManager&) = delete;
~PrerenderManager() override;
// content::WebContentsObserver
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
// Maybe start prerendering a prewarm page if we haven't prewarm it yet for
// the underlying WebContents. Returns true if a new prerender is started.
// TODO(https://crbug.com/423465927): Decide a better timing to close.
bool MaybeStartPrewarmSearchResult();
// Deletes the existing prewarm page to start another one for testing.
void StopPrewarmSearchResultForTesting();
// Sets the prewarm page URL for testing as it's difficult to set the testing
// server's URL as a Finch parameter in the tests.
void SetPrewarmUrlForTesting(const GURL& url);
// Calling this method will lead to the cancellation of the previous prerender
// if the given `canonical_search_url` differs from the ongoing one's.
void StartPrerenderSearchResult(
const GURL& canonical_search_url,
const GURL& prerendering_url,
base::WeakPtr<content::PreloadingAttempt> attempt);
// Cancels the prerender that is prerendering the given
// `canonical_search_url`.
// TODO(crbug.com/40214220): Use the creator's address to identify the
// owner that can cancels the corresponding prerendering?
void StopPrerenderSearchResult(const GURL& canonical_search_url);
// The entry of direct url input prerender.
// Calling this method will return WeakPtr of the started prerender, and lead
// to the cancellation of the previous prerender if the given url is different
// from the on-going one. If the url given is already on-going, this function
// will return the weak pointer to the on-going prerender handle.
// PreloadingAttempt represents the attempt corresponding to this prerender to
// log the necessary metrics.
base::WeakPtr<content::PrerenderHandle> StartPrerenderDirectUrlInput(
const GURL& prerendering_url,
content::PreloadingAttempt& preloading_attempt);
// Returns true if the current tab prerendered a search result for omnibox
// inputs.
bool HasSearchResultPagePrerendered() const;
base::WeakPtr<PrerenderManager> GetWeakPtr();
// Returns the prerendered search terms if search_prerender_task_ exists.
// Returns empty string otherwise.
const GURL GetPrerenderCanonicalSearchURLForTesting() const;
private:
class SearchPrerenderTask;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(PrewarmDecision)
enum class PrewarmDecision {
kReady = 0,
kAlreadyExists = 1,
kDisabled = 2,
kInHeadlessMode = 3,
kDebuggerAttached = 4,
kInvalidUrl = 5,
kNoTemplateUrlService = 6,
kNoDefaultSearchProvider = 7,
kNotSameOriginWithDSE = 8,
kInPictureInPicture = 9,
kInIsolatedWebApp = 10,
kMaxValue = kInIsolatedWebApp,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/navigation/enums.xml:PrerenderPrewarmDecision)
explicit PrerenderManager(content::WebContents* web_contents);
friend class content::WebContentsUserData<PrerenderManager>;
void ResetPrerenderHandlesOnPrimaryPageChanged(
content::NavigationHandle* navigation_handle);
// Decides if prewarm should be triggered. If not, returns the reason why.
// Otherwise, returns kReady and sets `prewarm_url`.
PrewarmDecision ShouldPrewarm(GURL& prewarm_url);
std::unique_ptr<content::PrerenderHandle> search_prewarm_handle_;
std::optional<GURL> prewarm_url_for_testing_;
// Stores the prerender which serves for search results. It is responsible for
// tracking a started search prerender, and informing `SearchPrefetchService`
// of the prerender status.
std::unique_ptr<SearchPrerenderTask> search_prerender_task_;
std::unique_ptr<content::PrerenderHandle> direct_url_input_prerender_handle_;
base::WeakPtrFactory<PrerenderManager> weak_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
#endif // CHROME_BROWSER_PRELOADING_PRERENDER_PRERENDER_MANAGER_H_