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 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
|
// Copyright 2020 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_PERFORMANCE_MANAGER_POLICIES_BACKGROUND_TAB_LOADING_POLICY_H_
#define CHROME_BROWSER_PERFORMANCE_MANAGER_POLICIES_BACKGROUND_TAB_LOADING_POLICY_H_
#include <map>
#include <optional>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/raw_ptr.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/node_data_describer.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/graph/system_node.h"
#include "url/gurl.h"
namespace performance_manager {
namespace mechanism {
class PageLoader;
} // namespace mechanism
FORWARD_DECLARE_TEST(BackgroundTabLoadingBrowserTest,
RestoredTabsAreLoadedGradually);
class BackgroundTabLoadingBrowserTest;
class SiteDataReader;
namespace policies {
// This policy manages loading of background tabs created by session restore. It
// is responsible for assigning priorities and controlling the load of
// background tab loading at all times.
class BackgroundTabLoadingPolicy : public GraphOwned,
public NodeDataDescriberDefaultImpl,
public PageNodeObserver,
public SystemNodeObserver {
public:
// `all_restored_tabs_loaded_callback` is invoked when all tabs passed to
// ScheduleLoadForRestoredTabs() are loaded.
explicit BackgroundTabLoadingPolicy(
base::RepeatingClosure all_restored_tabs_loaded_callback);
~BackgroundTabLoadingPolicy() override;
BackgroundTabLoadingPolicy(const BackgroundTabLoadingPolicy& other) = delete;
BackgroundTabLoadingPolicy& operator=(const BackgroundTabLoadingPolicy&) =
delete;
// GraphOwned implementation:
void OnPassedToGraph(Graph* graph) override;
void OnTakenFromGraph(Graph* graph) override;
// PageNodeObserver implementation:
void OnLoadingStateChanged(const PageNode* page_node,
PageNode::LoadingState previous_state) override;
void OnBeforePageNodeRemoved(const PageNode* page_node) override;
// Holds data about a PageNode being added to this policy.
struct PageNodeData {
explicit PageNodeData(
base::WeakPtr<PageNode> page_node,
GURL main_frame_url = GURL(),
blink::mojom::PermissionStatus notification_permission_status =
blink::mojom::PermissionStatus::ASK);
PageNodeData(PageNodeData&& other);
PageNodeData& operator=(PageNodeData&& other);
PageNodeData(const PageNodeData& other);
PageNodeData& operator=(const PageNodeData& other);
~PageNodeData();
base::WeakPtr<PageNode> page_node;
GURL main_frame_url;
blink::mojom::PermissionStatus notification_permission_status;
std::optional<size_t> site_engagement;
};
// Schedules the PageNodes in |page_node_and_permission_vector| to be loaded
// when appropriate.
void ScheduleLoadForRestoredTabs(
std::vector<PageNodeData> page_node_and_permission_vector);
void SetMockLoaderForTesting(std::unique_ptr<mechanism::PageLoader> loader);
void SetMaxSimultaneousLoadsForTesting(size_t loading_slots);
void SetFreeMemoryForTesting(size_t free_memory_mb);
void ResetPolicyForTesting();
// Returns the instance of BackgroundTabLoadingPolicy within the graph.
static BackgroundTabLoadingPolicy* GetInstance();
private:
friend class ::performance_manager::BackgroundTabLoadingBrowserTest;
friend class BackgroundTabLoadingPolicyTest;
// Holds data about a PageNode waiting to be loaded by this policy.
struct PageNodeToLoadData {
PageNodeToLoadData(const PageNode* page_node,
std::optional<size_t> site_engagement);
~PageNodeToLoadData();
// Move-only.
PageNodeToLoadData(const PageNodeToLoadData&) = delete;
PageNodeToLoadData& operator=(const PageNodeToLoadData&) = delete;
PageNodeToLoadData(PageNodeToLoadData&&) = default;
PageNodeToLoadData& operator=(PageNodeToLoadData&&) = default;
// Returns true if the data about this PageNode indicates it uses background
// communication.
bool UsesBackgroundCommunication() const;
// Keeps a pointer to the corresponding PageNode.
raw_ptr<const PageNode> page_node;
// A higher value here means the tab has higher priority for restoring.
std::optional<float> score;
// Whether the tab updates its title or favicon when backgrounded.
// Initialized to nullopt and set asynchronously with the proper value from
// the sites database.
std::optional<bool> updates_title_or_favicon_in_bg;
std::optional<size_t> site_engagement;
};
// Comparator used to sort PageNodeToLoadData.
struct ScoredTabComparator;
// NodeDataDescriber implementation:
base::Value::Dict DescribePageNodeData(const PageNode* node) const override;
base::Value::Dict DescribeSystemNodeData(
const SystemNode* node) const override;
// SystemNodeObserver:
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel new_level) override;
// Returns the SiteDataReader instance for |page_node|, if any. Virtual for
// testing.
virtual SiteDataReader* GetSiteDataReader(const PageNode* page_node) const;
// Determines whether or not the given PageNode should be loaded. If this
// returns false, then the policy no longer attempts to load |page_node| and
// removes it from the policy's internal state. This is called immediately
// prior to trying to load the PageNode.
bool ShouldLoad(const PageNodeToLoadData& page_node_data);
// This will initialize |page_node_to_load_data->used_in_bg| to the proper
// value, score the tab and call DispatchNotifyAllTabsScoredIfNeeded().
void OnUsedInBackgroundAvailable(base::WeakPtr<PageNode> page_node);
// Stops loading tabs by clearing |page_nodes_to_load_|.
void StopLoadingTabs();
// Calculates a |score| for the given tab.
void ScoreTab(PageNodeToLoadData* page_node_to_load_data);
// Schedule the task that will initialize |PageNodeToLoadData::used_in_bg|
// from the local site characteristics database.
void SetUsedInBackgroundAsync(PageNodeToLoadData* page_node_to_load_data);
// Invoke "NotifyAllTabsScored" if all tabs are scored.
void DispatchNotifyAllTabsScoredIfNeeded();
// Notifying that all tabs have final scores and starts loading.
void NotifyAllTabsScored();
// Move the PageNode from |page_nodes_to_load_| to
// |page_nodes_load_initiated_| and make the call to load the PageNode.
void InitiateLoad(const PageNode* page_node);
// Removes the PageNode from all the sets of PageNodes that the policy is
// tracking.
void RemovePageNode(const PageNode* page_node);
// Initiates the load of enough tabs to fill all loading slots. No-ops if all
// loading slots are occupied.
void MaybeLoadSomeTabs();
// Determines the number of tab loads that can be started at the moment to
// avoid exceeding the number of loading slots.
size_t GetMaxNewTabLoads() const;
// Loads the next tab. This should only be called if there is a next tab to
// load. This will always start loading a next tab even if the number of
// simultaneously loading tabs is exceeded.
void LoadNextTab();
// Compute the amount of free memory on the system.
size_t GetFreePhysicalMemoryMib() const;
// If `page_node` is in the set of page nodes to load, removes it and returns
// true.
bool ErasePageNodeToLoadData(const PageNode* page_node);
// Returns the `PageNodeToLoadData` for `page_node` if it exists, nullptr
// otherwise.
PageNodeToLoadData* FindPageNodeToLoadData(const PageNode* page_node);
// Returns true if there are restored tabs that must be loaded by this policy
// and aren't fully loaded yet.
bool HasRestoredTabsToLoad() const;
// Updates `has_restored_tabs_to_load_` to match `HasRestoredTabsToLoad()` and
// invokes `all_restored_tabs_loaded_callback_` if needed.
void UpdateHasRestoredTabsToLoad();
// The callback to invoke when all restored tabs are loaded.
const base::RepeatingClosure all_restored_tabs_loaded_callback_;
// Whether there are restored tabs that that must be loaded by this policy and
// aren't fully loaded yet.
//
// Set to true when ScheduleLoadForRestoredTabs() is invoked. Set to false
// when HasRestoredTabsToLoad() becomes false.
bool has_restored_tabs_to_load_ = false;
// The mechanism used to load the pages.
std::unique_ptr<performance_manager::mechanism::PageLoader> page_loader_;
// The set of PageNodes that have been restored for which we need to schedule
// loads.
std::vector<std::unique_ptr<PageNodeToLoadData>> page_nodes_to_load_;
// The set of PageNodes that BackgroundTabLoadingPolicy has initiated loading,
// and for which we are waiting for the loading to actually start. This signal
// will be received from |OnIsLoadingChanged|.
std::vector<raw_ptr<const PageNode, VectorExperimental>>
page_nodes_load_initiated_;
// PageNodes that are currently loading, mapped to a boolean indicating
// whether this policy was responsible for scheduling the load.
std::map<const PageNode*, bool> page_nodes_loading_;
// The number of simultaneous tab loads that are permitted by policy. This
// is computed based on the number of cores on the machine.
size_t max_simultaneous_tab_loads_;
// The number of tab loads that have started. Every call to InitiateLoad
// increments this value.
size_t tab_loads_started_ = 0;
// The number of tabs for which an accurate initial score has been assigned.
// This is incremented only after all tab data is available, which
// may happen asynchronously.
size_t tabs_scored_ = 0;
// Used to overwrite the amount of free memory available on the system.
size_t free_memory_mb_for_testing_ = 0;
// The minimum total number of restored tabs to load.
static constexpr uint32_t kMinTabsToLoad = 4;
// The maximum total number of restored tabs to load.
static constexpr uint32_t kMaxTabsToLoad = 20;
// The minimum amount of memory to keep free.
static constexpr uint32_t kDesiredAmountOfFreeMemoryMb = 150;
// The maximum time since last use of a tab in order for it to be loaded.
static constexpr base::TimeDelta kMaxTimeSinceLastUseToLoad = base::Days(30);
// Lower bound for the maximum number of tabs to load simultaneously.
static constexpr uint32_t kMinSimultaneousTabLoads = 1;
// Upper bound for the maximum number of tabs to load simultaneously.
static constexpr uint32_t kMaxSimultaneousTabLoads = 4;
// The number of CPU cores required per permitted simultaneous tab
// load.
static constexpr uint32_t kCoresPerSimultaneousTabLoad = 2;
// It's possible for this policy object to be destroyed while it has posted
// tasks. The tasks are bound to a weak pointer so that they are not executed
// after the policy object is destroyed.
base::WeakPtrFactory<BackgroundTabLoadingPolicy> weak_factory_{this};
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicyTest,
ShouldLoad_MaxTabsToRestore);
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicyTest,
ShouldLoad_MinTabsToRestore);
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicyTest,
ShouldLoad_FreeMemory);
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicyTest, ShouldLoad_OldTab);
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicyTest,
ShouldLoad_SiteEngagement);
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicySiteEngagementTest,
ShouldLoad_NoBackgroundCommunication);
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicySiteEngagementTest,
ShouldLoad_NotificationPermission);
FRIEND_TEST_ALL_PREFIXES(BackgroundTabLoadingPolicySiteEngagementTest,
ShouldLoad_UpdatesTitleOrFaviconInBackground);
FRIEND_TEST_ALL_PREFIXES(
BackgroundTabLoadingPolicyScheduleLoadTest,
ScheduleLoadForRestoredTabs_WithoutNotificationPermission);
FRIEND_TEST_ALL_PREFIXES(
BackgroundTabLoadingPolicyScheduleLoadTest,
ScheduleLoadForRestoredTabs_WithNotificationPermission);
FRIEND_TEST_ALL_PREFIXES(
::performance_manager::BackgroundTabLoadingBrowserTest,
RestoredTabsAreLoadedGradually);
};
} // namespace policies
} // namespace performance_manager
#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_POLICIES_BACKGROUND_TAB_LOADING_POLICY_H_
|