blob: 5be62a3fb27e37f3c1db6b811172f6dfebe18f61 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_CONTEXT_IMPL_H_
#define CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_CONTEXT_IMPL_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "content/browser/notifications/notification_database.h"
#include "content/browser/notifications/notification_id_generator.h"
#include "content/browser/service_worker/service_worker_context_core_observer.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/platform_notification_context.h"
#include "content/public/browser/render_process_host.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "third_party/blink/public/mojom/notifications/notification_service.mojom.h"
class GURL;
namespace base {
class SequencedTaskRunner;
}
namespace blink {
class StorageKey;
} // namespace blink
namespace content {
class BlinkNotificationServiceImpl;
class BrowserContext;
struct NotificationDatabaseData;
class PlatformNotificationServiceProxy;
class RenderProcessHost;
class ServiceWorkerContextWrapper;
class WeakDocumentPtr;
// Implementation of the Web Notification storage context. The public methods
// defined in this interface must only be called on the UI thread.
class CONTENT_EXPORT PlatformNotificationContextImpl
: public PlatformNotificationContext,
public ServiceWorkerContextCoreObserver {
public:
// Constructs a new platform notification context. If |path| is non-empty, the
// database will be initialized in the "Platform Notifications" subdirectory
// of |path|. Otherwise, the database will be initialized in memory.
PlatformNotificationContextImpl(
const base::FilePath& path,
BrowserContext* browser_context,
const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context);
PlatformNotificationContextImpl(const PlatformNotificationContextImpl&) =
delete;
PlatformNotificationContextImpl& operator=(
const PlatformNotificationContextImpl&) = delete;
// To be called to initialize the instance.
void Initialize();
// To be called when the context is being shut down.
void Shutdown();
// Creates a BlinkNotificationServiceImpl that is owned by this context.
// The `document_url` will be empty if the service is created by a worker.
// The `weak_document_ptr` points to the document if it's the creator of the
// notification service, or the worker's ancestor document if the notification
// service is created by a dedicated worker, or is `nullptr` otherwise.
void CreateService(
RenderProcessHost* render_process_host,
const blink::StorageKey& storage_key,
const GURL& document_url,
const WeakDocumentPtr& weak_document_ptr,
const RenderProcessHost::NotificationServiceCreatorType creator_type,
mojo::PendingReceiver<blink::mojom::NotificationService> receiver);
// Removes |service| from the list of owned services, for example because the
// Mojo pipe disconnected. Must be called on the UI thread.
void RemoveService(BlinkNotificationServiceImpl* service);
// Returns the notification Id generator owned by the context.
NotificationIdGenerator* notification_id_generator() {
return &notification_id_generator_;
}
// PlatformNotificationContext implementation.
void ReadNotificationDataAndRecordInteraction(
const std::string& notification_id,
const GURL& origin,
Interaction interaction,
ReadResultCallback callback) override;
void ReadNotificationResources(const std::string& notification_id,
const GURL& origin,
ReadResourcesResultCallback callback) override;
void WriteNotificationData(int64_t persistent_notification_id,
int64_t service_worker_registration_id,
const GURL& origin,
const NotificationDatabaseData& database_data,
WriteResultCallback callback) override;
void DeleteNotificationData(const std::string& notification_id,
const GURL& origin,
bool close_notification,
DeleteResultCallback callback) override;
void DeleteAllNotificationDataWithTag(
const std::string& tag,
std::optional<bool> is_shown_by_browser,
const GURL& origin,
DeleteAllResultCallback callback) override;
void DeleteAllNotificationDataForBlockedOrigins(
DeleteAllResultCallback callback) override;
void ReadAllNotificationDataForServiceWorkerRegistration(
const GURL& origin,
int64_t service_worker_registration_id,
ReadAllResultCallback callback) override;
void CountVisibleNotificationsForServiceWorkerRegistration(
const GURL& origin,
int64_t service_worker_registration_id,
CountResultCallback callback) override;
void TriggerNotifications() override;
void WriteNotificationResources(
std::vector<NotificationResourceData> resource_data,
WriteResourcesResultCallback callback) override;
void ReDisplayNotifications(
std::vector<GURL> origins,
ReDisplayNotificationsResultCallback callback) override;
void WriteNotificationMetadata(
const std::string& notification_id,
const GURL& origin,
const std::string& metadata_key,
const std::string& metadata_value,
WriteResourcesResultCallback callback) override;
// ServiceWorkerContextCoreObserver implementation.
void OnRegistrationDeleted(int64_t registration_id,
const GURL& pattern,
const blink::StorageKey& key) override;
void OnStorageWiped() override;
private:
friend class PlatformNotificationContextTest;
friend class PlatformNotificationContextTriggerTest;
~PlatformNotificationContextImpl() override;
void DidGetNotifications(std::set<std::string> displayed_notifications,
bool supports_synchronization);
using InitializeResultCallback = base::OnceCallback<void(bool)>;
using ReadAllOriginsResultCallback =
base::OnceCallback<void(bool /* success */,
std::set<GURL> /* origins */)>;
using InitializeGetDisplayedCallback = base::OnceCallback<void(
std::set<std::string> /* displayed_notifications */,
bool /* supports_synchronization */,
bool /* initialized */)>;
// Initializes the database if necessary. |callback| will be invoked on the
// |task_runner_| thread. If |lazy| is true this will not try to create a new
// database if there isn't one already. Otherwise this will try to open or
// create a new database. If everything is available, |callback| will be
// called with true, otherwise it will be called with false.
void InitializeDatabase(InitializeResultCallback callback, bool lazy = false);
// Marks this notification as shown and displays it.
void DoTriggerNotification(const NotificationDatabaseData& database_data);
// Opens the database. Must be called on the |task_runner_| thread. |callback|
// will be invoked on the |task_runner_| thread. If |create_if_missing| is
// true this will try to create a new database if there isn't one already.
// Otherwise we will just try to open it. When the database has been
// successfully opened, |callback| will be called with true, otherwise it will
// be called with false.
void OpenDatabase(InitializeResultCallback callback, bool create_if_missing);
// Actually reads the notification data from the database. Must only be
// called on the |task_runner_| thread. |callback| will be invoked on the
// UI thread when the operation has completed.
void DoReadNotificationData(const std::string& notification_id,
const GURL& origin,
Interaction interaction,
ReadResultCallback callback,
bool initialized);
// Actually reads the notification resources from the database. Must only be
// called on the |task_runner_| thread. |callback| will be invoked on the
// UI thread when the operation has completed.
void DoReadNotificationResources(const std::string& notification_id,
const GURL& origin,
ReadResourcesResultCallback callback,
bool initialized);
// Synchronize displayed notifications. This removes all non-displayed
// notifications from the database.
void DoSyncNotificationData(bool supports_synchronization,
std::set<std::string> displayed_notifications,
bool initialized);
// Checks if the given notification is still valid, otherwise deletes it from
// the database. Fills |close_notification_ids| with notification ids that
// should be closed by the platform.
void DoHandleSyncNotification(
bool supports_synchronization,
const std::set<std::string>& displayed_notifications,
std::set<std::string>* close_notification_ids,
const NotificationDatabaseData& data);
// Tries to get a list of displayed notification ids for `origin` if the
// platform supports synchronizing them. Calls `callback` with the result
// after initializing the database on the `task_runner_` thread.
void TryGetDisplayedNotifications(const GURL& origin,
InitializeGetDisplayedCallback callback);
// Called after getting a list of |displayed_notifications| on the UI thread.
// Calls |callback| after initializing the database on the |task_runner_|
// thread.
void OnGetDisplayedNotifications(
InitializeGetDisplayedCallback callback,
std::set<std::string> displayed_notifications,
bool supports_synchronization);
// Actually reads all notification data from the database. Must only be
// called on the |task_runner_| thread. |callback| will be invoked on the
// UI thread when the operation has completed.
void DoReadAllNotificationDataForServiceWorkerRegistration(
base::Time start_time,
const GURL& origin,
int64_t service_worker_registration_id,
ReadAllResultCallback callback,
std::set<std::string> displayed_notifications,
bool supports_synchronization,
bool initialized);
// Actually counts visible notifications for |service_worker_registration_id|
// by comparing the entries in the database with |displayed_notifications|.
// Must only be called on the |task_runner_| thread. |callback| will be
// invoked on the UI thread when the operation has completed.
void DoCountVisibleNotificationsForServiceWorkerRegistration(
base::Time start_time,
const GURL& origin,
int64_t service_worker_registration_id,
CountResultCallback callback,
std::set<std::string> displayed_notifications,
bool supports_synchronization,
bool initialized);
// Checks if the number of notifications scheduled for |origin| does not
// exceed the quota.
bool DoCheckNotificationTriggerQuota(const GURL& origin);
// Actually writes the notification database to the database. Must only be
// called on the |task_runner_| thread. |callback| will be invoked on the
// UI thread when the operation has completed.
void DoWriteNotificationData(int64_t persistent_notification_id,
int64_t service_worker_registration_id,
const GURL& origin,
const NotificationDatabaseData& database_data,
WriteResultCallback callback,
bool initialized);
// Actually deletes the notification information from the database. Must only
// be called on the |task_runner_| thread. |callback| will be invoked on the
// UI thread when the operation has completed.
void DoDeleteNotificationData(const std::string& notification_id,
const GURL& origin,
DeleteResultCallback callback,
bool should_log_close,
bool initialized);
// Actually reads all notification origins from the database. Must only be
// called on the |task_runner_| thread. |callback| will be invoked on the UI
// thread when the operation has completed.
void DoReadAllNotificationOrigins(ReadAllOriginsResultCallback callback,
bool initialized);
// Checks permissions for all |origins| via PermissionController and deletes
// all notifications for origins that do not have granted permissions. Must be
// called on the UI thread. |callback| will be invoked on the UI thread when
// the operation has completed.
void CheckPermissionsAndDeleteBlocked(DeleteAllResultCallback callback,
bool success,
std::set<GURL> origins);
// Actually deletes the notification information for all |origins| from the
// database. Optionally filtered by |tag|. Must only be called on the
// |task_runner_| thread. |callback| will be invoked on the UI thread when the
// operation has completed.
void DoDeleteAllNotificationDataForOrigins(
std::set<GURL> origins,
const std::string& tag,
std::optional<bool> is_shown_by_browser,
DeleteAllResultCallback callback,
bool initialized);
// Actually writes the notification resources to the database. Must only be
// called on the |task_runner_| thread. |callback| will be invoked on the UI
// thread when the operation has completed.
void DoWriteNotificationResources(
std::vector<NotificationResourceData> resource_data,
WriteResourcesResultCallback callback,
bool initialized);
// Actually reads all notification that should be on screen for |origins| from
// the database and displays them. Must only be called on the |task_runner_|
// thread. |callback| will be invoked on the UI thread with the number of
// displayed notifications when the operation has completed.
void DoReDisplayNotifications(std::vector<GURL> origins,
ReDisplayNotificationsResultCallback callback,
bool initialized);
void DoWriteNotificationMetadata(const std::string& notification_id,
const GURL& origin,
const std::string& metadata_key,
const std::string& metadata_value,
WriteResourcesResultCallback callback,
bool initialized);
void OnStorageWipedInitialized(bool initialized);
// Deletes all notifications associated with |service_worker_registration_id|
// belonging to |origin|. Must be called on the |task_runner_| thread.
void DoDeleteNotificationsForServiceWorkerRegistration(
const GURL& origin,
int64_t service_worker_registration_id,
bool initialized);
// Destroys the database regardless of its initialization status. This method
// must only be called on the |task_runner_| thread. Returns if the directory
// the database was stored in could be emptied.
bool DestroyDatabase();
// Returns the path in which the database should be initialized. May be empty.
base::FilePath GetDatabasePath() const;
// Sets the task runner to use for testing purposes.
void SetTaskRunnerForTesting(
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
void DisplayNotification(const NotificationDatabaseData& data,
WriteResultCallback callback);
void CloseNotifications(const std::set<std::string>& notification_ids);
void ScheduleTrigger(base::Time timestamp);
void ScheduleNotification(const NotificationDatabaseData& data);
void LogClose(const NotificationDatabaseData& data);
base::FilePath path_;
raw_ptr<BrowserContext> browser_context_;
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
std::unique_ptr<NotificationDatabase> database_;
NotificationIdGenerator notification_id_generator_;
// Keeps track of the next trigger timestamp.
std::optional<base::Time> next_trigger_;
// Calls through to PlatformNotificationService methods.
std::unique_ptr<PlatformNotificationServiceProxy> service_proxy_;
// The notification services are owned by the platform context, and will be
// removed when either this class is destroyed or the Mojo pipe disconnects.
std::vector<std::unique_ptr<BlinkNotificationServiceImpl>> services_;
NotificationDatabase::UkmCallback ukm_callback_;
// Flag if the |browser_context_| has been shutdown already.
std::atomic_bool has_shutdown_;
};
} // namespace content
#endif // CONTENT_BROWSER_NOTIFICATIONS_PLATFORM_NOTIFICATION_CONTEXT_IMPL_H_