blob: 0a3eabd536c09890c533208a5901f35396c2a21f [file] [log] [blame]
// Copyright 2012 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_DEVICE_SETTINGS_SERVICE_H_
#define CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_SERVICE_H_
#include <memory>
#include <string>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
#include "components/ownership/owner_settings_service.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/core/common/cloud/cloud_policy_validator.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "components/policy/proto/device_management_backend.pb.h"
class PrefService;
namespace ownership {
class OwnerKeyUtil;
class PublicKey;
} // namespace ownership
namespace policy {
namespace off_hours {
class DeviceOffHoursController;
} // namespace off_hours
} // namespace policy
namespace ash {
class SessionManagerOperation;
// Deals with the low-level interface to Chrome OS device settings. Device
// settings are stored in a protobuf that's protected by a cryptographic
// signature generated by a key in the device owner's possession. Key and
// settings are brokered by the session_manager daemon.
//
// The purpose of DeviceSettingsService is to keep track of the current key and
// settings blob. For reading and writing device settings, use CrosSettings
// instead, which provides a high-level interface that allows for manipulation
// of individual settings.
//
// DeviceSettingsService generates notifications for key and policy update
// events so interested parties can reload state as appropriate.
class DeviceSettingsService : public SessionManagerClient::Observer {
public:
// Indicates ownership status of the device (listed in upgrade order).
enum class OwnershipStatus {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
kOwnershipUnknown = 0,
// Not yet owned.
kOwnershipNone = 1,
// Either consumer ownership or cloud management.
kOwnershipTaken = 2,
kMaxValue = kOwnershipTaken
};
using OwnershipStatusCallback = base::OnceCallback<void(OwnershipStatus)>;
using PolicyDataCallback =
base::OnceCallback<void(enterprise_management::PolicyData*)>;
// Status codes for Load() and Store().
// These values are logged to UMA. Entries should not be renumbered and
// numeric values should never be reused. Please keep in sync with
// "DeviceSettingsStatus2" in
// tools/metrics/histograms/metadata/enterprise/enums.xml.
enum Status {
STORE_SUCCESS,
STORE_KEY_UNAVAILABLE, // Owner key not yet configured.
STORE_OPERATION_FAILED, // IPC to session_manager daemon failed.
STORE_NO_POLICY, // No settings blob present.
STORE_INVALID_POLICY, // Invalid settings blob (proto parse failed).
STORE_VALIDATION_ERROR, // Policy validation failure.
STORE_KEY_UNAVAILABLE_NOT_INITIALIZED, // Early in boot process.
STORE_KEY_UNAVAILABLE_NOT_LOCKED, // Owner key not present, ownership
// not taken. Not an error.
STORE_KEY_UNAVAILABLE_MANAGED, // Owner key not present for managed device.
kMaxValue = STORE_KEY_UNAVAILABLE_MANAGED,
};
// Observer interface.
class Observer {
public:
virtual ~Observer();
// Indicates device ownership status changes. This is triggered upon every
// browser start since the transition from uninitialized (OWNERSHIP_UNKNOWN)
// to initialized (either of OWNERSHIP_{NONE,TAKEN}) also counts as an
// ownership change.
virtual void OwnershipStatusChanged();
// Gets called after updates to the device settings.
virtual void DeviceSettingsUpdated();
virtual void OnDeviceSettingsServiceShutdown();
};
// Manage singleton instance.
static void Initialize();
static bool IsInitialized();
static void Shutdown();
static DeviceSettingsService* Get();
// Returns a human-readable string describing |status|.
static const char* StatusToString(Status status);
// Creates a device settings service instance. This is meant for unit tests,
// production code uses the singleton returned by Get() above.
DeviceSettingsService();
DeviceSettingsService(const DeviceSettingsService&) = delete;
DeviceSettingsService& operator=(const DeviceSettingsService&) = delete;
~DeviceSettingsService() override;
// To be called on startup once threads are initialized and D-Bus is ready.
// `local_state` must be valid until `StopProcessing()`. `local_state` may be
// null only in tests.
void StartProcessing(PrefService* local_state,
SessionManagerClient* session_manager_client,
scoped_refptr<ownership::OwnerKeyUtil> owner_key_util);
// Prevents the service from making further calls to session_manager_client
// and stops any pending operations.
void StopProcessing();
// Must only be used with a |device_mode| that has been read and verified by
// the InstallAttributes class.
void SetDeviceMode(policy::DeviceMode device_mode);
const enterprise_management::PolicyData* policy_data() const {
return policy_data_.get();
}
const enterprise_management::PolicyFetchResponse* policy_fetch_response()
const {
return policy_fetch_response_.get();
}
// Returns the currently active device settings. Returns nullptr if the device
// settings have not been retrieved from session_manager yet.
const enterprise_management::ChromeDeviceSettingsProto* device_settings()
const {
return device_settings_.get();
}
// Returns the currently used owner key.
scoped_refptr<ownership::PublicKey> GetPublicKey();
// Returns the status generated by the *last operation*.
// WARNING: It is not correct to take this method as an indication of whether
// DeviceSettingsService contains valid device settings. In order to answer
// that question, simply check whether device_settings() is different from
// nullptr.
Status status() const { return store_status_; }
// Returns the currently device off hours controller. The returned pointer is
// guaranteed to be non-null.
policy::off_hours::DeviceOffHoursController* device_off_hours_controller()
const {
return device_off_hours_controller_.get();
}
void SetDeviceOffHoursControllerForTesting(
std::unique_ptr<policy::off_hours::DeviceOffHoursController> controller);
// Triggers an attempt to pull the public half of the owner key from disk and
// load the device settings.
void Load();
// Attempts to load asynchronously the settings if they haven't been loaded
// already and no request is in the queue. The aim is to avoid additional
// request when not needed. Should NOT be used when the settings need to be
// renewed, like in invalidations flow or when an explicit request from user
// to reload is received.
void LoadIfNotPresent();
// Synchronously pulls the public key and loads the device settings.
void LoadImmediately();
// Stores a policy blob to session_manager. The result of the operation is
// reported through |callback|. If successful, the updated device settings are
// present in policy_data() and device_settings() when the callback runs.
void Store(std::unique_ptr<enterprise_management::PolicyFetchResponse> policy,
base::OnceClosure callback);
// Returns the ownership status. May return OWNERSHIP_UNKNOWN if the disk
// hasn't been checked yet.
OwnershipStatus GetOwnershipStatus();
// Determines the ownership status and reports the result to |callback|. This
// is guaranteed to never return OWNERSHIP_UNKNOWN.
virtual void GetOwnershipStatusAsync(OwnershipStatusCallback callback);
// Checks whether we have the private owner key.
//
// DEPRECATED (ygorshenin@, crbug.com/433840): this method should
// not be used since private key is a profile-specific resource and
// should be checked and used in a profile-aware manner, through
// OwnerSettingsService.
bool HasPrivateOwnerKey();
// Sets the identity of the user that's interacting with the service. This is
// relevant only for writing settings through SignAndStore().
//
// TODO (ygorshenin@, crbug.com/433840): get rid of the method when
// write path for device settings will be removed from
// DeviceSettingsProvider and all existing clients will be switched
// to OwnerSettingsServiceAsh.
void InitOwner(const std::string& username,
const base::WeakPtr<ownership::OwnerSettingsService>&
owner_settings_service);
const std::string& GetUsername() const;
ownership::OwnerSettingsService* GetOwnerSettingsService() const;
// Mark that the device will establish consumer ownership. If the flag is set
// and ownership is not taken, policy reload will be deferred until InitOwner
// is called. So that the ownership status is flipped after the private part
// of owner is fully loaded.
void MarkWillEstablishConsumerOwnership();
// Returns whether the current user should take ownership of the device
// (effectively whether the user is the first consumer user on the device).
bool GetWillEstablishConsumerOwnership() const {
return will_establish_consumer_ownership_;
}
// Returns if the device is managed according to the device settings.
bool IsDeviceManaged() const;
// Returns if the device policy is loaded and contains the DM token.
bool HasDmToken() const;
// Adds an observer.
void AddObserver(Observer* observer);
// Removes an observer.
void RemoveObserver(Observer* observer);
// SessionManagerClient::Observer:
void OwnerKeySet(bool success) override;
void PropertyChangeComplete(bool success) override;
void SessionStopping() override;
private:
friend class OwnerSettingsServiceAsh;
// Enqueues a new operation. Takes ownership of |operation| and starts it
// right away if there is no active operation currently.
void Enqueue(std::unique_ptr<SessionManagerOperation> operation);
// Enqueues a load operation.
void EnqueueLoad(bool request_key_load);
// Makes sure there's a reload operation so changes to the settings (and key,
// in case |request_key_load| is set) are getting picked up.
void EnsureReload(bool request_key_load);
// Runs the next pending operation.
void StartNextOperation();
// Updates status, policy data and owner key from a finished operation.
void HandleCompletedOperation(base::OnceClosure callback,
SessionManagerOperation* operation,
Status status);
// Same as HandleCompletedOperation(), but also starts the next pending
// operation if available.
void HandleCompletedAsyncOperation(base::OnceClosure callback,
SessionManagerOperation* operation,
Status status);
// Helper method for GetOwnershipStatusAsync to avoid data race upon
// user sign-in.
void ValidateOwnershipStatusAndNotify(OwnershipStatusCallback callback);
// Run OwnershipStatusChanged() for observers.
void NotifyOwnershipStatusChanged() const;
// Run DeviceSettingsUpdated() for observers.
void NotifyDeviceSettingsUpdated() const;
// Processes pending callbacks from GetOwnershipStatusAsync().
void RunPendingOwnershipStatusCallbacks();
raw_ptr<PrefService> local_state_ = nullptr;
raw_ptr<SessionManagerClient> session_manager_client_ = nullptr;
scoped_refptr<ownership::OwnerKeyUtil> owner_key_util_;
Status store_status_ = STORE_SUCCESS;
std::vector<OwnershipStatusCallback> pending_ownership_status_callbacks_;
std::string username_;
scoped_refptr<ownership::PublicKey> public_key_;
base::WeakPtr<ownership::OwnerSettingsService> owner_settings_service_;
// Ownership status before the current session manager operation.
OwnershipStatus previous_ownership_status_ =
OwnershipStatus::kOwnershipUnknown;
std::unique_ptr<enterprise_management::PolicyFetchResponse>
policy_fetch_response_;
std::unique_ptr<enterprise_management::PolicyData> policy_data_;
std::unique_ptr<enterprise_management::ChromeDeviceSettingsProto>
device_settings_;
policy::DeviceMode device_mode_ = policy::DEVICE_MODE_PENDING;
// The queue of pending operations. The first operation on the queue is
// currently active; it gets removed and destroyed once it completes.
base::circular_deque<std::unique_ptr<SessionManagerOperation>>
pending_operations_;
base::ObserverList<Observer>::Unchecked observers_;
// Whether the device will be establishing consumer ownership.
bool will_establish_consumer_ownership_ = false;
// Whether we received the signal that the session is stopping.
bool session_stopping_ = false;
std::unique_ptr<policy::off_hours::DeviceOffHoursController>
device_off_hours_controller_;
base::WeakPtrFactory<DeviceSettingsService> weak_factory_{this};
};
std::ostream& operator<<(std::ostream&, DeviceSettingsService::OwnershipStatus);
} // namespace ash
#endif // CHROME_BROWSER_ASH_SETTINGS_DEVICE_SETTINGS_SERVICE_H_