File: discard_eligibility_policy.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (182 lines) | stat: -rw-r--r-- 6,839 bytes parent folder | download | duplicates (3)
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
// Copyright 2025 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_DISCARD_ELIGIBILITY_POLICY_H_
#define CHROME_BROWSER_PERFORMANCE_MANAGER_POLICIES_DISCARD_ELIGIBILITY_POLICY_H_

#include <map>

#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/performance_manager/policies/cannot_discard_reason.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom-shared.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"

namespace url_matcher {
class URLMatcher;
}  // namespace url_matcher

namespace performance_manager::policies {

#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
inline constexpr base::TimeDelta kNonVisiblePagesUrgentProtectionTime =
    base::TimeDelta();
#else
// Time during which non visible pages are protected from urgent discarding
// (not on ChromeOS).
inline constexpr base::TimeDelta kNonVisiblePagesUrgentProtectionTime =
    base::Minutes(10);
#endif

#if BUILDFLAG(IS_ANDROID)
// TODO(crbug.com/412839833): kTabAudioProtectionTime may be needed on Android
// as well.
inline constexpr base::TimeDelta kTabAudioProtectionTime = base::TimeDelta();
#else
// Time during which a tab cannot be discarded after having played audio.
inline constexpr base::TimeDelta kTabAudioProtectionTime = base::Minutes(1);
#endif

// Whether a page can be discarded.
enum class CanDiscardResult {
  // The page can be discarded. The user should experience minimal disruption
  // from discarding.
  kEligible,
  // The page can be discarded. The user will likely find discarding disruptive.
  kProtected,
  // The page cannot be discarded.
  kDisallowed,
};

// Caches page node properties to facilitate sorting.
class PageNodeSortProxy {
 public:
  PageNodeSortProxy(base::WeakPtr<const PageNode> page_node,
                    CanDiscardResult can_discard_result,
                    bool is_visible,
                    bool is_focused,
                    base::TimeTicks last_visibility_change_time);
  PageNodeSortProxy(PageNodeSortProxy&&);
  PageNodeSortProxy& operator=(PageNodeSortProxy&&);
  ~PageNodeSortProxy();

  base::WeakPtr<const PageNode> page_node() const { return page_node_; }
  bool is_disallowed() const {
    return can_discard_result_ == CanDiscardResult::kDisallowed;
  }
  bool is_protected() const {
    return can_discard_result_ == CanDiscardResult::kProtected;
  }
  bool is_visible() const { return is_visible_; }
  bool is_focused() const { return is_focused_; }
  base::TimeTicks last_visibility_change_time() const {
    return last_visibility_change_time_;
  }

  // Returns true if the rhs is more important.
  bool operator<(const PageNodeSortProxy& rhs) const {
    if (is_disallowed() != rhs.is_disallowed()) {
      return rhs.is_disallowed();
    }
    if (is_focused_ != rhs.is_focused_) {
      return rhs.is_focused_;
    }
    if (is_visible_ != rhs.is_visible_) {
      return rhs.is_visible_;
    }
    if (is_protected() != rhs.is_protected()) {
      return rhs.is_protected();
    }
    return last_visibility_change_time_ < rhs.last_visibility_change_time_;
  }

 private:
  base::WeakPtr<const PageNode> page_node_;
  CanDiscardResult can_discard_result_;
  bool is_visible_;
  bool is_focused_;
  base::TimeTicks last_visibility_change_time_;
};

// DiscardEligibilityPolicy decides which PageNode is eligigle for tab
// discarding.
class DiscardEligibilityPolicy
    : public GraphOwnedAndRegistered<DiscardEligibilityPolicy>,
      public NodeDataDescriberDefaultImpl,
      public PageNodeObserver {
 public:
  // Export discard reason in the public interface.
  using DiscardReason = ::mojom::LifecycleUnitDiscardReason;

  DiscardEligibilityPolicy();
  ~DiscardEligibilityPolicy() override;
  DiscardEligibilityPolicy(const DiscardEligibilityPolicy& other) = delete;
  DiscardEligibilityPolicy& operator=(const DiscardEligibilityPolicy&) = delete;

  // PageNodeObserver:
  void OnMainFrameDocumentChanged(const PageNode* page_node) override;

  base::WeakPtr<DiscardEligibilityPolicy> GetWeakPtr() {
    return weak_factory_.GetWeakPtr();
  }

  void SetNoDiscardPatternsForProfile(const std::string& browser_context_id,
                                      const std::vector<std::string>& patterns);
  void ClearNoDiscardPatternsForProfile(const std::string& browser_context_id);

  // Indicates if `page_node` can be urgently discarded, using a list of
  // criteria depending on `discard_reason`. If `minimum_time_in_background` is
  // non-zero, the page will not be discarded if it has not spent at least
  // `minimum_time_in_background` in the not-visible state.
  CanDiscardResult CanDiscard(
      const PageNode* page_node,
      DiscardReason discard_reason,
      base::TimeDelta minimum_time_in_background =
          kNonVisiblePagesUrgentProtectionTime,
      std::vector<CannotDiscardReason>* cannot_discard_reasons = nullptr) const;

  // This must be called from PageDiscardingHelper or from test only.
  static void AddDiscardAttemptMarker(PageNode* page_node);
  static void RemovesDiscardAttemptMarkerForTesting(PageNode* page_node);

  // Sets an additional callback that should be invoked whenever the
  // SetNoDiscardPatternsForProfile() or ClearNoDiscardPatternsForProfile()
  // methosd is called, with the method's `browser_context_id` argument.
  void SetOptOutPolicyChangedCallback(
      base::RepeatingCallback<void(std::string_view)> callback);

  bool IsPageOptedOutOfDiscarding(const std::string& browser_context_id,
                                  const GURL& url) const;

  void set_always_discard_for_testing(bool always_discard) {
    always_discard_for_testing_ = always_discard;
  }

 private:
  void OnPassedToGraph(Graph* graph) override;
  void OnTakenFromGraph(Graph* graph) override;

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

  std::map<std::string, std::unique_ptr<url_matcher::URLMatcher>>
      profiles_no_discard_patterns_ GUARDED_BY_CONTEXT(sequence_checker_);

  base::RepeatingCallback<void(std::string_view)>
      opt_out_policy_changed_callback_ GUARDED_BY_CONTEXT(sequence_checker_);

  bool always_discard_for_testing_ = false;

  SEQUENCE_CHECKER(sequence_checker_);

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

}  // namespace performance_manager::policies

#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_POLICIES_DISCARD_ELIGIBILITY_POLICY_H_