blob: 3dee59cdc55d0d6372d5590bc72de9ccc8d361c1 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_MINIMUM_VERSION_POLICY_HANDLER_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_MINIMUM_VERSION_POLICY_HANDLER_H_
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/util/timer/wall_clock_timer.h"
#include "base/version.h"
#include "chrome/browser/ash/settings/cros_settings.h"
#include "chrome/browser/upgrade_detector/build_state_observer.h"
#include "chromeos/dbus/update_engine_client.h"
#include "chromeos/network/network_state_handler_observer.h"
class PrefRegistrySimple;
namespace ash {
class UpdateRequiredNotification;
} // namespace ash
namespace base {
class Clock;
class DictionaryValue;
class Time;
} // namespace base
namespace policy {
// This class observes the device setting |kDeviceMinimumVersion|, and
// checks if respective requirement is met. If an update is not required, all
// running timers are reset. If an update is required, it calculates the
// deadline using the warning period in the policy and restarts the timer. It
// also calls UpdateRequiredNotification to show in-session notifications if an
// update is required but it cannot be downloaded due to network limitations or
// Auto Update Expiration.
class MinimumVersionPolicyHandler
: public BuildStateObserver,
public chromeos::NetworkStateHandlerObserver,
public chromeos::UpdateEngineClient::Observer {
public:
static const char kRequirements[];
static const char kChromeOsVersion[];
static const char kWarningPeriod[];
static const char kEolWarningPeriod[];
static const char kUnmanagedUserRestricted[];
class Observer {
public:
virtual void OnMinimumVersionStateChanged() = 0;
virtual ~Observer() = default;
};
// Delegate of MinimumVersionPolicyHandler to handle the external
// dependencies.
class Delegate {
public:
virtual ~Delegate() {}
// Checks if the user is logged in as any kiosk app.
virtual bool IsKioskMode() const = 0;
// Checks if the device is enterprise managed.
virtual bool IsEnterpriseManaged() const = 0;
// Checks if a user is logged in.
virtual bool IsUserLoggedIn() const = 0;
// Checks if the user logged in is managed and not a child user.
virtual bool IsUserEnterpriseManaged() const = 0;
// Checks if we are currently on the login screen.
virtual bool IsLoginSessionState() const = 0;
// Checks if login is in progress before starting user session.
virtual bool IsLoginInProgress() const = 0;
// Shows the update required screen.
virtual void ShowUpdateRequiredScreen() = 0;
// Terminates the current session and restarts Chrome to show the login
// screen.
virtual void RestartToLoginScreen() = 0;
// Hides update required screen and shows the login screen.
virtual void HideUpdateRequiredScreenIfShown() = 0;
virtual base::Version GetCurrentVersion() const = 0;
};
class MinimumVersionRequirement {
public:
MinimumVersionRequirement(const base::Version version,
const base::TimeDelta warning,
const base::TimeDelta eol_warning);
MinimumVersionRequirement(const MinimumVersionRequirement&) = delete;
// Method used to create an instance of MinimumVersionRequirement from
// dictionary if it contains valid version string.
static std::unique_ptr<MinimumVersionRequirement> CreateInstanceIfValid(
const base::DictionaryValue* dict);
// This is used to compare two MinimumVersionRequirement objects
// and returns 1 if the first object has version or warning time
// or eol warning time greater than that the second, -1 if the
// its version or warning time or eol warning time is less than the second,
// else 0.
int Compare(const MinimumVersionRequirement* other) const;
base::Version version() const { return minimum_version_; }
base::TimeDelta warning() const { return warning_time_; }
base::TimeDelta eol_warning() const { return eol_warning_time_; }
private:
base::Version minimum_version_;
base::TimeDelta warning_time_;
base::TimeDelta eol_warning_time_;
};
enum class NetworkStatus { kAllowed, kMetered, kOffline };
enum class NotificationType {
kMeteredConnection,
kNoConnection,
kEolReached
};
explicit MinimumVersionPolicyHandler(Delegate* delegate,
ash::CrosSettings* cros_settings);
~MinimumVersionPolicyHandler() override;
// BuildStateObserver:
void OnUpdate(const BuildState* build_state) override;
// NetworkStateHandlerObserver:
void DefaultNetworkChanged(const chromeos::NetworkState* network) override;
// UpdateEngineClient::Observer:
void UpdateStatusChanged(const update_engine::StatusResult& status) override;
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
bool RequirementsAreSatisfied() const { return GetState() == nullptr; }
const MinimumVersionRequirement* GetState() const { return state_.get(); }
bool DeadlineReached() { return deadline_reached_; }
static void RegisterPrefs(PrefRegistrySimple* registry);
// Show notification on login if the user is managed or
// |unmanaged_user_restricted_| is set to true if it is the last day to
// deadline.
void MaybeShowNotificationOnLogin();
// Whether banner to return back the device should be visible in Settings. It
// is true when an update is required on a device that has reached End Of Life
// (Auto Update Expiration) and the currently signed in user is enterprise
// managed or an unmanaged user restricted by DeviceMinimumVersion policy.
bool ShouldShowUpdateRequiredEolBanner() const;
// Returns the number of days to deadline if update is required and deadline
// has not been reached. Returns null if update is not required.
base::Optional<int> GetTimeRemainingInDays();
// Callback used in tests and invoked after end-of-life status has been
// fetched from the update_engine.
void set_fetch_eol_callback_for_testing(base::OnceClosure callback) {
fetch_eol_callback_ = std::move(callback);
}
base::Time update_required_deadline_for_testing() const {
return update_required_deadline_;
}
bool IsDeadlineTimerRunningForTesting() const;
private:
// Returns |true| if the current version satisfies the given requirement.
bool CurrentVersionSatisfies(
const MinimumVersionRequirement& requirement) const;
// Whether the current user should receive update required notifications and
// force signed out on reaching the deadline. Retuns true if the user is
// enterprise managed or |unmanaged_user_restricted_| is true.
bool IsPolicyRestrictionAppliedForUser() const;
void OnPolicyChanged();
bool IsPolicyApplicable();
void Reset();
// Handles post update completed actions like reset timers, hide update
// required notification and stop observing build state.
void ResetOnUpdateCompleted();
// Handles the state when update is required as per the policy. If on the
// login screen, update required screen is shown, else the user is logged out
// if the device is not updated within the given |warning_time|. The
// |warning_time| is supplied by the policy.
void HandleUpdateRequired(base::TimeDelta warning_time);
void HandleUpdateNotRequired();
// Invokes update_engine_client to fetch the end-of-life status of the device.
void FetchEolInfo();
// Callback after fetching end-of-life info from the update_engine_client.
void OnFetchEolInfo(chromeos::UpdateEngineClient::EolInfo info);
// Called when the warning time to apply updates has expired. If the user on
// the login screen, the update required screen is shown else the current user
// session is terminated to bring the user back to the login screen.
void OnDeadlineReached();
// Starts the timer to expire when |deadline| is reached.
void StartDeadlineTimer(base::Time deadline);
// Starts observing the BuildState for any updates in Chrome OS and resets the
// state if new version satisfies the minimum version requirement.
void StartObservingUpdate();
// Shows notification for a managed logged in user if update is required and
// the device can not be updated due to end-of-life or network limitations.
void MaybeShowNotification(base::TimeDelta warning);
// Shows notification if required and starts a timer to expire when the next
// notification is to be shown.
void ShowAndScheduleNotification(base::Time deadline);
void HideNotification() const;
void StopObservingNetwork();
// Start updating over metered network as user has given consent through
// notification click.
void UpdateOverMeteredPermssionGranted();
// Tells whether starting an update check succeeded or not.
void OnUpdateCheckStarted(
chromeos::UpdateEngineClient::UpdateCheckResult result);
// Callback from UpdateEngineClient::SetUpdateOverCellularOneTimePermission().
void OnSetUpdateOverCellularOneTimePermission(bool success);
// Updates pref |kUpdateRequiredWarningPeriod| in local state to
// |warning_time|. If |kUpdateRequiredTimerStartTime| is not null, it means
// update is already required and hence, the timer start time should not be
// updated.
void UpdateLocalState(base::TimeDelta warning_time);
// Resets the local state prefs to default values.
void ResetLocalState();
// This delegate instance is owned by the owner of
// MinimumVersionPolicyHandler. The owner is responsible to make sure that the
// delegate lives throughout the life of the policy handler.
Delegate* delegate_;
// This represents the current minimum version requirement.
// It is chosen as one of the configurations specified in the policy. It is
// set to nullptr if the current version is higher than the minimum required
// version in all the configurations.
std::unique_ptr<MinimumVersionRequirement> state_;
// If this flag is true, unmanaged user sessions receive update required
// notifications and are force logged out when deadline is reached.
bool unmanaged_user_restricted_ = false;
bool eol_reached_ = false;
// If this flag is true, user should restricted to use the session by logging
// out and/or showing update required screen.
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_;
// 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_;
// Fires when the deadline to update the device has reached or passed.
util::WallClockTimer update_required_deadline_timer_;
// Fires when next update required notification is to be shown.
util::WallClockTimer notification_timer_;
// Non-owning reference to CrosSettings. This class have shorter lifetime than
// CrosSettings.
ash::CrosSettings* cros_settings_;
base::Clock* const clock_;
base::OnceClosure fetch_eol_callback_;
base::CallbackListSubscription policy_subscription_;
// Handles showing in-session update required notifications on the basis of
// current network and time to reach the deadline.
std::unique_ptr<ash::UpdateRequiredNotification> notification_handler_;
// List of registered observers.
base::ObserverList<Observer>::Unchecked observers_;
base::WeakPtrFactory<MinimumVersionPolicyHandler> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(MinimumVersionPolicyHandler);
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_MINIMUM_VERSION_POLICY_HANDLER_H_