Skip to content

Commit

Permalink
Show post reboot notification
Browse files Browse the repository at this point in the history
Show simple post reboot notification after the reboot occurs due to DeviceScheduledReboot policy set.

Bug: 1293741
Change-Id: Ifcc20448773bfe129f00877bf7bd51d54bf0b6b4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3497746
Reviewed-by: Xiaoqian Dai <xdai@chromium.org>
Reviewed-by: David Roger <droger@chromium.org>
Reviewed-by: Anqing Zhao <anqing@chromium.org>
Commit-Queue: Sanja Perisic <sanjaperisic@chromium.org>
Cr-Commit-Position: refs/heads/main@{#992016}
  • Loading branch information
Sanja Perisic authored and Chromium LUCI CQ committed Apr 13, 2022
1 parent 5f88608 commit 9121793
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 75 deletions.
4 changes: 4 additions & 0 deletions ash/constants/ash_pref_names.cc
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,10 @@ const char kLoginScreenWebUILazyLoading[] =
// Boolean value for the FloatingWorkspaceEnabled policy
const char kFloatingWorkspaceEnabled[] = "ash.floating_workspace_enabled";

// Boolean value indicating that post reboot notification should be shown to the
// user.
const char kShowPostRebootNotification[] = "ash.show_post_reboot_notification";

// NOTE: New prefs should start with the "ash." prefix. Existing prefs moved
// into this file should not be renamed, since they may be synced.

Expand Down
1 change: 1 addition & 0 deletions ash/constants/ash_pref_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ extern const char kLoginScreenWebUILazyLoading[];

COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kFloatingWorkspaceEnabled[];

COMPONENT_EXPORT(ASH_CONSTANTS) extern const char kShowPostRebootNotification[];
} // namespace prefs
} // namespace ash

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ void DeviceScheduledRebootHandler::OnRebootTimerExpired() {
// not skip reboot due to grace period applied.
if (!skip_reboot_ && base::FeatureList::IsEnabled(
ash::features::kDeviceForceScheduledReboot)) {
// Schedule post reboot notification for the user in session.
notifications_scheduler_->SchedulePostRebootNotification();
RebootDevice(kRebootDescriptionOnTimerExpired);
return;
}
Expand Down Expand Up @@ -171,7 +173,7 @@ void DeviceScheduledRebootHandler::StartRebootTimer() {
if (base::FeatureList::IsEnabled(
ash::features::kDeviceForceScheduledReboot)) {
if (!skip_reboot_) {
notifications_scheduler_->ScheduleNotifications(
notifications_scheduler_->SchedulePendingRebootNotifications(
base::BindOnce(&DeviceScheduledRebootHandler::OnRebootButtonClicked,
base::Unretained(this)),
scheduled_task_executor_->GetScheduledTaskTime());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@

#include "chrome/browser/ash/policy/scheduled_task_handler/reboot_notifications_scheduler.h"

#include "ash/constants/ash_pref_names.h"
#include "base/system/sys_info.h"
#include "base/time/default_clock.h"
#include "base/time/default_tick_clock.h"
#include "chrome/browser/ash/app_restore/full_restore_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_prefs/user_prefs.h"

namespace policy {

Expand All @@ -18,7 +25,10 @@ constexpr base::TimeDelta kGraceTime = base::Hours(1);

RebootNotificationsScheduler::RebootNotificationsScheduler()
: RebootNotificationsScheduler(base::DefaultClock::GetInstance(),
base::DefaultTickClock::GetInstance()) {}
base::DefaultTickClock::GetInstance()) {
if (session_manager::SessionManager::Get())
observation_.Observe(session_manager::SessionManager::Get());
}

RebootNotificationsScheduler::RebootNotificationsScheduler(
const base::Clock* clock,
Expand All @@ -28,7 +38,12 @@ RebootNotificationsScheduler::RebootNotificationsScheduler(

RebootNotificationsScheduler::~RebootNotificationsScheduler() = default;

void RebootNotificationsScheduler::ScheduleNotifications(
void RebootNotificationsScheduler::RegisterProfilePrefs(
PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(ash::prefs::kShowPostRebootNotification, false);
}

void RebootNotificationsScheduler::SchedulePendingRebootNotifications(
base::OnceClosure reboot_callback,
const base::Time& reboot_time) {
ResetState();
Expand All @@ -44,21 +59,54 @@ void RebootNotificationsScheduler::ScheduleNotifications(
base::Time timer_run_time = reboot_time_ - kNotificationDelay;
notification_timer_.Start(
FROM_HERE, timer_run_time,
base::BindOnce(&RebootNotificationsScheduler::MaybeShowNotification,
weak_ptr_factory_.GetWeakPtr()));
base::BindOnce(
&RebootNotificationsScheduler::MaybeShowPendingRebootNotification,
weak_ptr_factory_.GetWeakPtr()));
} else {
MaybeShowNotification();
MaybeShowPendingRebootNotification();
}

if (delay > kDialogDelay) {
base::Time timer_run_time = reboot_time_ - kDialogDelay;
dialog_timer_.Start(
FROM_HERE, timer_run_time,
base::BindOnce(&RebootNotificationsScheduler::MaybeShowDialog,
weak_ptr_factory_.GetWeakPtr()));
base::BindOnce(
&RebootNotificationsScheduler::MaybeShowPendingRebootDialog,
weak_ptr_factory_.GetWeakPtr()));
return;
}
MaybeShowDialog();
MaybeShowPendingRebootDialog();
}

void RebootNotificationsScheduler::SchedulePostRebootNotification() {
PrefService* prefs = GetPrefsForActiveProfile();
if (prefs) {
prefs->SetBoolean(ash::prefs::kShowPostRebootNotification, true);
}
}

void RebootNotificationsScheduler::OnUserSessionStarted(bool is_primary_user) {
// Return if we need to wait for the initialization of full restore service.
if (ShouldWaitFullRestoreInit())
return;

MaybeShowPostRebootNotification(true /*show_simple_notification*/);
}

void RebootNotificationsScheduler::MaybeShowPostRebootNotification(
bool show_simple_notification) {
PrefService* prefs = GetPrefsForActiveProfile();
// Return if the pref is not set for the profile.
if (!prefs->GetBoolean(ash::prefs::kShowPostRebootNotification))
return;

if (show_simple_notification) {
notification_controller_.MaybeShowPostRebootNotification();
}
prefs->SetBoolean(ash::prefs::kShowPostRebootNotification, false);
// No need to observe any more, since we showed the post reboot notification,
// either as a simple one or integrated with full restore.
observation_.Reset();
}

void RebootNotificationsScheduler::ResetState() {
Expand All @@ -76,20 +124,27 @@ bool RebootNotificationsScheduler::ShouldApplyGraceTime(
return ((delay + GetSystemUptime()) <= kGraceTime);
}

void RebootNotificationsScheduler::MaybeShowNotification() {
void RebootNotificationsScheduler::MaybeShowPendingRebootNotification() {
notification_controller_.MaybeShowPendingRebootNotification(
reboot_time_,
base::BindRepeating(&RebootNotificationsScheduler::OnRebootButtonClicked,
base::Unretained(this)));
}

void RebootNotificationsScheduler::MaybeShowDialog() {
void RebootNotificationsScheduler::MaybeShowPendingRebootDialog() {
notification_controller_.MaybeShowPendingRebootDialog(
reboot_time_,
base::BindOnce(&RebootNotificationsScheduler::OnRebootButtonClicked,
base::Unretained(this)));
}

PrefService* RebootNotificationsScheduler::GetPrefsForActiveProfile() const {
Profile* profile = ProfileManager::GetActiveUserProfile();
if (!profile)
return nullptr;
return user_prefs::UserPrefs::Get(profile);
}

void RebootNotificationsScheduler::OnRebootButtonClicked() {
DCHECK(reboot_callback_);
std::move(reboot_callback_).Run();
Expand All @@ -113,4 +168,10 @@ void RebootNotificationsScheduler::CloseNotifications() {
notification_controller_.CloseRebootDialog();
}

bool RebootNotificationsScheduler::ShouldWaitFullRestoreInit() const {
Profile* profile = ProfileManager::GetActiveUserProfile();
return ash::full_restore::FullRestoreServiceFactory::
IsFullRestoreAvailableForProfile(profile);
}

} // namespace policy
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,43 @@

#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/wall_clock_timer.h"
#include "chrome/browser/ui/ash/device_scheduled_reboot/reboot_notification_controller.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "components/session_manager/core/session_manager_observer.h"

namespace policy {

// This class schedules timers for showing notification and dialog when
// scheduled reboot policy is set.
class RebootNotificationsScheduler {
// This class schedules timers for showing pending reboot notification and
// dialog when scheduled reboot policy is set. The class also schedules
// post-reboot notification shown to the user after the policy reboot. If the
// full restore service is available for the user profile, post reboot
// notification is integrated with full restore notification. Otherwise, a
// simple post reboot notification is shown.
class RebootNotificationsScheduler
: public session_manager::SessionManagerObserver {
public:
RebootNotificationsScheduler();
RebootNotificationsScheduler(const RebootNotificationsScheduler&) = delete;
RebootNotificationsScheduler& operator=(const RebootNotificationsScheduler&) =
delete;
virtual ~RebootNotificationsScheduler();
~RebootNotificationsScheduler() override;

// Schedules timers for showing notification and dialog or shows them right
// away if the scheduled reboot time is soon. Notifications are not shown when
// grace time applies.
void ScheduleNotifications(base::OnceClosure reboot_callback,
const base::Time& reboot_time);
// Registers boolean pref for showing post reboot notification.
static void RegisterProfilePrefs(PrefRegistrySimple* registry);

// Schedules timers for showing pending reboot notification and dialog or
// shows them right away if the scheduled reboot time is soon. Notifications
// are not shown when grace time applies.
void SchedulePendingRebootNotifications(base::OnceClosure reboot_callback,
const base::Time& reboot_time);

// Sets pref for showing the post reboot notification for the active user.
void SchedulePostRebootNotification();

// Resets timers and closes notification and dialog if open.
void ResetState();
Expand All @@ -36,6 +52,13 @@ class RebootNotificationsScheduler {
// last device reboot.
bool ShouldApplyGraceTime(const base::Time& reboot_time) const;

// SessionManagerObserver:
void OnUserSessionStarted(bool is_primary_user) override;

// Shows simple post reboot notification if |show_simple_notification| flag is
// set to true and unsets the pref for showing the post reboot notification.
void MaybeShowPostRebootNotification(bool show_simple_notification);

protected:
RebootNotificationsScheduler(const base::Clock* clock,
const base::TickClock* tick_clock);
Expand All @@ -45,8 +68,11 @@ class RebootNotificationsScheduler {
void OnRebootButtonClicked();

private:
virtual void MaybeShowNotification();
virtual void MaybeShowDialog();
virtual void MaybeShowPendingRebootNotification();
virtual void MaybeShowPendingRebootDialog();

// Returns prefs for active profile or nullptr.
virtual PrefService* GetPrefsForActiveProfile() const;

// Returns current time.
virtual const base::Time GetCurrentTime() const;
Expand All @@ -57,9 +83,13 @@ class RebootNotificationsScheduler {
// Returns delay from now until |reboot_time|.
base::TimeDelta GetRebootDelay(const base::Time& reboot_time) const;

// Closes the reboot notification and the reboot dialog.
// Closes the pending reboot notification and the reboot dialog.
virtual void CloseNotifications();

// Returns true if the full restore service is available for the profile and
// we need to wait for full restore service initialization.
virtual bool ShouldWaitFullRestoreInit() const;

// Timers for scheduling notification or dialog displaying.
base::WallClockTimer notification_timer_, dialog_timer_;
// Controller responsible for creating notifications and dialog.
Expand All @@ -68,6 +98,10 @@ class RebootNotificationsScheduler {
base::Time reboot_time_;
// Callback to run on "Reboot now" button click.
base::OnceClosure reboot_callback_;
base::ScopedObservation<session_manager::SessionManager,
session_manager::SessionManagerObserver>
observation_{this};

base::WeakPtrFactory<RebootNotificationsScheduler> weak_ptr_factory_{this};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "ash/components/settings/cros_settings_names.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "base/feature_list.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
Expand All @@ -24,6 +25,7 @@
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "components/prefs/testing_pref_service.h"
#include "components/user_manager/scoped_user_manager.h"
#include "services/device/public/cpp/test/test_wake_lock_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
Expand Down Expand Up @@ -84,11 +86,13 @@ class DeviceScheduledRebootHandlerTest : public testing::Test {
auto task_executor = std::make_unique<FakeScheduledTaskExecutor>(
task_environment_.GetMockClock());
scheduled_task_executor_ = task_executor.get();
prefs_ = std::make_unique<TestingPrefServiceSimple>();
auto notifications_scheduler =
std::make_unique<FakeRebootNotificationsScheduler>(
task_environment_.GetMockClock(),
task_environment_.GetMockTickClock());
task_environment_.GetMockTickClock(), prefs_.get());
notifications_scheduler_ = notifications_scheduler.get();
RebootNotificationsScheduler::RegisterProfilePrefs(prefs_->registry());
device_scheduled_reboot_handler_ =
std::make_unique<DeviceScheduledRebootHandlerForTest>(
ash::CrosSettings::Get(), std::move(task_executor),
Expand Down Expand Up @@ -173,6 +177,7 @@ class DeviceScheduledRebootHandlerTest : public testing::Test {
std::unique_ptr<DeviceScheduledRebootHandlerForTest>
device_scheduled_reboot_handler_;
ash::ScopedTestingCrosSettings cros_settings_;
std::unique_ptr<TestingPrefServiceSimple> prefs_;
device::TestWakeLockProvider wake_lock_provider_;
FakeRebootNotificationsScheduler* notifications_scheduler_;
base::test::ScopedFeatureList scoped_feature_list_;
Expand Down Expand Up @@ -493,6 +498,7 @@ TEST_F(DeviceScheduledRebootHandlerTest,
InitWithFeatureFlag(true /* enable_force_scheduled_reboots */);
EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
.WillRepeatedly(testing::Return(true));
EXPECT_FALSE(prefs_->GetBoolean(ash::prefs::kShowPostRebootNotification));

// Set device uptime to 10 minutes and schedule reboot in 30 minutes. Apply
// grace time - reboot should not occur.
Expand Down Expand Up @@ -535,6 +541,9 @@ TEST_F(DeviceScheduledRebootHandlerTest,
EXPECT_TRUE(CheckNotificationStats(expected_notification_count,
expected_dialog_count));
EXPECT_TRUE(CheckStats(expected_scheduled_reboots, expected_reboot_requests));

// Verify post reboot notification flag is set.
EXPECT_TRUE(prefs_->GetBoolean(ash::prefs::kShowPostRebootNotification));
}

TEST_F(DeviceScheduledRebootHandlerTest, SimulateNotificationButtonClick) {
Expand Down Expand Up @@ -570,6 +579,9 @@ TEST_F(DeviceScheduledRebootHandlerTest, SimulateNotificationButtonClick) {
notifications_scheduler_->SimulateRebootButtonClick();
expected_reboot_requests += 1;
EXPECT_TRUE(CheckStats(expected_scheduled_reboots, expected_reboot_requests));

// Verify post reboot notification flag is not set.
EXPECT_FALSE(prefs_->GetBoolean(ash::prefs::kShowPostRebootNotification));
}

} // namespace policy

0 comments on commit 9121793

Please sign in to comment.