| // Copyright 2019 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_CHILD_ACCOUNTS_TIME_LIMITS_APP_ACTIVITY_REGISTRY_H_ |
| #define CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_ACTIVITY_REGISTRY_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <optional> |
| #include <set> |
| #include <vector> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/observer_list_types.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "chrome/browser/ash/child_accounts/time_limits/app_activity_report_interface.h" |
| #include "chrome/browser/ash/child_accounts/time_limits/app_service_wrapper.h" |
| #include "chrome/browser/ash/child_accounts/time_limits/app_types.h" |
| |
| namespace base { |
| class UnguessableToken; |
| } // namespace base |
| |
| namespace enterprise_management { |
| class ChildStatusReportRequest; |
| } // namespace enterprise_management |
| |
| class PrefRegistrySimple; |
| class PrefService; |
| |
| namespace ash { |
| namespace app_time { |
| |
| class AppTimeLimitsAllowlistPolicyWrapper; |
| class AppTimeNotificationDelegate; |
| class PersistedAppInfo; |
| |
| // Keeps track of app activity and time limits information. |
| // Stores app activity between user session. Information about uninstalled apps |
| // are removed from the registry after activity was uploaded to server or after |
| // 30 days if upload did not happen. |
| class AppActivityRegistry : public AppServiceWrapper::EventListener { |
| public: |
| // Used for tests to get internal implementation details. |
| class TestApi { |
| public: |
| explicit TestApi(AppActivityRegistry* registry); |
| ~TestApi(); |
| |
| const std::optional<AppLimit>& GetAppLimit(const AppId& app_id) const; |
| std::optional<base::TimeDelta> GetTimeLeft(const AppId& app_id) const; |
| void SaveAppActivity(); |
| |
| private: |
| const raw_ptr<AppActivityRegistry, DanglingUntriaged> registry_; |
| }; |
| |
| // Interface for the observers interested in the changes of apps state. |
| class AppStateObserver : public base::CheckedObserver { |
| public: |
| AppStateObserver() = default; |
| AppStateObserver(const AppStateObserver&) = delete; |
| AppStateObserver& operator=(const AppStateObserver&) = delete; |
| ~AppStateObserver() override = default; |
| |
| // Called when state of the app with |app_id| changed to |kLimitReached|. |
| // |was_active| indicates whether the app was active before reaching the |
| // limit. |
| virtual void OnAppLimitReached(const AppId& app_id, |
| base::TimeDelta time_limit, |
| bool was_active) = 0; |
| |
| // Called when state of the app with |app_id| is no longer |kLimitReached|. |
| virtual void OnAppLimitRemoved(const AppId& app_id) = 0; |
| |
| // Called when new app was installed. |
| virtual void OnAppInstalled(const AppId& app_id) = 0; |
| }; |
| |
| static void RegisterProfilePrefs(PrefRegistrySimple* registry); |
| |
| AppActivityRegistry(AppServiceWrapper* app_service_wrapper, |
| AppTimeNotificationDelegate* notification_delegate, |
| PrefService* pref_service); |
| AppActivityRegistry(const AppActivityRegistry&) = delete; |
| AppActivityRegistry& operator=(const AppActivityRegistry&) = delete; |
| ~AppActivityRegistry() override; |
| |
| // AppServiceWrapper::EventListener: |
| void OnAppInstalled(const AppId& app_id) override; |
| void OnAppUninstalled(const AppId& app_id) override; |
| void OnAppAvailable(const AppId& app_id) override; |
| void OnAppBlocked(const AppId& app_id) override; |
| void OnAppActive(const AppId& app_id, |
| const base::UnguessableToken& instance_id, |
| base::Time timestamp) override; |
| void OnAppInactive(const AppId& app_id, |
| const base::UnguessableToken& instance_id, |
| base::Time timestamp) override; |
| void OnAppDestroyed(const AppId& app_id, |
| const base::UnguessableToken& instance_id, |
| base::Time timestamp) override; |
| |
| bool IsAppInstalled(const AppId& app_id) const; |
| bool IsAppAvailable(const AppId& app_id) const; |
| bool IsAppBlocked(const AppId& app_id) const; |
| bool IsAppTimeLimitReached(const AppId& app_id) const; |
| bool IsAppActive(const AppId& app_id) const; |
| bool IsAllowlistedApp(const AppId& app_id) const; |
| |
| // Manages AppStateObservers. |
| void AddAppStateObserver(AppStateObserver* observer); |
| void RemoveAppStateObserver(AppStateObserver* observer); |
| |
| // Called from AppTimeController to notify AppActivityRegistry about installed |
| // apps which AppActivityRegistry may have missed. |
| void SetInstalledApps(const std::vector<AppId>& installed_apps); |
| |
| // Returns the total active time for the application since the last time limit |
| // reset. |
| base::TimeDelta GetActiveTime(const AppId& app_id) const; |
| |
| // Web time limit is the time limit set for Chrome browser. It is shared |
| // between Chrome and Web apps. |
| const std::optional<AppLimit>& GetWebTimeLimit() const; |
| |
| AppState GetAppState(const AppId& app_id) const; |
| |
| // Returns current time limit for the app identified by |app_id|. |
| // Will return nullopt if there is no limit set. |
| std::optional<base::TimeDelta> GetTimeLimit(const AppId& app_id) const; |
| |
| // Reporting enablement is set if |enabled| has value. |
| void SetReportingEnabled(std::optional<bool> enabled); |
| |
| void GenerateHiddenApps( |
| enterprise_management::ChildStatusReportRequest* report); |
| |
| // Populates |report| with collected app activity. Returns whether any data |
| // were reported. |
| AppActivityReportInterface::ReportParams GenerateAppActivityReport( |
| enterprise_management::ChildStatusReportRequest* report); |
| |
| // Application activities earlier than |timestamp| have been reported. Clear |
| // entries earlier than |timestamp|. |
| void OnSuccessfullyReported(base::Time timestamp); |
| |
| // Updates time limits for all installed apps. |
| // Apps not present in |app_limits| are treated as they do not have limit set. |
| // Returns true if a new app limit is observed in any of the applications. |
| bool UpdateAppLimits(const std::map<AppId, AppLimit>& app_limits); |
| |
| // Sets time limit for app identified with |app_id|. |
| // Does not affect limits of any other app. Not specified |app_limit| means |
| // that app does not have limit set. Does not affect limits of any other app. |
| // Returns true if a new app limit is observed. |
| bool SetAppLimit(const AppId& app_id, |
| const std::optional<AppLimit>& app_limit); |
| |
| // Sets the app identified with |app_id| as being always available. |
| void SetAppAllowlisted(const AppId& app_id); |
| |
| // Reset time has been reached at |timestamp|. |
| void OnResetTimeReached(base::Time timestamp); |
| |
| // Called from WebTimeActivityProvider to update chrome app state. |
| void OnChromeAppActivityChanged(ChromeAppActivityState state, |
| base::Time timestamp); |
| |
| // Allowlisted applications changed. Called by AppTimeController. |
| void OnTimeLimitAllowlistChanged( |
| const AppTimeLimitsAllowlistPolicyWrapper& wrapper); |
| |
| // Saves app activity into user preference. |
| void SaveAppActivity(); |
| |
| std::vector<AppId> GetAppsWithAppRestriction( |
| AppRestriction restriction) const; |
| |
| private: |
| struct SystemNotification { |
| SystemNotification(std::optional<base::TimeDelta> app_time_limit, |
| AppNotification app_notification); |
| SystemNotification(const SystemNotification&); |
| SystemNotification& operator=(const SystemNotification&); |
| std::optional<base::TimeDelta> time_limit = std::nullopt; |
| AppNotification notification = AppNotification::kUnknown; |
| }; |
| |
| // Bundles detailed data stored for a specific app. |
| struct AppDetails { |
| AppDetails(); |
| explicit AppDetails(const AppActivity& activity); |
| AppDetails(const AppDetails&) = delete; |
| AppDetails& operator=(const AppDetails&) = delete; |
| ~AppDetails(); |
| |
| // Resets the time limit check timer. |
| void ResetTimeCheck(); |
| |
| // Checks |limit| and |activity| to determine if the limit was reached. |
| bool IsLimitReached() const; |
| |
| // Checks if |limit| is equal to |another_limit| with exception for the |
| // timestamp (that does not indicate that limit changed). |
| bool IsLimitEqual(const std::optional<AppLimit>& another_limit) const; |
| |
| // Contains information about current app state and logged activity. |
| AppActivity activity{AppState::kAvailable}; |
| |
| // Contains the set of active instances for the application. |
| std::set<base::UnguessableToken> active_instances; |
| |
| // The set of instances AppActivityRegistry has requested to be paused, but |
| // which have not been paused yet. |
| std::set<base::UnguessableToken> paused_instances; |
| |
| // Contains information about restriction set for the app. |
| std::optional<AppLimit> limit; |
| |
| // Timer set up for when the app time limit is expected to be reached and |
| // preceding notifications. |
| std::unique_ptr<base::OneShotTimer> app_limit_timer; |
| |
| // Boolean to specify if OnAppInstalled call has been received for this |
| // particular application. |
| bool received_app_installed_ = false; |
| |
| // At the beginning of a session, we may want to send system notifications |
| // for applications. This may happen if there is an update in |
| // PerAppTimeLimits policy while the user was logged out. In these |
| // scenarios, we have to wait until the application is installed. |
| std::vector<SystemNotification> pending_notifications_; |
| }; |
| |
| // OnAppReinstalled is called when an application has been uninstalled and |
| // then installed again before being removed from app registry. |
| void OnAppReinstalled(const AppId& app_id); |
| |
| // Removes data older than |timestamp| from the registry. |
| // Removes entries for uninstalled apps if there is no more relevant activity |
| // data left. |
| void CleanRegistry(base::Time timestamp); |
| |
| // Adds an ap to the registry if it does not exist. |
| void Add(const AppId& app_id); |
| |
| // Convenience methods to access state of the app identified by |app_id|. |
| // Should only be called if app exists in the registry. |
| void SetAppState(const AppId& app_id, AppState app_state); |
| |
| // Notifies state observers the application identified by |app_id| has reached |
| // its set time limit. |
| void NotifyLimitReached(const AppId& app_id, bool was_active); |
| |
| // Methods to set the application as active and inactive respectively. |
| void SetAppActive(const AppId& app_id, base::Time timestamp); |
| void SetAppInactive(const AppId& app_id, base::Time timestamp); |
| |
| std::optional<base::TimeDelta> GetTimeLeftForApp(const AppId& app_id) const; |
| |
| // Schedules a time limit check for application when it becomes active. |
| void ScheduleTimeLimitCheckForApp(const AppId& app_id); |
| |
| // Checks the limit and shows notification if needed. |
| void CheckTimeLimitForApp(const AppId& app_id); |
| |
| // Shows notification about time limit updates for the app if there were |
| // relevant changes between |old_limit| and |new_limit|. Returns true if a |
| // notification has been made. |
| bool ShowLimitUpdatedNotificationIfNeeded( |
| const AppId& app_id, |
| const std::optional<AppLimit>& old_limit, |
| const std::optional<AppLimit>& new_limit); |
| |
| base::TimeDelta GetWebActiveRunningTime() const; |
| |
| void WebTimeLimitReached(base::Time timestamp); |
| |
| // Initializes |activity_registry_| from the stored values in user pref. |
| // Installed applications, their AppStates and their running active times will |
| // be restored. |
| void InitializeRegistryFromPref(); |
| void InitializeAppActivities(); |
| |
| // Updates |AppActivity::active_times_| to include the current activity up to |
| // |timestamp| then creates the most up to date instance of PersistedAppInfo. |
| PersistedAppInfo GetPersistedAppInfoForApp(const AppId& app_id, |
| base::Time timestamp); |
| |
| // Returns true if the last successfully reported time is earlier than 30 days |
| // from base::Time::Now(); |
| bool ShouldCleanUpStoredPref(); |
| |
| // Sends system notification for the application. |
| void SendSystemNotificationsForApp(const AppId& app_id); |
| |
| // Shows notification or queues it to be shown later. |
| void MaybeShowSystemNotification(const AppId& app_id, |
| const SystemNotification& notification); |
| |
| // Called by AppActivityRegistry::SetAppLimit after the application's limit |
| // has been updated. |
| void AppLimitUpdated(const AppId& app_id); |
| |
| const raw_ptr<PrefService> pref_service_; |
| |
| // Owned by AppTimeController. |
| const raw_ptr<AppServiceWrapper> app_service_wrapper_; |
| |
| // Notification delegate. |
| const raw_ptr<AppTimeNotificationDelegate> notification_delegate_; |
| |
| // Observers to be notified about app state changes. |
| base::ObserverList<AppStateObserver> app_state_observers_; |
| |
| std::map<AppId, AppDetails> activity_registry_; |
| |
| // Newly installed applications which have not yet been added to the user |
| // pref. |
| std::vector<AppId> newly_installed_apps_; |
| |
| // Repeating timer to trigger saving app activity to pref service. |
| base::RepeatingTimer save_data_to_pref_service_; |
| |
| // This records the timestamp of the latest set app limit. |
| base::Time latest_app_limit_update_; |
| |
| // Boolean to capture if app activity data reporting is enabled. |
| bool activity_reporting_enabled_ = true; |
| }; |
| |
| } // namespace app_time |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_CHILD_ACCOUNTS_TIME_LIMITS_APP_ACTIVITY_REGISTRY_H_ |