blob: 6d76c48c2459fe488c61cee04379423fab95fdae [file] [log] [blame]
// Copyright 2023 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_UI_SAFETY_HUB_SAFETY_HUB_SERVICE_H_
#define CHROME_BROWSER_UI_SAFETY_HUB_SAFETY_HUB_SERVICE_H_
#include <memory>
#include "base/gtest_prod_util.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "components/keyed_service/core/keyed_service.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
constexpr char kSafetyHubTimestampResultKey[] = "timestamp";
// Base class for Safety Hub services. The background and UI tasks of the
// derived classes will be executed periodically, according to the time delta
// interval returned by GetRepeatedUpdateInterval().
class SafetyHubService : public KeyedService,
public base::SupportsWeakPtr<SafetyHubService> {
public:
// Base class for results returned after the periodic execution of the Safety
// Hub service. Each service should implement a derived class that captures
// the specific information that is retrieved. Any intermediate data that is
// required for the background task, or that needs to passed through to the UI
// thread task should be included as well.
class Result {
public:
Result(const Result&) = default;
Result& operator=(const Result&) = delete;
virtual ~Result() = default;
virtual base::Value::Dict ToDictValue() = 0;
// Determines whether the current result meets the bar for showing a
// notification to the user in the Chrome menu.
virtual bool IsTriggerForMenuNotification() = 0;
// Determines whether the previous result is sufficiently different that for
// the current result a new notification should be shown. This indication is
// just based on the comparison of the two results, and thus irrelevant to
// how frequently a menu notification has already been shown.
virtual bool WarrantsNewMenuNotification(const Result& previousResult) = 0;
template <typename T>
static std::unique_ptr<T> FromDictValue(const base::Value::Dict& dict) {
return std::make_unique<T>(dict);
}
base::Time timestamp() const;
protected:
explicit Result(base::Time timestamp = base::Time::Now());
explicit Result(const base::Value::Dict& dict);
base::Value::Dict BaseToDictValue();
private:
base::Time timestamp_;
};
class Observer : public base::CheckedObserver {
public:
// Called when the result from the update of the service is available.
virtual void OnResultAvailable(const Result* result) = 0;
};
SafetyHubService();
SafetyHubService(const SafetyHubService&) = delete;
SafetyHubService& operator=(const SafetyHubService&) = delete;
~SafetyHubService() override;
// Makes an asynchronous call to the background task, which will be followed
// by the UI task.
void UpdateAsync();
// Adds an observer to be notified when a new result is available.
void AddObserver(Observer* observer);
// Removes an observer from the observer list.
void RemoveObserver(Observer* observer);
// Indicates whether the update process is currently running.
bool IsUpdateRunning();
// Returns the latest result that is available in memory.
absl::optional<SafetyHubService::Result*> GetCachedResult();
// KeyedService implementation.
void Shutdown() override;
protected:
// Triggers the repeated update task that updates the state of the Safety Hub
// service.
void StartRepeatedUpdates();
// SafetyHubService overrides.
// Initializes the latest result such that it is available in memory.
virtual void InitializeLatestResult() = 0;
// The value returned by this function determines the interval of how often
// the Update function will be called.
virtual base::TimeDelta GetRepeatedUpdateInterval() = 0;
// Should return the background task that will be executed, containing the
// computation-heavy part of the update process. This task should be static
// and not be bound to the service, as it will be executed on a separate
// background thread. As such, only thread-safe parameters should be bound.
// The returned Result will be passed along to the UpdateOnUIThread function.
virtual base::OnceCallback<std::unique_ptr<Result>()> GetBackgroundTask() = 0;
// This function contains the part of the update task that will be executed
// synchronously on the UI thread. Hence, it should not be computation-heavy
// to avoid freezing the browser. It will be passed the intermediate result
// that was produced by the background task. The result returned by this UI
// task will be the final result that will be sent to the observers.
virtual std::unique_ptr<Result> UpdateOnUIThread(
std::unique_ptr<Result> result) = 0;
virtual base::WeakPtr<SafetyHubService> GetAsWeakRef() = 0;
// The latest available result, which is initialized at the start.
std::unique_ptr<Result> latest_result_ = nullptr;
private:
FRIEND_TEST_ALL_PREFIXES(SafetyHubServiceTest, ManageObservers);
FRIEND_TEST_ALL_PREFIXES(SafetyHubServiceTest, UpdateOnBackgroundThread);
// Called as soon as the update has been finished.
void OnUpdateFinished(std::unique_ptr<Result> result);
// Notifies each of the added observers that a new result is available.
void NotifyObservers(Result* result);
// Posts the background task on a background thread.
void UpdateAsyncInternal();
// Repeating timer that runs the recurring tasks.
base::RepeatingTimer update_timer_;
// List of observers that have to be notified when a new result is available.
base::ObserverList<Observer> observers_;
// Indicator of how many requested updates are still pending.
int pending_updates_ = 0;
};
#endif // CHROME_BROWSER_UI_SAFETY_HUB_SAFETY_HUB_SERVICE_H_