| // Copyright 2021 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_SETTINGS_OWNER_PENDING_SETTING_CONTROLLER_H_ |
| #define CHROME_BROWSER_ASH_SETTINGS_OWNER_PENDING_SETTING_CONTROLLER_H_ |
| |
| #include "base/callback_list.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/scoped_observation.h" |
| #include "base/sequence_checker.h" |
| #include "base/values.h" |
| #include "chrome/browser/ash/settings/device_settings_service.h" |
| #include "chromeos/ash/components/settings/cros_settings.h" |
| #include "components/ownership/owner_settings_service.h" |
| |
| class PrefService; |
| class Profile; |
| |
| namespace ownership { |
| class OwnerSettingsService; |
| } |
| |
| namespace ash { |
| |
| // An extra layer on top of CrosSettings / OwnerSettingsService that allows for |
| // writing a setting before ownership is taken. |
| // |
| // Ordinarily, the OwnerSettingsService interface is used for writing settings, |
| // and the CrosSettings interface is used for reading them - but as the OSS |
| // cannot be used until the device has an owner, this class can be used instead, |
| // since writing the new value with SetEnabled works even before ownership is |
| // taken. |
| // |
| // If OSS is ready then the new value is written straight away, and if not, then |
| // a pending write is queued that is completed as soon as the OSS is ready. |
| // This write will complete even if Chrome is restarted in the meantime. |
| // The caller need not care whether the write was immediate or pending, as long |
| // as they also use this class to read the value of the device pref. |
| // IsEnabled will return the pending value until ownership is taken and the |
| // pending value is written - from then on it will return the signed, stored |
| // value from CrosSettings. |
| class OwnerPendingSettingController |
| : public ownership::OwnerSettingsService::Observer { |
| public: |
| OwnerPendingSettingController() = delete; |
| OwnerPendingSettingController(const OwnerPendingSettingController&) = delete; |
| OwnerPendingSettingController& operator=( |
| const OwnerPendingSettingController&) = delete; |
| |
| // Store the new value. This will happen straight away if |profile| is the |
| // owner, and it will cause a pending write to be buffered and written later |
| // if the device has no owner yet. It will write a warning and skip if the |
| // device already has an owner, and |profile| is not that owner. |
| void Set(Profile* profile, base::Value value); |
| |
| // Returns the latest value - regardless of whether this has been successfully |
| // signed and persisted, or if it is still stored as a pending write. Can |
| // return std::nullopt if there is no pending write and no signed value. |
| std::optional<base::Value> GetValue() const; |
| |
| // Add an observer |callback| for changes to the setting. |
| [[nodiscard]] base::CallbackListSubscription AddObserver( |
| const base::RepeatingClosure& callback); |
| |
| // Called once ownership is taken, |service| is the service of the user taking |
| // ownership. |
| void OnOwnershipTaken(ownership::OwnerSettingsService* service); |
| |
| // Sets the callback which is called once when the pending |value| is |
| // propagated to the device settings. Support only one callback at a time. |
| // CHECKs if the second callback is being set. |
| // It's different from the |AddObserver| API. Observers are called |
| // immediately after |Set| is called with the different |value| setting. |
| void SetOnDeviceSettingsStoredCallBack(base::OnceClosure callback); |
| |
| // ownership::OwnerSettingsService::Observer implementation: |
| void OnSignedPolicyStored(bool success) override; |
| void OnServiceShutdown() override; |
| |
| // Clears any value waiting to be written (from storage in local state). |
| void ClearPendingValue(); |
| |
| protected: |
| OwnerPendingSettingController(const std::string& pref_name, |
| const std::string& pending_pref_name, |
| PrefService* local_state); |
| ~OwnerPendingSettingController() override; |
| |
| // Delegates immediately to SetWithService if |service| is ready, otherwise |
| // runs SetWithService asynchronously once |service| is ready. |
| void SetWithServiceAsync(ownership::OwnerSettingsService* service, |
| base::Value value); |
| |
| // Callback used by SetWithServiceAsync. |
| void SetWithServiceCallback( |
| const base::WeakPtr<ownership::OwnerSettingsService>& service, |
| const base::Value& value, |
| bool is_owner); |
| |
| // Uses |service| to write the latest value, as long as |service| belongs |
| // to the owner - otherwise just prints a warning. |
| void SetWithService(ownership::OwnerSettingsService* service, |
| const base::Value& value); |
| |
| // Notifies observers if the value has changed. |
| void NotifyObservers(); |
| |
| base::WeakPtr<OwnerPendingSettingController> as_weak_ptr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| raw_ptr<PrefService> local_state_; |
| std::optional<base::Value> value_notified_to_observers_; |
| base::RepeatingClosureList callback_list_; |
| base::CallbackListSubscription setting_subscription_; |
| |
| base::ScopedObservation<ownership::OwnerSettingsService, |
| ownership::OwnerSettingsService::Observer> |
| owner_settings_service_observation_{this}; |
| |
| // Indicates if the setting value is in the process of being set with the |
| // service. There is a small period of time needed between start saving the |
| // value and before the value is stored correctly in the service. We should |
| // not use the setting value from the service if it is still in the process |
| // of being saved. |
| bool is_value_being_set_with_service_ = false; |
| |
| private: |
| friend class StatsReportingControllerTest; |
| |
| // Gets the current ownership status - owned, unowned, or unknown. |
| DeviceSettingsService::OwnershipStatus GetOwnershipStatus() const; |
| |
| // Get the owner-settings service for a particular profile. A variety of |
| // different results can be returned, depending on the profile. |
| // a) A ready-to-use service that we know belongs to the owner. |
| // b) A ready-to-use service that we know does NOT belong to the owner. |
| // c) A service that is NOT ready-to-use, which MIGHT belong to the owner. |
| // d) nullptr (for instance, if |profile| is a guest). |
| ownership::OwnerSettingsService* GetOwnerSettingsService(Profile* profile); |
| |
| // Return the value waiting to be written (stored in local_state), if one |
| // exists. |
| std::optional<base::Value> GetPendingValue() const; |
| |
| // Return the value signed and stored in CrosSettings, if one exists. |
| std::optional<base::Value> GetSignedStoredValue() const; |
| |
| // Returns whether pending value should be used when determining the value |
| // of `GetValue`. |
| bool ShouldReadFromPendingValue() const; |
| |
| base::OnceClosure on_device_settings_stored_callback_; |
| |
| const std::string pref_name_; |
| const std::string pending_pref_name_; |
| |
| base::WeakPtrFactory<OwnerPendingSettingController> weak_factory_{this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_SETTINGS_OWNER_PENDING_SETTING_CONTROLLER_H_ |