File: freezing_policy.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; 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,811; 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 (330 lines) | stat: -rw-r--r-- 14,614 bytes parent folder | download | duplicates (4)
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
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
// 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 COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_POLICY_H_
#define COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_POLICY_H_

#include <deque>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string_view>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/rand_util.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/performance_manager/freezing/freezer.h"
#include "components/performance_manager/public/decorators/page_live_state_decorator.h"
#include "components/performance_manager/public/freezing/cannot_freeze_reason.h"
#include "components/performance_manager/public/freezing/freezing.h"
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/graph_registered.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/resource_attribution/cpu_proportion_tracker.h"
#include "components/performance_manager/public/resource_attribution/queries.h"
#include "content/public/browser/browsing_instance_id.h"
#include "url/origin.h"

namespace performance_manager {

// Freezes sets of connected pages when no page in the set is opted-out and:
// - All pages have at least one freezing vote, or,
// - A group of same-origin and same-browsing-instance frames/workers associated
//   with the set of connected pages used a lot of CPU in the background and
//   Battery Saver is active.
//
// Pages are connected if they host frames from the same browsing instance. For
// example:
// - Page A hosts frames from browsing instance 1
// - Page B hosts frames from browsing instances 1 and 2
// - Page C hosts frames from browsing instance 2
// - Page D hosts frames from browsing instance 3
// The sets of connected pages are {A, B, C} and {D}.
//
// The `CannotFreezeReason` enum lists conditions that opt-out a page from
// freezing.
class FreezingPolicy : public PageNodeObserver,
                       public FrameNodeObserver,
                       public PageLiveStateObserver,
                       public resource_attribution::QueryResultObserver,
                       public GraphOwnedAndRegistered<FreezingPolicy>,
                       public NodeDataDescriberDefaultImpl {
 public:
  enum class FreezingType {
    // Freezing via the voting system exposed to embedders.
    kVoting,
    // Freezing of CPU-intensive background tabs when Battery Saver is active.
    kBatterySaver,
    // Freezing of tabs which aren't in the set of most recently used, to
    // scale to infinite tabs.
    kInfiniteTabs,
  };
  using FreezingTypeSet = base::
      EnumSet<FreezingType, FreezingType::kVoting, FreezingType::kInfiniteTabs>;

  explicit FreezingPolicy(
      std::unique_ptr<freezing::Discarder> discarder,
      std::unique_ptr<freezing::OptOutChecker> opt_out_checker = nullptr);
  ~FreezingPolicy() override;

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

  void SetFreezerForTesting(std::unique_ptr<Freezer> freezer) {
    freezer_ = std::move(freezer);
  }

  // Invoked freezing on battery saver is enabled or disabled.
  void ToggleFreezingOnBatterySaverMode(bool is_enabled);

  // Add or remove a freezing vote for `page_node`. A browsing instance is
  // frozen if all its pages have a freezing vote and none have a
  // `CannotFreezeReason`.
  void AddFreezeVote(PageNode* page_node);
  void RemoveFreezeVote(PageNode* page_node);

  // Returns details about whether a page can be frozen.
  freezing::CanFreezeDetails GetCanFreezeDetails(const PageNode* page_node);

  // Returns a set of `CannotFreezeReason`s applicable to `freezing_type`.
  static freezing::CannotFreezeReasonSet CannotFreezeReasonsForType(
      FreezingPolicy::FreezingType type);

 private:
  FRIEND_TEST_ALL_PREFIXES(FreezingPolicyBatterySaverTest,
                           RecordFreezingEligibilityUKMForPageStatic);

  class CanFreezePerTypeTracker;

  // Freezing related state for a page.
  struct PageFreezingState;

  // Freezing related state for a browsing instance.
  struct BrowsingInstanceState {
    BrowsingInstanceState();
    ~BrowsingInstanceState();

    // Returns true if all pages in this browsing instance are frozen.
    bool AllPagesFrozen() const;

    // Pages that have frames in this browsing instance (typically only 1 page,
    // but may contain an unbounded amount of pages connected via opener
    // relationship).
    base::flat_set<const PageNode*> pages;
    // Highest CPU measurement for a group of same-origin frames/workers
    // associated with this browsing instance, over the last measurement period.
    // (1.0 = 100% of 1 core)
    std::optional<double> highest_cpu_current_interval;
    // Highest CPU measurement for a group of same-origin frames/workers
    // associated within this browsing instance, over any past measurement
    // period during which no `CannotFreezeReason` associated with
    // `FreezingType::kBatterySaver` was applicable. (1.0 = 100% of 1 core)
    double highest_cpu_without_battery_saver_cannot_freeze = 0.0;
    // `CannotFreezeReason`s applicable to this browsing instance at any point
    // since the last CPU measurement.
    freezing::CannotFreezeReasonSet
        cannot_freeze_reasons_since_last_cpu_measurement;
    // First per-origin Private Memory Footprint measurement taken after this
    // browsing instance became frozen. Empty if not all pages in this browsing
    // instance are frozen.
    base::flat_map<url::Origin, uint64_t> per_origin_pmf_after_freezing_kb;
  };

  // Returns pages connected to `page`, including `page` itself. See
  // meta-comment above this class for a definition of "connected".
  base::flat_set<raw_ptr<const PageNode>> GetConnectedPages(
      const PageNode* page);

  // Returns browsing instance id(s) for `page`.
  base::flat_set<content::BrowsingInstanceId> GetBrowsingInstances(
      const PageNode* page) const;

  // Returns the `PageFreezingState` for `page`, creating it if necessary.
  PageFreezingState& GetFreezingState(const PageNode* page_node) const;

  // Update frozen state for all pages connected to `page`. Connected pages
  // (including `page_node`) are added to `connected_pages_out` if not nullptr.
  void UpdateFrozenState(
      const PageNode* page_node,
      base::TimeTicks now = base::TimeTicks::Now(),
      base::flat_set<raw_ptr<const PageNode>>* connected_pages_out = nullptr);

  // Helper to add or remove a `CannotFreezeReason` for `page_node`.
  void OnCannotFreezeReasonChange(const PageNode* page_node,
                                  bool add,
                                  freezing::CannotFreezeReason reason);

  // Returns the union of `CannotFreezeReason`s applicable to pages associated
  // with `browsing_instance_state`.
  freezing::CannotFreezeReasonSet GetCannotFreezeReasons(
      const BrowsingInstanceState& browsing_instance_state);

  // GraphOwned implementation:
  void OnPassedToGraph(Graph* graph) override;
  void OnTakenFromGraph(Graph* graph) override;

  // PageNodeObserver implementation:
  void OnPageNodeAdded(const PageNode* page_node) override;
  void OnBeforePageNodeRemoved(const PageNode* page_node) override;
  void OnTypeChanged(const PageNode* page_node,
                     PageType previous_type) override;
  void OnIsVisibleChanged(const PageNode* page_node) override;
  void OnIsAudibleChanged(const PageNode* page_node) override;
  void OnPageLifecycleStateChanged(const PageNode* page_node) override;
  void OnPageHasFreezingOriginTrialOptOutChanged(
      const PageNode* page_node) override;
  void OnPageIsHoldingWebLockChanged(const PageNode* page_node) override;
  void OnPageIsHoldingBlockingIndexedDBLockChanged(
      const PageNode* page_node) override;
  void OnPageUsesWebRTCChanged(const PageNode* page_node) override;
  void OnPageNotificationPermissionStatusChange(
      const PageNode* page_node,
      std::optional<blink::mojom::PermissionStatus> previous_status) override;
  void OnMainFrameUrlChanged(const PageNode* page_node) override;
  void OnLoadingStateChanged(const PageNode* page_node,
                             PageNode::LoadingState previous_state) override;

  // FrameNodeObserver implementation:
  void OnFrameNodeAdded(const FrameNode* frame_node) override;
  void OnFrameNodeRemoved(
      const FrameNode* frame_node,
      const FrameNode* previous_parent_frame_node,
      const PageNode* previous_page_node,
      const ProcessNode* previous_process_node,
      const FrameNode* previous_parent_or_outer_document_or_embedder) override;
  void OnIsAudibleChanged(const FrameNode* frame_node) override;

  // PageLiveStateObserver:
  void OnIsConnectedToUSBDeviceChanged(const PageNode* page_node) override;
  void OnIsConnectedToBluetoothDeviceChanged(
      const PageNode* page_node) override;
  void OnIsConnectedToHidDeviceChanged(const PageNode* page_node) override;
  void OnIsConnectedToSerialPortChanged(const PageNode* page_node) override;
  void OnIsCapturingVideoChanged(const PageNode* page_node) override;
  void OnIsCapturingAudioChanged(const PageNode* page_node) override;
  void OnIsBeingMirroredChanged(const PageNode* page_node) override;
  void OnIsCapturingWindowChanged(const PageNode* page_node) override;
  void OnIsCapturingDisplayChanged(const PageNode* page_node) override;

  // NodeDataDescriber:
  base::Value::Dict DescribePageNodeData(const PageNode* node) const override;

  // resource_attribution::QueryResultObserver:
  void OnResourceUsageUpdated(
      const resource_attribution::QueryResultMap& results) override;

  // Discards browsing instances for which memory usage has significantly
  // increased since they were frozen upon receiving a memory measurement.
  void DiscardFrozenPagesWithGrowingMemoryOnMemoryMeasurement(
      const resource_attribution::QueryResultMap& results);

  // Updates the frozen state of all browsing instances upon receiving a CPU
  // measurement.
  void UpdateFrozenStateOnCPUMeasurement(
      const resource_attribution::QueryResultMap& results);

  // Invoked by the OptOutChecker when the opt-out policy for
  // `browser_context_id` changes.
  void OnOptOutPolicyChanged(std::string_view browser_context_id);

  // Removes the last page from the most recently used list if needed, to keep
  // its size below the limit.
  void MaybePopFromMostRecentlyUsedList();

  // Checks that the size of the most recently used list respects the limit.
  void CheckMostRecentlyUsedListSize();

  // Starts a timer to manage periodic unfreezing of a tab frozen for
  // `FreezingContext::kInfiniteTabs`. The timer is scheduled to invoke
  // OnPeriodicUnfreezeTimer() at the next time when the tab must be unfrozen or
  // re-frozen.
  void StartPeriodicUnfreezeTimer(const PageNode* page_node,
                                  base::TimeTicks now);

  // Method invoked when when it's time to unfreeze or re-freeze a tab frozen
  // for `FreezingContext::kInfiniteTabs`.
  void OnPeriodicUnfreezeTimer(const PageNode* page);

  // Records freezing eligibility UKM for all pages.
  void RecordFreezingEligibilityUKM();

  // Records freezing eligibility UKM for a page. Virtual for testing.
  virtual void RecordFreezingEligibilityUKMForPage(
      ukm::SourceId source_id,
      double highest_cpu_current_interval,
      double highest_cpu_without_battery_saver_cannot_freeze,
      freezing::CannotFreezeReasonSet battery_saver_cannot_freeze_reasons);

  // Records freezing eligibility UKM for a page. Static implementation.
  //
  // Note: The virtual method RecordFreezingEligibilityUKMForPage() and the
  // static method RecordFreezingEligibilityUKMForPageStatic() are separate to
  // facilitate testing the code that produces the inputs for the UKM event and
  // the code that records the UKM event based on these inputs separately.
  static void RecordFreezingEligibilityUKMForPageStatic(
      ukm::SourceId source_id,
      double highest_cpu_current_interval,
      double highest_cpu_without_battery_saver_cannot_freeze,
      freezing::CannotFreezeReasonSet battery_saver_cannot_freeze_reasons);

  // Returns a random periodic unfreeze phase. Can be overridden in test to
  // eliminate randomness.
  virtual base::TimeTicks GenerateRandomPeriodicUnfreezePhase() const;

  // Used to freeze pages.
  std::unique_ptr<Freezer> freezer_;

  // Used to discard pages.
  std::unique_ptr<freezing::Discarder> discarder_;

  // Used to check whether pages are opted out of freezing by the embedder.
  std::unique_ptr<freezing::OptOutChecker> opt_out_checker_;

  // State of each browsing instance.
  std::map<content::BrowsingInstanceId, BrowsingInstanceState>
      browsing_instance_states_;

  // Whether Battery Saver is currently active.
  bool is_battery_saver_active_ = false;

  // Measures cumulative CPU usage per group of frames/workers that belong to
  // the same [browsing instance, origin]. Engaged when the
  // "CPUMeasurementInFreezingPolicy" feature is enabled.
  std::optional<resource_attribution::ScopedResourceUsageQuery>
      resource_usage_query_;

  // Manages observation of `resource_usage_query_` by `this`.
  resource_attribution::ScopedQueryObservation
      resource_usage_query_observation_{this};

  // Calculates the proportion of CPU used by a group of frames/workers that
  // belong to the same [browsing instance, origin] over an interval, based on
  // cumulative measurements from `resource_usage_query_`.
  resource_attribution::CPUProportionTracker cpu_proportion_tracker_;

  // Used to subsample the emission of UKM events.
  base::MetricsSubSampler metrics_subsampler_;

  // List of most recently used hidden tabs. A tab becomes the most recently
  // used when it transitions from visible to hidden, or when it's created in a
  // hidden state.
  std::deque<raw_ptr<const PageNode>> most_recently_used_;

  // Number of visible tabs.
  int num_visible_tabs_ = 0;

  base::WeakPtrFactory<FreezingPolicy> weak_factory_{this};
};

}  // namespace performance_manager

#endif  // COMPONENTS_PERFORMANCE_MANAGER_FREEZING_FREEZING_POLICY_H_