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 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
|
// Copyright 2011 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_UPGRADE_DETECTOR_UPGRADE_DETECTOR_H_
#define CHROME_BROWSER_UPGRADE_DETECTOR_UPGRADE_DETECTOR_H_
#include <optional>
#include <string>
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "chrome/browser/upgrade_detector/upgrade_observer.h"
#include "components/prefs/pref_change_registrar.h"
class PrefRegistrySimple;
class UpgradeObserver;
namespace base {
class Clock;
class TickClock;
}
///////////////////////////////////////////////////////////////////////////////
// UpgradeDetector
//
// This class is a singleton class that monitors when an upgrade happens in the
// background. We basically ask Omaha what it thinks the latest version is and
// if our version is lower we send out a notification upon:
// a) Detecting an upgrade and...
// b) When we think the user should be notified about the upgrade.
// The latter happens much later, since we don't want to be too annoying.
// This class is not thread safe -- all access must take place on the UI thread.
//
class UpgradeDetector {
public:
// The Homeland Security Upgrade Advisory System.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum UpgradeNotificationAnnoyanceLevel {
UPGRADE_ANNOYANCE_NONE = 0, // What? Me worry?
UPGRADE_ANNOYANCE_LOW = 1, // Green.
UPGRADE_ANNOYANCE_ELEVATED = 2, // Yellow.
UPGRADE_ANNOYANCE_HIGH = 3, // Red.
// UPGRADE_ANNOYANCE_SEVERE = 4, // Removed in 2018-03 for lack of use.
UPGRADE_ANNOYANCE_CRITICAL = 5, // Red exclamation mark.
UPGRADE_ANNOYANCE_VERY_LOW = 6, // Green early warning for canary and dev.
UPGRADE_ANNOYANCE_GRACE = 7, // Red last warning before deadline.
UPGRADE_ANNOYANCE_MAX_VALUE = UPGRADE_ANNOYANCE_GRACE
};
struct RelaunchWindow {
constexpr RelaunchWindow(int start_hour,
int start_minute,
base::TimeDelta duration)
: hour(start_hour), minute(start_minute), duration(duration) {}
bool IsValid() const {
return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 &&
duration >= base::Minutes(1) && duration != base::TimeDelta::Max();
}
int hour;
int minute;
base::TimeDelta duration;
};
// Returns the singleton implementation instance.
static UpgradeDetector* GetInstance();
UpgradeDetector(const UpgradeDetector&) = delete;
UpgradeDetector& operator=(const UpgradeDetector&) = delete;
virtual ~UpgradeDetector();
// Returns the default delta from upgrade detection until high annoyance is
// reached.
static base::TimeDelta GetDefaultHighAnnoyanceThreshold();
// Returns the default delta from upgrade detection until elevated annoyance
// is reached.
static base::TimeDelta GetDefaultElevatedAnnoyanceThreshold();
static void RegisterPrefs(PrefRegistrySimple* registry);
virtual void Init();
virtual void Shutdown();
// Returns the time at which an available upgrade was detected.
base::Time upgrade_detected_time() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return upgrade_detected_time_;
}
// Whether the user should be notified about an upgrade.
bool notify_upgrade() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return notify_upgrade_;
}
// Whether the upgrade recommendation is due to Chrome being outdated.
bool is_outdated_install() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return upgrade_available_ == UPGRADE_NEEDED_OUTDATED_INSTALL;
}
// Whether the upgrade recommendation is due to Chrome being outdated AND
// auto-update is turned off.
bool is_outdated_install_no_au() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return upgrade_available_ == UPGRADE_NEEDED_OUTDATED_INSTALL_NO_AU;
}
// Returns true if the detector has found that a newer version of Chrome is
// installed and a relaunch would complete the update.
bool is_upgrade_available() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return upgrade_available_ == UPGRADE_AVAILABLE_REGULAR ||
upgrade_available_ == UPGRADE_AVAILABLE_CRITICAL;
}
// Notify this object that the user has acknowledged the critical update so we
// don't need to complain about it for now.
void acknowledge_critical_update() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
critical_update_acknowledged_ = true;
}
// Whether the user has acknowledged the critical update.
bool critical_update_acknowledged() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return critical_update_acknowledged_;
}
#if BUILDFLAG(IS_CHROMEOS)
bool is_factory_reset_required() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return is_factory_reset_required_;
}
bool is_rollback() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return is_rollback_;
}
#endif // BUILDFLAG(IS_CHROMEOS)
UpgradeNotificationAnnoyanceLevel upgrade_notification_stage() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return upgrade_notification_stage_;
}
// Returns the time at which `level` annoyance level will be (or was) reached,
// or a null time object if an upgrade has not yet been detected.
virtual base::Time GetAnnoyanceLevelDeadline(
UpgradeNotificationAnnoyanceLevel level) = 0;
// Overrides the "high" annoyance deadline, setting it to |deadline|. On
// Chrome OS, this also sets the "elevated" annoyance deadline to the time at
// which the available update was detected. This has no effect on desktop
// Chrome browsers.
virtual void OverrideHighAnnoyanceDeadline(base::Time deadine) {}
// Resets the overridden deadlines and recalculates them according to the
// thresholds from the Local State. This has no effect on desktop Chrome
// browsers.
virtual void ResetOverriddenDeadline() {}
// Overrides the relaunch notification style to required if |override|; else
// resets the override so that the policy settings take effect.
void OverrideRelaunchNotificationToRequired(bool overridden);
void AddObserver(UpgradeObserver* observer);
void RemoveObserver(UpgradeObserver* observer);
// Notifies that the current install is outdated. No details are expected.
void NotifyOutdatedInstall();
// Notifies that the current install is outdated and auto-update (AU) is
// disabled. No details are expected.
void NotifyOutdatedInstallNoAutoUpdate();
void set_upgrade_notification_stage_for_testing(
UpgradeNotificationAnnoyanceLevel stage) {
set_upgrade_notification_stage(stage);
}
void NotifyUpgradeForTesting();
protected:
enum UpgradeAvailable {
// If no update is available and current install is recent enough.
UPGRADE_AVAILABLE_NONE,
// If a regular update is available.
UPGRADE_AVAILABLE_REGULAR,
// If a critical update to Chrome has been installed, such as a zero-day
// fix.
UPGRADE_AVAILABLE_CRITICAL,
// If no update to Chrome has been installed for more than the recommended
// time.
UPGRADE_NEEDED_OUTDATED_INSTALL,
// If no update to Chrome has been installed for more than the recommended
// time AND auto-update is turned off.
UPGRADE_NEEDED_OUTDATED_INSTALL_NO_AU,
};
UpgradeDetector(const base::Clock* clock, const base::TickClock* tick_clock);
// Starts observing changes to Local State preference `pref`.
void MonitorPrefChanges(const std::string& pref);
// Returns the notification period specified via the
// RelaunchNotificationPeriod policy setting, or a zero delta if unset or out
// of range.
static base::TimeDelta GetRelaunchNotificationPeriod();
static bool IsRelaunchNotificationPolicyEnabled();
// Returns the adjusted deadline to fall within `window`. If the
// `deadline` has already passed the window for the day, it is prolonged for
// the next day within the window. If the `deadline` already falls within the
// window, no change is made.
static base::Time AdjustDeadline(base::Time deadline,
const RelaunchWindow& window);
// Returns the relaunch window specified via the RelaunchWindow policy
// setting, or nullopt if unset or set incorrectly.
static std::optional<RelaunchWindow> GetRelaunchWindowPolicyValue();
// Returns the default relaunch window within which the relaunch should take
// place. It is 2am to 4am from Chrome OS and the whole day for others.
static RelaunchWindow GetDefaultRelaunchWindow();
// Returns the delta between "grace" and "high" annoyance levels using
// `elevated_to_high_delta` which is the delta between "elevated" and "high"
// annoyance levels.
static base::TimeDelta GetGracePeriod(base::TimeDelta elevated_to_high_delta);
// Returns the network time, falling back to system time if unavailable.
// Returns true if it's network time, or false if it's not.
bool GetNetworkTimeWithFallback(base::Time& network_time);
// Returns true if `last_served_date_` is known and older than the number
// of days specified by the RelaunchFastIfOutdated policy.
bool ShouldRelaunchFast();
// Returns true if the last served date should be fetched on update, for
// the RelaunchOutdatedInstall policy.
bool ShouldFetchLastServedDate() const;
// Fetches the last served date via GetLastServedDate(), and updates
// `last_served_date_`.
void FetchLastServedDate();
const base::Clock* clock() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return clock_;
}
const base::TickClock* tick_clock() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return tick_clock_;
}
// Notifies that update is recommended and triggers different actions based
// on the update availability.
void NotifyUpgrade();
// Notifies that update is recommended.
void NotifyUpgradeRecommended();
// Notifies that a critical update has been installed. No details are
// expected.
void NotifyCriticalUpgradeInstalled();
// Notifies that an update is downloaded but deferred. Set `use_notification`
// to true to enable system tray notification.
void NotifyUpdateDeferred(bool use_notification);
// The function that sends out a notification that lets the rest of the UI
// know we should notify the user that a new update is available to download
// over cellular connection.
void NotifyUpdateOverCellularAvailable();
// Notifies that the user's one time permission on update over cellular
// connection has been granted.
void NotifyUpdateOverCellularOneTimePermissionGranted();
// Notifies about a request to override the relaunch notification style to
// required or reset the overridden style.
void NotifyRelaunchOverriddenToRequired(bool overridden);
// Triggers a critical update, which starts a timer that checks the machine
// idle state. Protected and virtual so that it could be overridden by tests.
virtual void TriggerCriticalUpdate();
UpgradeAvailable upgrade_available() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return upgrade_available_;
}
void set_upgrade_available(UpgradeAvailable available) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
upgrade_available_ = available;
}
void set_upgrade_detected_time(base::Time upgrade_detected_time) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
upgrade_detected_time_ = upgrade_detected_time;
}
void set_best_effort_experiment_updates_available(bool available) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
best_effort_experiment_updates_available_ = available;
}
bool critical_experiment_updates_available() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return critical_experiment_updates_available_;
}
void set_critical_experiment_updates_available(bool available) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
critical_experiment_updates_available_ = available;
}
void set_critical_update_acknowledged(bool acknowledged) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
critical_update_acknowledged_ = acknowledged;
}
void set_upgrade_notification_stage(UpgradeNotificationAnnoyanceLevel stage) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
upgrade_notification_stage_ = stage;
}
#if BUILDFLAG(IS_CHROMEOS)
void set_is_factory_reset_required(bool is_factory_reset_required) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
is_factory_reset_required_ = is_factory_reset_required;
}
void set_is_rollback(bool is_rollback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
is_rollback_ = is_rollback;
}
#endif // BUILDFLAG(IS_CHROMEOS)
private:
FRIEND_TEST_ALL_PREFIXES(AppMenuModelTest, Basics);
FRIEND_TEST_ALL_PREFIXES(RelaunchNotificationControllerUiTest,
ReactivateAfterDeadline);
FRIEND_TEST_ALL_PREFIXES(SystemTrayClientTest, UpdateTrayIcon);
friend class RelaunchNotificationControllerUiTest;
friend class UpgradeMetricsProviderTest;
// Called on the UI thread after one or more monitored prefs or
// `last_served_date_` have changed. If an update has been detected,
// subclasses may need to recompute the schedule for advancing through the
// annoyance levels.
virtual void RecomputeSchedule() {}
// Initiates an Idle check. Tells us whether Chrome has received any
// input events since the specified time.
void CheckIdle();
// Handles a change to the relaunch notification related Local State
// preferences. Posts a task to call OnThresholdPrefChanged() if it isn't
// already posted and pending for execution.
void OnRelaunchPrefChanged();
// Handles the result of GetLastServedDate().
void OnGotLastServedDate(std::optional<base::Time> last_served_date);
// A provider of Time to the detector.
const raw_ptr<const base::Clock> clock_;
// A provider of TimeTicks to the detectors' timers.
const raw_ptr<const base::TickClock> tick_clock_;
// Observes changes to the browser.relaunch_notification_period Local State
// preference.
PrefChangeRegistrar pref_change_registrar_;
// Whether any software updates are available (experiment updates are tracked
// separately via additional member variables below).
UpgradeAvailable upgrade_available_;
// The time at which an available upgrade was detected.
base::Time upgrade_detected_time_;
// Whether "best effort" experiment updates are available.
bool best_effort_experiment_updates_available_;
// Whether "critical" experiment updates are available.
bool critical_experiment_updates_available_;
// Whether the user has acknowledged the critical update.
bool critical_update_acknowledged_;
// Whether a task posted on any relaunch preference change is still pending
// for execution.
bool pref_change_task_pending_ = false;
#if BUILDFLAG(IS_CHROMEOS)
// Whether a factory reset is needed to complete an update.
bool is_factory_reset_required_ = false;
// Whether the update is actually an admin-initiated rollback of the device
// to an earlier version of Chrome OS, which results in the device being
// wiped when it's rebooted.
bool is_rollback_ = false;
#endif // BUILDFLAG(IS_CHROMEOS)
// A timer to check to see if we've been idle for long enough to show the
// critical warning. Should only be set if |upgrade_available_| is
// UPGRADE_AVAILABLE_CRITICAL.
base::RepeatingTimer idle_check_timer_;
// The stage at which the annoyance level for upgrade notifications is at.
UpgradeNotificationAnnoyanceLevel upgrade_notification_stage_;
// Whether we have waited long enough after detecting an upgrade (to see
// is we should start nagging about upgrading).
bool notify_upgrade_;
bool fetched_last_served_date_ = false;
std::optional<base::Time> last_served_date_;
SEQUENCE_CHECKER(sequence_checker_);
base::ObserverList<UpgradeObserver>::Unchecked observer_list_;
base::WeakPtrFactory<UpgradeDetector> weak_factory_{this};
};
#endif // CHROME_BROWSER_UPGRADE_DETECTOR_UPGRADE_DETECTOR_H_
|