| // Copyright 2017 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_ASH_POLICY_HANDLERS_MINIMUM_VERSION_POLICY_HANDLER_H_ |
| #define CHROME_BROWSER_ASH_POLICY_HANDLERS_MINIMUM_VERSION_POLICY_HANDLER_H_ |
| |
| #include <memory> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "base/scoped_observation.h" |
| #include "base/time/time.h" |
| #include "base/timer/wall_clock_timer.h" |
| #include "base/version.h" |
| #include "chrome/browser/upgrade_detector/build_state_observer.h" |
| #include "chromeos/ash/components/dbus/update_engine/update_engine_client.h" |
| #include "chromeos/ash/components/network/network_state_handler_observer.h" |
| #include "chromeos/ash/components/settings/cros_settings.h" |
| |
| class PrefRegistrySimple; |
| |
| namespace ash { |
| class NetworkStateHandler; |
| class UpdateRequiredNotification; |
| } // namespace ash |
| |
| namespace base { |
| class Clock; |
| 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 ash::NetworkStateHandlerObserver, |
| public ash::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() = default; |
| |
| // Checks if the user is logged in as any kiosk app or this is an |
| // auto-launch kiosk device. |
| virtual bool IsKioskMode() const = 0; |
| |
| // Checks if the device is enterprise managed. |
| virtual bool IsDeviceEnterpriseManaged() 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::Value::Dict& 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(const MinimumVersionPolicyHandler&) = delete; |
| MinimumVersionPolicyHandler& operator=(const MinimumVersionPolicyHandler&) = |
| delete; |
| |
| ~MinimumVersionPolicyHandler() override; |
| |
| // BuildStateObserver: |
| void OnUpdate(const BuildState* build_state) override; |
| |
| // NetworkStateHandlerObserver: |
| void DefaultNetworkChanged(const ash::NetworkState* network) override; |
| void OnShuttingDown() 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. |
| std::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(ash::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(ash::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. |
| raw_ptr<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. |
| base::WallClockTimer update_required_deadline_timer_; |
| |
| // Fires when next update required notification is to be shown. |
| base::WallClockTimer notification_timer_; |
| |
| // Non-owning reference to CrosSettings. This class have shorter lifetime than |
| // CrosSettings. |
| raw_ptr<ash::CrosSettings> cros_settings_; |
| |
| const raw_ptr<base::Clock> 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_; |
| |
| base::ScopedObservation<ash::NetworkStateHandler, |
| ash::NetworkStateHandlerObserver> |
| network_state_handler_observer_{this}; |
| |
| // List of registered observers. |
| base::ObserverList<Observer>::Unchecked observers_; |
| |
| base::WeakPtrFactory<MinimumVersionPolicyHandler> weak_factory_{this}; |
| }; |
| |
| } // namespace policy |
| |
| #endif // CHROME_BROWSER_ASH_POLICY_HANDLERS_MINIMUM_VERSION_POLICY_HANDLER_H_ |