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
|
// Copyright 2023 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_TABS_ORGANIZATION_TRIGGER_POLICIES_H_
#define CHROME_BROWSER_UI_TABS_ORGANIZATION_TRIGGER_POLICIES_H_
#include <memory>
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
#include "chrome/browser/ui/tabs/organization/trigger.h"
namespace content {
class BrowserContext;
}
class PrefService;
// We want to parameterize trigger policies with things like target triggering
// frequencies. That begs the question - how should we define those frequencies?
// Once per week? Once every 8 hours of active chrome usage? Once per 200 tabs
// opened?
// A simple way to model this is with clocks that measure time differently. Some
// clock options, in increasing complexity order:
// 1. Wall time. Simple and predictable, but could spam users who don't often
// use Chrome and under-serve users who use Chrome frequently.
// 2. Chrome foreground time, implemented below. Still fairly simple, and maps
// better to actual usage, but fails for cases like streaming a movie or leaving
// a computer on overnight.
// 3. Number of browser actions of some kind, e.g. page loads. Weirder to think
// about, some risk of degenerate behavior for unusual usage patterns, but can
// map very directly to e.g. tabstrip usage.
// 4. The above, but deduplicate events performed in quick succession. This
// effectively amounts to defining our own notion of 'active tabstrip time'.
// Fixes the issues with 3 but might just be overkill.
// A clock that runs only while Chrome is in the foreground. See also
// chrome/browser/resource_coordinator/usage_clock.h which implements the same
// concept in a resource_coordinator specific way.
class UsageTickClock final : public base::TickClock,
metrics::DesktopSessionDurationTracker::Observer {
public:
explicit UsageTickClock(const base::TickClock* base_clock);
UsageTickClock(const UsageTickClock&) = delete;
UsageTickClock& operator=(const UsageTickClock&) = delete;
~UsageTickClock() override;
base::TimeTicks NowTicks() const override;
private:
void OnSessionStarted(base::TimeTicks session_start) override;
void OnSessionEnded(base::TimeDelta session_length,
base::TimeTicks session_end) override;
const raw_ptr<const base::TickClock> base_clock_;
const base::TimeTicks start_time_;
base::TimeDelta usage_time_in_completed_sessions_ = base::TimeDelta();
std::optional<base::TimeTicks> current_usage_session_start_time_ =
std::nullopt;
};
class BackoffLevelProvider {
public:
virtual ~BackoffLevelProvider() = default;
virtual unsigned int Get() const = 0;
virtual void Increment() = 0;
virtual void Decrement() = 0;
};
class ProfilePrefBackoffLevelProvider final : public BackoffLevelProvider {
public:
explicit ProfilePrefBackoffLevelProvider(content::BrowserContext* context);
~ProfilePrefBackoffLevelProvider() override;
// BackoffLevelProvider:
unsigned int Get() const override;
void Increment() override;
void Decrement() override;
private:
raw_ptr<PrefService> prefs_;
};
// A policy which triggers up to once per period, based on the classic solution
// to the secretary problem. Has an observation phase and a trigger phase.
// During the observation phase, it keeps track of the best score seen so far.
// During the trigger phase, it triggers the first time the best score from the
// observation phase is beaten.
//
// For any given period, it has a 1/e chance to not trigger at all, but the rest
// of the time it will likely trigger on a very good moment, relative to the
// other moments in this period.
class TargetFrequencyTriggerPolicy final : public TriggerPolicy {
public:
TargetFrequencyTriggerPolicy(std::unique_ptr<base::TickClock> clock,
base::TimeDelta base_period,
float backoff_base,
BackoffLevelProvider* backoff_level_provider);
~TargetFrequencyTriggerPolicy() override;
bool ShouldTrigger(float score) override;
void OnTriggerSucceeded();
void OnTriggerFailed();
private:
const std::unique_ptr<base::TickClock> clock_;
const base::TimeDelta base_period_;
const float backoff_base_;
const raw_ptr<BackoffLevelProvider> backoff_level_provider_;
base::TimeTicks cycle_start_time_;
std::optional<float> best_score = std::nullopt;
bool has_triggered_ = false;
};
// Never trigger. Useful for disabling the trigger under certain conditions.
class NeverTriggerPolicy final : public TriggerPolicy {
public:
bool ShouldTrigger(float score) override;
};
// Trigger every time. Very spammy, but suitable for testing or demoing.
class DemoTriggerPolicy final : public TriggerPolicy {
public:
bool ShouldTrigger(float score) override;
};
#endif // CHROME_BROWSER_UI_TABS_ORGANIZATION_TRIGGER_POLICIES_H_
|