File: webui_contents_preload_manager.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (220 lines) | stat: -rw-r--r-- 8,773 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// Copyright 2024 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_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_PRELOAD_MANAGER_H_
#define CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_PRELOAD_MANAGER_H_

#include <optional>

#include "base/no_destructor.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chrome/browser/ui/webui/top_chrome/per_profile_webui_tracker.h"
#include "chrome/browser/ui/webui/top_chrome/preload_candidate_selector.h"
#include "chrome/browser/ui/webui/top_chrome/webui_contents_preload_state.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"

class Browser;
class PerProfileWebUITracker;

// WebUIContentsPreloadManager is a singleton class that preloads top Chrome
// WebUIs. At anytime, at most one WebContents is preloaded across all profiles.
// If under heavy memory pressure, no preloaded contents will be created.
//
// See comments in TopChromeWebUIConfig for making a WebUI preloadable.
class WebUIContentsPreloadManager : public ProfileObserver,
                                    public PerProfileWebUITracker::Observer {
 public:
  enum class PreloadMode {
    // Preloads on calling `WarmupForBrowser()` and after every WebUI
    // creation.
    // TODO(326505383): preloading on browser startup causes test failures
    // primarily because they expect a certain number of WebContents are
    // created.
    kPreloadOnWarmup = 0,
    // Preloads only after every WebUI creation.
    // After the preloaded contents is taken, perloads a new contents.
    kPreloadOnMakeContents = 1,
  };

  struct RequestResult {
    RequestResult();
    RequestResult(RequestResult&&);
    RequestResult& operator=(RequestResult&&);
    RequestResult(const RequestResult&) = delete;
    RequestResult& operator=(const RequestResult&) = delete;
    ~RequestResult();

    std::unique_ptr<content::WebContents> web_contents;
    // True if `web_contents` is ready to be shown on screen. This boolean only
    // reflects the state when this struct is constructed. The `web_contents`
    // will cease to be ready to show, for example, if it reloads.
    bool is_ready_to_show;
  };

  ~WebUIContentsPreloadManager() override;

  WebUIContentsPreloadManager(const WebUIContentsPreloadManager&) = delete;
  WebUIContentsPreloadManager& operator=(const WebUIContentsPreloadManager&) =
      delete;

  static WebUIContentsPreloadManager* GetInstance();

  // Warms up the preload manager. Depending on PreloadMode this may or may not
  // make a preloaded contents.
  void WarmupForBrowser(Browser* browser);

  // Make a WebContents that shows `webui_url` under `browser_context`. If a
  // preloaded WebContents exists for the same `browser_context`, it will be
  // reused.
  // This method handles navigation to `webui_url` internally.
  // A new preloaded contents will be created, unless the system is under heavy
  // memory pressure.
  RequestResult Request(const GURL& webui_url,
                        content::BrowserContext* browser_context);

  // Returns the timeticks when the specific `web_contents` was requested.
  std::optional<base::TimeTicks> GetRequestTime(
      content::WebContents* web_contents);

  // Returns true if the given `web_contents` was preloaded.
  bool WasPreloaded(content::WebContents* web_contents) const;

  content::WebContents* preloaded_web_contents() {
    return preloaded_web_contents_.get();
  }

  // Disable navigations for tests that don't have //content properly
  // initialized.
  void DisableNavigationForTesting();

 private:
  WebUIContentsPreloadManager();
  friend class base::NoDestructor<WebUIContentsPreloadManager>;
  friend class WebUIContentsPreloadManagerTestAPI;
  class WebUIControllerEmbedderStub;
  class PendingPreload;

  // Used in telemetry to record the reason of preloading.
  enum class PreloadReason {
    // Preloading triggered by calling `WarmupForBrowser()`.
    kBrowserWarmup = 0,
    // Preloading triggered by destroy of WebUIs tracked by
    // `PerProfileWebUITracker`.
    kWebUIDestroyed = 1,
    // Preloading triggered by request of WebUIs, i.e. `Request()` is called.
    kWebUIRequested = 2,
    kMaxValue = kWebUIRequested,
  };

  std::vector<GURL> GetAllPreloadableWebUIURLs();

  // Returns the currently preloaded WebUI URL. Returns nullopt if no content is
  // preloaded.
  void SetPreloadCandidateSelector(
      std::unique_ptr<webui::PreloadCandidateSelector>
          preload_candidate_selector);

  // Returns the next WebUI URL to preload. This can return nullopt indicating
  // that no new WebUI will be preloaded.
  std::optional<GURL> GetNextWebUIURLToPreload(
      content::BrowserContext* browser_context) const;

  // Preload a WebContents for `browser_context`.
  // There is at most one preloaded contents at any time.
  // If the preloaded contents has a different browser context, replace it
  // with a new contents under the given `browser_context`.
  // If under heavy memory pressure, no preloaded contents will be created.
  void MaybePreloadForBrowserContext(
      content::BrowserContext* browser_context,
      PreloadReason preload_reason);

  // Schedule a preload. This calls MaybePreloadForBrowserContext() at a later
  // time.
  //
  // The preload will happen when `busy_web_contents_to_watch` emits the
  // first non-empty paint or when the deadline has passed.
  //
  // When called with a nullptr `busy_web_contents_to_watch`, only watch for
  // deadline to pass.
  //
  // When called while a preload is pending, cancel the pending preload and
  // schedule a new one.
  void MaybePreloadForBrowserContextLater(
      content::BrowserContext* browser_context,
      content::WebContents* busy_web_contents_to_watch,
      PreloadReason preload_reason,
      base::TimeDelta deadline = base::Seconds(3));

  // Sets the current preloaded WebContents and performs necessary bookkepping.
  // The bookkeeping includes monitoring for the shutdown of the browser context
  // and handling the "ready-to-show" event emitted by the WebContents.
  // Returns the previous preloaded WebContents.
  std::unique_ptr<content::WebContents> SetPreloadedContents(
      std::unique_ptr<content::WebContents> web_contents);

  std::unique_ptr<content::WebContents> CreateNewContents(
      content::BrowserContext* browser_context,
      GURL url);

  void LoadURLForContents(content::WebContents* web_contents, GURL url);

  // Returns true if a new preloaded contents should be created for
  // `browser_context`.
  bool ShouldPreloadForBrowserContext(
      content::BrowserContext* browser_context) const;

  bool IsDelayPreloadEnabled() const;

  // Cleans up preloaded contents on browser context shutdown.
  void OnBrowserContextShutdown(content::BrowserContext* browser_context);

  // ProfileObserver:
  void OnProfileWillBeDestroyed(Profile* profile) override;

  // PerProfileWebUITracker::Observer:
  void OnWebContentsDestroyed(content::WebContents* web_contents) override;
  void OnWebContentsPrimaryPageChanged(
      content::WebContents* web_contents) override;

  PreloadMode preload_mode_ = PreloadMode::kPreloadOnMakeContents;

  // Disable navigations for views unittests because they don't initialize
  // //content properly.
  bool is_navigation_disabled_for_test_ = false;

  // Used in tests to disable delay preload.
  // If not delayed, preloading waits for non-empty paint or a deadline.
  bool is_delay_preload_disabled_for_test_ = false;

  // Used to prevent the preload re-entrance due to destroying the old preload
  // contents.
  bool is_setting_preloaded_web_contents_ = false;

  std::unique_ptr<content::WebContents> preloaded_web_contents_;

  std::unique_ptr<PendingPreload> pending_preload_;

  // Tracks the WebUI presence state under a profile.
  std::unique_ptr<PerProfileWebUITracker> webui_tracker_;

  // Observes the tracker for WebContents destroy.
  base::ScopedObservation<PerProfileWebUITracker,
                          PerProfileWebUITracker::Observer>
      webui_tracker_observation_{this};

  // PreloadCandidateSelector selects the next WebUI to preload.
  std::unique_ptr<webui::PreloadCandidateSelector> preload_candidate_selector_;

  // A stub WebUI page embdeder that captures the ready-to-show signal.
  std::unique_ptr<WebUIControllerEmbedderStub> webui_controller_embedder_stub_;

  // Observation of destroy of preload content's profile.
  base::ScopedObservation<Profile, ProfileObserver> profile_observation_{this};
};

#endif  // CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_PRELOAD_MANAGER_H_