Commit 8d0066e7 authored by Saurabh Nijhara's avatar Saurabh Nijhara Committed by Commit Bot

Configure relaunch notifications for device policy

The minimum chrome version policy enforces updates within a warning
time supplied by the admin. Once the device has installed the updates,
it is up to the relaunch notifications to enforce relaunch for
applying the updates.
This CL configures the relaunch notification according to the deadline
of the minimum chrome version policy if the relaunch deadline lies
post this policy deadline. It also overrides the relaunch notification
type to required.
Any further policy change to relaunch notification type, period and
heads up period would have no effect to enforce updates within the
policy deadline.

Bug: 1048607
Change-Id: I96a665a8feb494fd8a59d01e7dcb8155d8b07e0c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2270457
Commit-Queue: Saurabh Nijhara <snijhara@google.com>
Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#786234}
parent 7994b5e1
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "chrome/browser/chromeos/ui/update_required_notification.h" #include "chrome/browser/chromeos/ui/update_required_notification.h"
#include "chrome/browser/ui/ash/system_tray_client.h" #include "chrome/browser/ui/ash/system_tray_client.h"
#include "chrome/browser/upgrade_detector/build_state.h" #include "chrome/browser/upgrade_detector/build_state.h"
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_features.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
...@@ -82,6 +83,21 @@ chromeos::UpdateEngineClient* GetUpdateEngineClient() { ...@@ -82,6 +83,21 @@ chromeos::UpdateEngineClient* GetUpdateEngineClient() {
return chromeos::DBusThreadManager::Get()->GetUpdateEngineClient(); return chromeos::DBusThreadManager::Get()->GetUpdateEngineClient();
} }
// Overrides the relaunch notification style to required and configures the
// relaunch deadline according to the deadline.
void OverrideRelaunchNotification(base::Time deadline) {
UpgradeDetector* upgrade_detector = UpgradeDetector::GetInstance();
upgrade_detector->OverrideRelaunchNotificationToRequired(true);
upgrade_detector->OverrideHighAnnoyanceDeadline(deadline);
}
// Resets the overridden relaunch notification style and deadline.
void ResetRelaunchNotification() {
UpgradeDetector* upgrade_detector = UpgradeDetector::GetInstance();
upgrade_detector->ResetOverriddenDeadline();
upgrade_detector->OverrideRelaunchNotificationToRequired(false);
}
} // namespace } // namespace
const char MinimumVersionPolicyHandler::kChromeVersion[] = "chrome_version"; const char MinimumVersionPolicyHandler::kChromeVersion[] = "chrome_version";
...@@ -170,7 +186,7 @@ void MinimumVersionPolicyHandler::RegisterPrefs(PrefRegistrySimple* registry) { ...@@ -170,7 +186,7 @@ void MinimumVersionPolicyHandler::RegisterPrefs(PrefRegistrySimple* registry) {
base::TimeDelta()); base::TimeDelta());
} }
bool MinimumVersionPolicyHandler::IsDeadlineTimerRunningForTesting() { bool MinimumVersionPolicyHandler::IsDeadlineTimerRunningForTesting() const {
return update_required_deadline_timer_.IsRunning(); return update_required_deadline_timer_.IsRunning();
} }
...@@ -250,15 +266,16 @@ void MinimumVersionPolicyHandler::HandleUpdateNotRequired() { ...@@ -250,15 +266,16 @@ void MinimumVersionPolicyHandler::HandleUpdateNotRequired() {
Reset(); Reset();
// Hide update required screen if it is visible and switch back to the login // Hide update required screen if it is visible and switch back to the login
// screen. // screen.
if (delegate_->IsLoginSessionState()) { if (delegate_->IsLoginSessionState())
delegate_->HideUpdateRequiredScreenIfShown(); delegate_->HideUpdateRequiredScreenIfShown();
} ResetRelaunchNotification();
} }
void MinimumVersionPolicyHandler::Reset() { void MinimumVersionPolicyHandler::Reset() {
deadline_reached = false; deadline_reached = false;
eol_reached_ = false; eol_reached_ = false;
update_required_deadline_ = base::Time(); update_required_deadline_ = base::Time();
update_required_time_ = base::Time();
update_required_deadline_timer_.Stop(); update_required_deadline_timer_.Stop();
notification_timer_.Stop(); notification_timer_.Stop();
GetBuildState()->RemoveObserver(this); GetBuildState()->RemoveObserver(this);
...@@ -337,8 +354,9 @@ void MinimumVersionPolicyHandler::HandleUpdateRequired( ...@@ -337,8 +354,9 @@ void MinimumVersionPolicyHandler::HandleUpdateRequired(
// Need to start the timer even if the deadline is same as the previous one to // Need to start the timer even if the deadline is same as the previous one to
// handle the case of Chrome reboot. // handle the case of Chrome reboot.
if (update_required_deadline_ == previous_deadline && if (update_required_deadline_timer_.IsRunning() &&
update_required_deadline_timer_.IsRunning()) { update_required_deadline_timer_.desired_run_time() ==
update_required_deadline_) {
return; return;
} }
...@@ -348,9 +366,9 @@ void MinimumVersionPolicyHandler::HandleUpdateRequired( ...@@ -348,9 +366,9 @@ void MinimumVersionPolicyHandler::HandleUpdateRequired(
// still required. // still required.
// Hide update required screen if it is shown on the login screen. // Hide update required screen if it is shown on the login screen.
if (delegate_->IsLoginSessionState()) { if (delegate_->IsLoginSessionState())
delegate_->HideUpdateRequiredScreenIfShown(); delegate_->HideUpdateRequiredScreenIfShown();
}
// The |deadline| can only be equal to or greater than the // The |deadline| can only be equal to or greater than the
// |previous_deadline|. No need to update the local state if the deadline has // |previous_deadline|. No need to update the local state if the deadline has
// not been extended. // not been extended.
...@@ -360,8 +378,7 @@ void MinimumVersionPolicyHandler::HandleUpdateRequired( ...@@ -360,8 +378,7 @@ void MinimumVersionPolicyHandler::HandleUpdateRequired(
// The device has already downloaded the update in-session and waiting for // The device has already downloaded the update in-session and waiting for
// reboot to apply it. // reboot to apply it.
if (GetBuildState()->update_type() == BuildState::UpdateType::kNormalUpdate) { if (GetBuildState()->update_type() == BuildState::UpdateType::kNormalUpdate) {
// TODO(https://crbug.com/1048607): May be adjust relaunch notification OverrideRelaunchNotification(update_required_deadline_);
// timer as per new deadline.
return; return;
} }
...@@ -498,8 +515,10 @@ void MinimumVersionPolicyHandler::OnUpdate(const BuildState* build_state) { ...@@ -498,8 +515,10 @@ void MinimumVersionPolicyHandler::OnUpdate(const BuildState* build_state) {
// If the device has been successfully updated, the relaunch notifications // If the device has been successfully updated, the relaunch notifications
// will reboot it for applying the updates. // will reboot it for applying the updates.
GetUpdateEngineClient()->RemoveObserver(this); GetUpdateEngineClient()->RemoveObserver(this);
if (build_state->update_type() == BuildState::UpdateType::kNormalUpdate) if (build_state->update_type() == BuildState::UpdateType::kNormalUpdate) {
ResetOnUpdateCompleted(); ResetOnUpdateCompleted();
OverrideRelaunchNotification(update_required_deadline_);
}
} }
void MinimumVersionPolicyHandler::HideNotification() const { void MinimumVersionPolicyHandler::HideNotification() const {
......
...@@ -160,7 +160,11 @@ class MinimumVersionPolicyHandler ...@@ -160,7 +160,11 @@ class MinimumVersionPolicyHandler
fetch_eol_callback_ = std::move(callback); fetch_eol_callback_ = std::move(callback);
} }
bool IsDeadlineTimerRunningForTesting(); base::Time update_required_deadline_for_testing() const {
return update_required_deadline_;
}
bool IsDeadlineTimerRunningForTesting() const;
private: private:
void OnPolicyChanged(); void OnPolicyChanged();
...@@ -246,8 +250,13 @@ class MinimumVersionPolicyHandler ...@@ -246,8 +250,13 @@ class MinimumVersionPolicyHandler
// out and/or showing update required screen. // out and/or showing update required screen.
bool deadline_reached = false; bool deadline_reached = false;
// Time when the policy is applied and with respect to which the deadline to
// update the device is calculated.
base::Time update_required_time_; base::Time update_required_time_;
// Deadline for updating the device post which the user is restricted from
// using the session by force log out if a session is active and then blocking
// sign in at the login screen.
base::Time update_required_deadline_; base::Time update_required_deadline_;
// Fires when the deadline to update the device has reached or passed. // Fires when the deadline to update the device has reached or passed.
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h"
#include "chrome/browser/upgrade_detector/upgrade_detector.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_features.h"
#include "chromeos/constants/chromeos_switches.h" #include "chromeos/constants/chromeos_switches.h"
...@@ -665,6 +666,32 @@ IN_PROC_BROWSER_TEST_F(MinimumVersionPolicyTest, EolNotificationClick) { ...@@ -665,6 +666,32 @@ IN_PROC_BROWSER_TEST_F(MinimumVersionPolicyTest, EolNotificationClick) {
"chrome://management/"); "chrome://management/");
} }
IN_PROC_BROWSER_TEST_F(MinimumVersionPolicyTest, RelaunchNotificationOverride) {
LoginManagedUser();
// Set policy value as a list of requirements.
base::Value requirement_list(base::Value::Type::LIST);
requirement_list.Append(
CreateRequirement(kNewVersion, kShortWarningInDays, kShortWarningInDays));
SetDevicePolicyAndWaitForSettingChange(requirement_list);
base::Time deadline =
GetMinimumVersionPolicyHandler()->update_required_deadline_for_testing();
// Simulate device updated.
SetUpdateEngineStatus(update_engine::Operation::UPDATED_NEED_REBOOT);
// Relaunch notifications are shown and the relaunch deadline is configured as
// per the policy deadline.
UpgradeDetector* upgrade_detector = UpgradeDetector::GetInstance();
EXPECT_EQ(upgrade_detector->upgrade_notification_stage(),
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
EXPECT_EQ(upgrade_detector->GetHighAnnoyanceDeadline(), deadline);
// Revoking update required should reset the overridden the relaunch
// notifications.
SetDevicePolicyAndWaitForSettingChange(base::Value(base::Value::Type::LIST));
EXPECT_NE(upgrade_detector->GetHighAnnoyanceDeadline(), deadline);
}
class MinimumVersionNoUsersLoginTest : public MinimumVersionPolicyTestBase { class MinimumVersionNoUsersLoginTest : public MinimumVersionPolicyTestBase {
public: public:
MinimumVersionNoUsersLoginTest() = default; MinimumVersionNoUsersLoginTest() = default;
......
...@@ -40,12 +40,14 @@ enum class RelaunchNotificationSetting { ...@@ -40,12 +40,14 @@ enum class RelaunchNotificationSetting {
// Returns the policy setting, mapping out-of-range values to kChromeMenuOnly. // Returns the policy setting, mapping out-of-range values to kChromeMenuOnly.
RelaunchNotificationSetting ReadPreference() { RelaunchNotificationSetting ReadPreference() {
switch (g_browser_process->local_state()->GetInteger( PrefService* local_state = g_browser_process->local_state();
prefs::kRelaunchNotification)) { if (local_state) {
case 1: switch (local_state->GetInteger(prefs::kRelaunchNotification)) {
return RelaunchNotificationSetting::kRecommendedBubble; case 1:
case 2: return RelaunchNotificationSetting::kRecommendedBubble;
return RelaunchNotificationSetting::kRequiredDialog; case 2:
return RelaunchNotificationSetting::kRequiredDialog;
}
} }
return RelaunchNotificationSetting::kChromeMenuOnly; return RelaunchNotificationSetting::kChromeMenuOnly;
} }
...@@ -59,8 +61,7 @@ RelaunchNotificationController::RelaunchNotificationController( ...@@ -59,8 +61,7 @@ RelaunchNotificationController::RelaunchNotificationController(
base::DefaultTickClock::GetInstance()) {} base::DefaultTickClock::GetInstance()) {}
RelaunchNotificationController::~RelaunchNotificationController() { RelaunchNotificationController::~RelaunchNotificationController() {
if (last_notification_style_ != NotificationStyle::kNone) StopObservingUpgrades();
StopObservingUpgrades();
} }
// static // static
...@@ -86,10 +87,15 @@ RelaunchNotificationController::RelaunchNotificationController( ...@@ -86,10 +87,15 @@ RelaunchNotificationController::RelaunchNotificationController(
// Synchronize the instance with the current state of the preference. // Synchronize the instance with the current state of the preference.
HandleCurrentStyle(); HandleCurrentStyle();
} }
// Need to register with the UpgradeDetector right at the start to observe any
// calls to override the preference value controlling the notification style.
StartObservingUpgrades();
} }
void RelaunchNotificationController::OnUpgradeRecommended() { void RelaunchNotificationController::OnUpgradeRecommended() {
DCHECK_NE(last_notification_style_, NotificationStyle::kNone); if (last_notification_style_ == NotificationStyle::kNone)
return;
UpgradeDetector::UpgradeNotificationAnnoyanceLevel current_level = UpgradeDetector::UpgradeNotificationAnnoyanceLevel current_level =
upgrade_detector_->upgrade_notification_stage(); upgrade_detector_->upgrade_notification_stage();
const base::Time current_high_deadline = const base::Time current_high_deadline =
...@@ -129,22 +135,34 @@ void RelaunchNotificationController::OnUpgradeRecommended() { ...@@ -129,22 +135,34 @@ void RelaunchNotificationController::OnUpgradeRecommended() {
last_high_deadline_ = current_high_deadline; last_high_deadline_ = current_high_deadline;
} }
void RelaunchNotificationController::OnRelaunchOverriddenToRequired(
bool override) {
if (notification_type_required_override_ == override)
return;
notification_type_required_override_ = override;
HandleCurrentStyle();
}
void RelaunchNotificationController::HandleCurrentStyle() { void RelaunchNotificationController::HandleCurrentStyle() {
NotificationStyle notification_style = NotificationStyle::kNone; NotificationStyle notification_style = NotificationStyle::kNone;
switch (ReadPreference()) { if (notification_type_required_override_) {
case RelaunchNotificationSetting::kChromeMenuOnly: notification_style = NotificationStyle::kRequired;
DCHECK_EQ(notification_style, NotificationStyle::kNone); } else {
break; switch (ReadPreference()) {
case RelaunchNotificationSetting::kRecommendedBubble: case RelaunchNotificationSetting::kChromeMenuOnly:
notification_style = NotificationStyle::kRecommended; DCHECK_EQ(notification_style, NotificationStyle::kNone);
break; break;
case RelaunchNotificationSetting::kRequiredDialog: case RelaunchNotificationSetting::kRecommendedBubble:
notification_style = NotificationStyle::kRequired; notification_style = NotificationStyle::kRecommended;
break; break;
case RelaunchNotificationSetting::kRequiredDialog:
notification_style = NotificationStyle::kRequired;
break;
}
} }
// Nothing to do if there has been no change in the preference. // Nothing to do if there has been no change in the notification style.
if (notification_style == last_notification_style_) if (notification_style == last_notification_style_)
return; return;
...@@ -156,18 +174,11 @@ void RelaunchNotificationController::HandleCurrentStyle() { ...@@ -156,18 +174,11 @@ void RelaunchNotificationController::HandleCurrentStyle() {
last_level_ = UpgradeDetector::UPGRADE_ANNOYANCE_NONE; last_level_ = UpgradeDetector::UPGRADE_ANNOYANCE_NONE;
if (notification_style == NotificationStyle::kNone) { if (notification_style == NotificationStyle::kNone) {
// Transition away from monitoring for upgrade events back to being dormant: // AppMenuIconController takes care of updating the Chrome menu as needed.
// there is no need since AppMenuIconController takes care of updating the
// Chrome menu as needed.
StopObservingUpgrades();
last_notification_style_ = notification_style; last_notification_style_ = notification_style;
return; return;
} }
// Transitioning away from being dormant: observe the UpgradeDetector.
if (last_notification_style_ == NotificationStyle::kNone)
StartObservingUpgrades();
last_notification_style_ = notification_style; last_notification_style_ = notification_style;
// Synchronize the instance with the current state of detection. // Synchronize the instance with the current state of detection.
......
...@@ -46,6 +46,9 @@ class TickClock; ...@@ -46,6 +46,9 @@ class TickClock;
// On Chrome OS both notifications (recommended and required, described above) // On Chrome OS both notifications (recommended and required, described above)
// are shown in the unified system tray, overwriting the default "update // are shown in the unified system tray, overwriting the default "update
// available" notification. It cannot be deferred, so it persists until reboot. // available" notification. It cannot be deferred, so it persists until reboot.
// In certain conditions, the preference value could be overridden by the
// UpgradeDetector which then takes priority over the original value and any
// further changes to the preference have no effect.
class RelaunchNotificationController : public UpgradeObserver { class RelaunchNotificationController : public UpgradeObserver {
public: public:
// |upgrade_detector| is expected to be the process-wide detector, and must // |upgrade_detector| is expected to be the process-wide detector, and must
...@@ -70,6 +73,7 @@ class RelaunchNotificationController : public UpgradeObserver { ...@@ -70,6 +73,7 @@ class RelaunchNotificationController : public UpgradeObserver {
// UpgradeObserver: // UpgradeObserver:
void OnUpgradeRecommended() override; void OnUpgradeRecommended() override;
void OnRelaunchOverriddenToRequired(bool override) override;
private: private:
enum class NotificationStyle { enum class NotificationStyle {
...@@ -82,7 +86,9 @@ class RelaunchNotificationController : public UpgradeObserver { ...@@ -82,7 +86,9 @@ class RelaunchNotificationController : public UpgradeObserver {
RelaunchNotificationControllerPlatformImpl platform_impl_; RelaunchNotificationControllerPlatformImpl platform_impl_;
// Adjusts to the current notification style as indicated by the // Adjusts to the current notification style as indicated by the
// browser.relaunch_notification Local State preference. // browser.relaunch_notification Local State preference. If the notification
// style has been overridden, then that value is given priority over the
// preference value.
void HandleCurrentStyle(); void HandleCurrentStyle();
// Bring the instance out of or back to dormant mode. // Bring the instance out of or back to dormant mode.
...@@ -190,6 +196,11 @@ class RelaunchNotificationController : public UpgradeObserver { ...@@ -190,6 +196,11 @@ class RelaunchNotificationController : public UpgradeObserver {
// relaunch once the relaunch required dialog's deadline is reached. // relaunch once the relaunch required dialog's deadline is reached.
util::WallClockTimer timer_; util::WallClockTimer timer_;
// A flag to denote that the relaunch notification type policy value has been
// overridden to required. Changes to the policy value will not affect the
// notification type.
bool notification_type_required_override_ = false;
DISALLOW_COPY_AND_ASSIGN(RelaunchNotificationController); DISALLOW_COPY_AND_ASSIGN(RelaunchNotificationController);
}; };
......
...@@ -148,6 +148,10 @@ class FakeUpgradeDetector : public UpgradeDetector { ...@@ -148,6 +148,10 @@ class FakeUpgradeDetector : public UpgradeDetector {
NotifyUpgrade(); NotifyUpgrade();
} }
void BroadcastNotificationTypeOverriden(bool override) {
NotifyRelaunchOverriddenToRequired(override);
}
base::TimeDelta high_threshold() const { return high_threshold_; } base::TimeDelta high_threshold() const { return high_threshold_; }
private: private:
...@@ -737,6 +741,31 @@ TEST_F(RelaunchNotificationControllerTest, DeferredRequired) { ...@@ -737,6 +741,31 @@ TEST_F(RelaunchNotificationControllerTest, DeferredRequired) {
::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate); ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
} }
// Call to override the current relaunch notification type should override it to
// required and policy change should not affect it.
TEST_F(RelaunchNotificationControllerTest, OverriddenToRequired) {
SetNotificationPref(1);
::testing::StrictMock<MockControllerDelegate> mock_controller_delegate;
FakeRelaunchNotificationController controller(
upgrade_detector(), GetMockClock(), GetMockTickClock(),
&mock_controller_delegate);
fake_upgrade_detector().BroadcastNotificationTypeOverriden(true);
EXPECT_CALL(mock_controller_delegate, NotifyRelaunchRequired());
fake_upgrade_detector().BroadcastLevelChange(
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
SetNotificationPref(0);
::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
EXPECT_CALL(mock_controller_delegate, Close());
fake_upgrade_detector().BroadcastNotificationTypeOverriden(false);
::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
}
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
class RelaunchNotificationControllerPlatformImplTest : public ::testing::Test { class RelaunchNotificationControllerPlatformImplTest : public ::testing::Test {
......
...@@ -59,6 +59,10 @@ void UpgradeDetector::Shutdown() { ...@@ -59,6 +59,10 @@ void UpgradeDetector::Shutdown() {
pref_change_registrar_.RemoveAll(); pref_change_registrar_.RemoveAll();
} }
void UpgradeDetector::OverrideRelaunchNotificationToRequired(bool override) {
NotifyRelaunchOverriddenToRequired(override);
}
UpgradeDetector::UpgradeDetector(const base::Clock* clock, UpgradeDetector::UpgradeDetector(const base::Clock* clock,
const base::TickClock* tick_clock) const base::TickClock* tick_clock)
: clock_(clock), : clock_(clock),
...@@ -182,6 +186,15 @@ void UpgradeDetector::NotifyUpdateOverCellularOneTimePermissionGranted() { ...@@ -182,6 +186,15 @@ void UpgradeDetector::NotifyUpdateOverCellularOneTimePermissionGranted() {
observer.OnUpdateOverCellularOneTimePermissionGranted(); observer.OnUpdateOverCellularOneTimePermissionGranted();
} }
void UpgradeDetector::NotifyRelaunchOverriddenToRequired(bool override) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!observer_list_.might_have_observers())
return;
for (auto& observer : observer_list_)
observer.OnRelaunchOverriddenToRequired(override);
}
void UpgradeDetector::TriggerCriticalUpdate() { void UpgradeDetector::TriggerCriticalUpdate() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const base::TimeDelta idle_timer = const base::TimeDelta idle_timer =
......
...@@ -132,6 +132,21 @@ class UpgradeDetector { ...@@ -132,6 +132,21 @@ class UpgradeDetector {
// reached, or a null tick count if an upgrade has not yet been detected. // reached, or a null tick count if an upgrade has not yet been detected.
virtual base::Time GetHighAnnoyanceDeadline() = 0; virtual base::Time GetHighAnnoyanceDeadline() = 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 override);
void AddObserver(UpgradeObserver* observer); void AddObserver(UpgradeObserver* observer);
void RemoveObserver(UpgradeObserver* observer); void RemoveObserver(UpgradeObserver* observer);
...@@ -198,6 +213,10 @@ class UpgradeDetector { ...@@ -198,6 +213,10 @@ class UpgradeDetector {
// connection has been granted. // connection has been granted.
void NotifyUpdateOverCellularOneTimePermissionGranted(); void NotifyUpdateOverCellularOneTimePermissionGranted();
// Notifies about a request to override the relaunch notification style to
// required or reset the overridden style.
void NotifyRelaunchOverriddenToRequired(bool override);
// Triggers a critical update, which starts a timer that checks the machine // 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. // idle state. Protected and virtual so that it could be overridden by tests.
virtual void TriggerCriticalUpdate(); virtual void TriggerCriticalUpdate();
......
...@@ -108,6 +108,26 @@ base::Time UpgradeDetectorChromeos::GetHighAnnoyanceDeadline() { ...@@ -108,6 +108,26 @@ base::Time UpgradeDetectorChromeos::GetHighAnnoyanceDeadline() {
return high_deadline_; return high_deadline_;
} }
void UpgradeDetectorChromeos::OverrideHighAnnoyanceDeadline(
base::Time deadline) {
DCHECK(!upgrade_detected_time().is_null());
if (deadline > upgrade_detected_time()) {
high_deadline_override_ = deadline;
CalculateDeadlines();
NotifyOnUpgrade();
}
}
void UpgradeDetectorChromeos::ResetOverriddenDeadline() {
if (high_deadline_override_.is_null())
return;
DCHECK(!upgrade_detected_time().is_null());
high_deadline_override_ = base::Time();
CalculateDeadlines();
NotifyOnUpgrade();
}
void UpgradeDetectorChromeos::OnUpdate(const BuildState* build_state) { void UpgradeDetectorChromeos::OnUpdate(const BuildState* build_state) {
if (upgrade_detected_time().is_null()) { if (upgrade_detected_time().is_null()) {
set_upgrade_detected_time(clock()->Now()); set_upgrade_detected_time(clock()->Now());
...@@ -194,6 +214,12 @@ void UpgradeDetectorChromeos::CalculateDeadlines() { ...@@ -194,6 +214,12 @@ void UpgradeDetectorChromeos::CalculateDeadlines() {
heads_up_period = kDefaultHeadsUpPeriod; heads_up_period = kDefaultHeadsUpPeriod;
elevated_deadline_ = elevated_deadline_ =
std::max(high_deadline_ - heads_up_period, upgrade_detected_time()); std::max(high_deadline_ - heads_up_period, upgrade_detected_time());
if (!high_deadline_override_.is_null() &&
high_deadline_ > high_deadline_override_) {
elevated_deadline_ = upgrade_detected_time();
high_deadline_ = std::max(elevated_deadline_, high_deadline_override_);
}
} }
void UpgradeDetectorChromeos::OnRelaunchNotificationPeriodPrefChanged() { void UpgradeDetectorChromeos::OnRelaunchNotificationPeriodPrefChanged() {
......
...@@ -39,6 +39,8 @@ class UpgradeDetectorChromeos : public UpgradeDetector, ...@@ -39,6 +39,8 @@ class UpgradeDetectorChromeos : public UpgradeDetector,
void Shutdown() override; void Shutdown() override;
base::TimeDelta GetHighAnnoyanceLevelDelta() override; base::TimeDelta GetHighAnnoyanceLevelDelta() override;
base::Time GetHighAnnoyanceDeadline() override; base::Time GetHighAnnoyanceDeadline() override;
void OverrideHighAnnoyanceDeadline(base::Time deadline) override;
void ResetOverriddenDeadline() override;
// BuildStateObserver: // BuildStateObserver:
void OnUpdate(const BuildState* build_state) override; void OnUpdate(const BuildState* build_state) override;
...@@ -63,7 +65,10 @@ class UpgradeDetectorChromeos : public UpgradeDetector, ...@@ -63,7 +65,10 @@ class UpgradeDetectorChromeos : public UpgradeDetector,
// zero delta if unset or out of range. // zero delta if unset or out of range.
static base::TimeDelta GetRelaunchHeadsUpPeriod(); static base::TimeDelta GetRelaunchHeadsUpPeriod();
// Calculates |elevated_deadline_| and |high_deadline_|. // Calculates |elevated_deadline_| and |high_deadline_| using either
// |high_deadline_override_| if it is not null or the threshold values
// computed based on the RelaunchNotificationPeriod and RelaunchHeadsUpPeriod
// policy settings.
void CalculateDeadlines(); void CalculateDeadlines();
// Handles a change to the browser.relaunch_heads_up_period or // Handles a change to the browser.relaunch_heads_up_period or
...@@ -94,6 +99,10 @@ class UpgradeDetectorChromeos : public UpgradeDetector, ...@@ -94,6 +99,10 @@ class UpgradeDetectorChromeos : public UpgradeDetector,
// The time when high annoyance deadline is reached. // The time when high annoyance deadline is reached.
base::Time high_deadline_; base::Time high_deadline_;
// The overridden high annoyance deadline which takes priority over
// |high_deadline_| for showing relaunch notifications.
base::Time high_deadline_override_;
// Observes changes to the browser.relaunch_heads_up_period Local State // Observes changes to the browser.relaunch_heads_up_period Local State
// preference. // preference.
PrefChangeRegistrar pref_change_registrar_; PrefChangeRegistrar pref_change_registrar_;
......
...@@ -55,6 +55,7 @@ class MockUpgradeObserver : public UpgradeObserver { ...@@ -55,6 +55,7 @@ class MockUpgradeObserver : public UpgradeObserver {
MOCK_METHOD0(OnCriticalUpgradeInstalled, void()); MOCK_METHOD0(OnCriticalUpgradeInstalled, void());
MOCK_METHOD0(OnOutdatedInstall, void()); MOCK_METHOD0(OnOutdatedInstall, void());
MOCK_METHOD0(OnOutdatedInstallNoAutoUpdate, void()); MOCK_METHOD0(OnOutdatedInstallNoAutoUpdate, void());
MOCK_METHOD1(OnRelaunchOverriddenToRequired, void(bool override));
private: private:
UpgradeDetector* const upgrade_detector_; UpgradeDetector* const upgrade_detector_;
...@@ -452,3 +453,65 @@ TEST_F(UpgradeDetectorChromeosTest, TimezoneAdjustment) { ...@@ -452,3 +453,65 @@ TEST_F(UpgradeDetectorChromeosTest, TimezoneAdjustment) {
upgrade_detector.Shutdown(); upgrade_detector.Shutdown();
RunUntilIdle(); RunUntilIdle();
} }
TEST_F(UpgradeDetectorChromeosTest, TestOverrideThresholds) {
TestUpgradeDetectorChromeos upgrade_detector(GetMockClock(),
GetMockTickClock());
upgrade_detector.Init();
::testing::StrictMock<MockUpgradeObserver> mock_observer(&upgrade_detector);
const auto notification_period = base::TimeDelta::FromDays(7);
const auto heads_up_period = base::TimeDelta::FromDays(2);
SetNotificationPeriodPref(notification_period);
SetHeadsUpPeriodPref(heads_up_period);
// Simulate update installed.
NotifyUpdateReadyToInstall();
EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
// Overriding the thresholds should change the high annoyance deadline and the
// notification stage accordingly and notify the observers.
base::TimeDelta delta = base::TimeDelta::FromHours(2);
base::Time deadline = upgrade_detector.upgrade_detected_time() + delta;
EXPECT_CALL(mock_observer, OnUpgradeRecommended());
upgrade_detector.OverrideHighAnnoyanceDeadline(deadline);
EXPECT_EQ(upgrade_detector.GetHighAnnoyanceDeadline(), deadline);
EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
UpgradeDetector::UPGRADE_ANNOYANCE_ELEVATED);
::testing::Mock::VerifyAndClear(&mock_observer);
EXPECT_CALL(mock_observer, OnUpgradeRecommended());
upgrade_detector.ResetOverriddenDeadline();
EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
::testing::Mock::VerifyAndClear(&mock_observer);
upgrade_detector.Shutdown();
RunUntilIdle();
}
TEST_F(UpgradeDetectorChromeosTest, TestOverrideNotificationType) {
TestUpgradeDetectorChromeos upgrade_detector(GetMockClock(),
GetMockTickClock());
upgrade_detector.Init();
::testing::StrictMock<MockUpgradeObserver> mock_observer(&upgrade_detector);
NotifyUpdateReadyToInstall();
EXPECT_EQ(upgrade_detector.upgrade_notification_stage(),
UpgradeDetector::UPGRADE_ANNOYANCE_NONE);
// Observer should get some notification about the overridden relaunch
// notification style.
EXPECT_CALL(mock_observer, OnRelaunchOverriddenToRequired(true));
upgrade_detector.OverrideRelaunchNotificationToRequired(true);
::testing::Mock::VerifyAndClear(&mock_observer);
// Observer should get some notification about the resetting the overridden
// relaunch notification style.
EXPECT_CALL(mock_observer, OnRelaunchOverriddenToRequired(false));
upgrade_detector.OverrideRelaunchNotificationToRequired(false);
::testing::Mock::VerifyAndClear(&mock_observer);
upgrade_detector.Shutdown();
RunUntilIdle();
}
...@@ -34,6 +34,10 @@ class UpgradeObserver { ...@@ -34,6 +34,10 @@ class UpgradeObserver {
// disabled. No details are expected. // disabled. No details are expected.
virtual void OnOutdatedInstallNoAutoUpdate() {} virtual void OnOutdatedInstallNoAutoUpdate() {}
// Triggered when a request to override the relaunch notification style to
// required or reset the overridden style is received.
virtual void OnRelaunchOverriddenToRequired(bool override) {}
protected: protected:
virtual ~UpgradeObserver() {} virtual ~UpgradeObserver() {}
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment