| // 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_METRICS_PER_USER_STATE_MANAGER_CHROMEOS_H_ |
| #define CHROME_BROWSER_METRICS_PER_USER_STATE_MANAGER_CHROMEOS_H_ |
| |
| #include <string> |
| |
| #include "base/callback_list.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/sequence_checker.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/task/thread_pool.h" |
| #include "chrome/browser/ash/settings/device_settings_service.h" |
| #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" |
| #include "chrome/browser/metrics/profile_pref_names.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chromeos/ash/components/login/session/session_termination_manager.h" |
| #include "components/account_id/account_id.h" |
| #include "components/metrics/metrics_log_store.h" |
| #include "components/metrics/metrics_provider.h" |
| #include "components/metrics/metrics_service.h" |
| #include "components/metrics_services_manager/metrics_services_manager.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/user_manager/user.h" |
| #include "components/user_manager/user_manager.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace metrics { |
| |
| // State manager for per-user metrics collection. Listens to user |
| // creation/deletion and manages user prefs accordingly. |
| // |
| // When a particular user is created (login), all metrics collected so far |
| // will be flushed to local state. Before a user is destroyed (logout), all |
| // metrics will be flushed to the user dir. |
| // |
| // It is assumed that there can only be at most one user logged in at once. This |
| // assumption is only true in Ash Chrome. |
| class PerUserStateManagerChromeOS |
| : public user_manager::UserManager::UserSessionStateObserver, |
| public user_manager::UserManager::Observer, |
| public ash::SessionTerminationManager::Observer { |
| public: |
| // Callback to handle changes in user metrics consent. |
| using MetricsConsentHandler = base::RepeatingCallback<void(bool)>; |
| |
| // Does not own params passed by pointer. Caller should ensure that the |
| // lifetimes of the weak pointers exceed that of |this|. |
| PerUserStateManagerChromeOS( |
| MetricsServiceClient* metrics_service_client, |
| user_manager::UserManager* user_manager, |
| PrefService* local_state, |
| const MetricsLogStore::StorageLimits& storage_limits, |
| const std::string& signing_key); |
| |
| // Does not own |metrics_service_client| and |local_state|. Lifetime of |
| // these raw pointers should be managed by the caller. |
| PerUserStateManagerChromeOS(MetricsServiceClient* metrics_service_client, |
| PrefService* local_state); |
| |
| PerUserStateManagerChromeOS(const PerUserStateManagerChromeOS& other) = |
| delete; |
| PerUserStateManagerChromeOS& operator=( |
| const PerUserStateManagerChromeOS& other) = delete; |
| ~PerUserStateManagerChromeOS() override; |
| |
| static void RegisterPrefs(PrefRegistrySimple* registry); |
| static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); |
| |
| // Returns the user_id of the current logged in user. If no user is logged in, |
| // returns absl::nullopt. If a user has logged in and has opted-out, will |
| // return absl::nullopt. |
| // |
| // If the user has opted-into metrics collection and is not ephemeral, then |
| // this will return the pseudo-anonymous identifier associated with the user. |
| absl::optional<std::string> GetCurrentUserId() const; |
| |
| // Returns the consent of the current logged in user only if current user's |
| // consent should be applied to metrics reporting. |
| // |
| // The cases in which this occurs are: |
| // |
| // 1) Regular non-owner users on non-managed devices. |
| // 2) Guest users on non-owned devices. |
| // |
| // If no user is logged in, returns absl::nullopt. True means that the user |
| // has opted-into metrics collection during the session and False means that |
| // the user has opted-out. |
| // |
| // Note: Use this function over GetUserConsentIfApplicable() to retrieve user |
| // metrics reporting status. |
| absl::optional<bool> GetCurrentUserReportingConsentIfApplicable() const; |
| |
| // Sets the metric consent for the current logged in user. If no user is |
| // logged in, no-ops. |
| // |
| // This method will reset the client id if a user toggles from a non-consent |
| // to consent state AND the user had consented to metrics collection in the |
| // past. This is to preserve the pseudo-anonymity of <user_id, client_id> |
| // identifier. |
| // |
| // This call should be used to toggle consent from the UI or during OOBE flow |
| // for the current user. |
| void SetCurrentUserMetricsConsent(bool metrics_consent); |
| |
| // Returns true if a user log store in the user cryptohome should be used for |
| // the current logged in user. |
| // |
| // Certain users (ie ephemeral sessions with metrics consent on) should not |
| // use a user log store since the user log store will be stored on the |
| // temporary cryptohome and will be deleted at the end of the session. |
| // Ephemeral sessions with metric consent on should be stored in local state |
| // to be persistent. |
| bool ShouldUseUserLogStore() const; |
| |
| // Returns true if |user| should have the ability to toggle user metrics |
| // collection for themselves. |
| // |
| // This will return false for managed device users as well as guest users. |
| bool IsUserAllowedToChangeConsent(user_manager::User* user) const; |
| |
| // Adds an observer |callback| to be called when a user consent should be |
| // applied. This happens either when an applicable user logs in or an |
| // applicable user changes metrics consent. |
| base::CallbackListSubscription AddObserver( |
| const MetricsConsentHandler& callback); |
| |
| // Sets behavior of IsReportingPolicyManaged() for testing. |
| // |
| // TODO(crbug/1269950): Investigate why ash::LoginManagerTest does not work |
| // with ash::ScopedStubInstallAttributes. Remove this function once resolved |
| // as it is hack to force PerUserStateManagerChromeOS to return a fixed value. |
| static void SetIsManagedForTesting(bool is_managed); |
| |
| protected: |
| // These methods are marked virtual to stub out for testing. |
| |
| // Sets the user log store to use |log_store|. Default uses |
| // |metrics_service_client_| implementation. |
| virtual void SetUserLogStore(std::unique_ptr<UnsentLogStore> log_store); |
| |
| // Unsets the user log store. Default uses |metrics_service_client_| |
| // implementation. |
| virtual void UnsetUserLogStore(); |
| |
| // Resets the client ID. Should be called when user consent is turned off->on |
| // and the user has opted-in metrics consent in the past. Default uses |
| // |metrics_service_client_| implementation. |
| virtual void ForceClientIdReset(); |
| |
| // Returns true if the reporting policy is managed. |
| virtual bool IsReportingPolicyManaged() const; |
| |
| // Returns the device metrics consent. If ownership has not been taken, will |
| // return false. |
| virtual bool GetDeviceMetricsConsent() const; |
| |
| // Returns true if user log store has been set to be used to persist metric |
| // logs. |
| virtual bool HasUserLogStore() const; |
| |
| // Returns true if the device is owned either by a policy or a local owner. |
| // |
| // See //chrome/browser/ash/settings/device_settings_service.h for more |
| // details as to when a device is considered owned and how a device becomes |
| // owned. |
| virtual bool IsDeviceOwned() const; |
| |
| // These methods are protected to avoid dependency on DeviceSettingsService |
| // during testing. |
| |
| // Ensures that ownership status is known before proceeding with using |
| // profile prefs. |
| virtual void WaitForOwnershipStatus(); |
| |
| // Loads appropriate prefs from |current_user_| and creates new log storage |
| // using profile prefs. |
| void InitializeProfileMetricsState( |
| ash::DeviceSettingsService::OwnershipStatus status); |
| |
| private: |
| // Possible states for |this|. |
| enum class State { |
| // Right after construction. |
| CONSTRUCTED = 0, |
| |
| // ActiveUserChanged on non-trivial user. The profile for the user is not |
| // immediately created. |
| USER_LOGIN = 1, |
| |
| // User profile has been created and ready to use. |
| USER_PROFILE_READY = 2, |
| |
| // User log store has been initialized, if applicable. Per-user consent |
| // now can be changed if the user has permissions to change consent. |
| // |
| // Terminal state. |
| USER_LOG_STORE_HANDLED = 3, |
| }; |
| |
| // UserManager::UserSessionStateObserver: |
| void ActiveUserChanged(user_manager::User* active_user) override; |
| |
| // UserManager::Observer: |
| void OnUserToBeRemoved(const AccountId& account_id) override; |
| |
| // ash::SessionTerminationManager::Observer: |
| void OnSessionWillBeTerminated() override; |
| |
| // Updates the current user ID to |new_user_id|. Updates both the profile pref |
| // as well as local state pref. |
| void UpdateCurrentUserId(const std::string& new_user_id); |
| |
| // Resets the state of |this| to that of no logged in user. |
| void ResetState(); |
| |
| // Returns the prefs for the current logged in user. |
| PrefService* GetCurrentUserPrefs() const; |
| |
| // Builds a unsent log store for |current_user_| and assigns it to be used as |
| // the primary log store for ongoing logs. |
| void AssignUserLogStore(); |
| |
| // Sets the reporting state for metrics collection. Notifies observers that |
| // user metrics consent has changed to |metrics_consent|. |
| void SetReportingState(bool metrics_consent); |
| |
| // Notifies observers of the per-user state change |metrics_consent|. |
| void NotifyObservers(bool metrics_consent); |
| |
| // Updates local state prefs based on |metrics_enabled|. If |metrics_enabled| |
| // is true, |
| // |
| // 1) Client ID will be reset if the user has ever had metrics reporting |
| // enabled. This is to preserve the pseudo-anonymous identifier |
| // <client_id, user_id>. |
| void UpdateLocalStatePrefs(bool metrics_enabled); |
| |
| SEQUENCE_CHECKER(sequence_checker_); |
| |
| base::RepeatingCallbackList<void(bool)> callback_list_; |
| |
| // Raw pointer to Metrics service client that should own |this|. |
| const raw_ptr<MetricsServiceClient, ExperimentalAsh> metrics_service_client_; |
| |
| // Raw pointer to user manager. User manager is used to listen to login/logout |
| // events as well as retrieve metadata about users. |user_manager_| should |
| // outlive |this|. |
| const raw_ptr<user_manager::UserManager, ExperimentalAsh> user_manager_; |
| |
| // Raw pointer to local state prefs store. |
| const raw_ptr<PrefService, ExperimentalAsh> local_state_; |
| |
| // Logs parameters that control log storage requirements and restrictions. |
| const MetricsLogStore::StorageLimits storage_limits_; |
| |
| // Signing key to encrypt logs. |
| const std::string signing_key_; |
| |
| // Pointer to the current logged-in user. |
| raw_ptr<user_manager::User, ExperimentalAsh> current_user_ = nullptr; |
| |
| // Current state for |this|. |
| State state_ = State::CONSTRUCTED; |
| |
| // Task runner. Used to persist state to daemon-store. |
| scoped_refptr<base::SequencedTaskRunner> task_runner_ = nullptr; |
| |
| base::WeakPtrFactory<PerUserStateManagerChromeOS> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace metrics |
| |
| #endif // CHROME_BROWSER_METRICS_PER_USER_STATE_MANAGER_CHROMEOS_H_ |