// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_MANAGER_H_ #define CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_MANAGER_H_ #include <map> #include <string> #include <utility> #include <vector> #include "base/callback_forward.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "content/browser/background_sync/background_sync.pb.h" #include "content/browser/background_sync/background_sync_registration.h" #include "content/browser/background_sync/background_sync_status.h" #include "content/browser/cache_storage/cache_storage_scheduler.h" #include "content/browser/service_worker/service_worker_context_observer.h" #include "content/browser/service_worker/service_worker_storage.h" #include "content/common/content_export.h" #include "content/common/service_worker/service_worker_status_code.h" #include "url/gurl.h" namespace content { class BackgroundSyncNetworkObserver; class BackgroundSyncPowerObserver; class ServiceWorkerContextWrapper; // BackgroundSyncManager manages and stores the set of background sync // registrations across all registered service workers for a profile. // Registrations are stored along with their associated Service Worker // registration in ServiceWorkerStorage. If the ServiceWorker is unregistered, // the sync registrations are removed. This class expects to be run on the IO // thread. The asynchronous methods are executed sequentially. // TODO(jkarlin): Check permissions when registering, scheduling, and firing // background sync. In the meantime, --enable-service-worker-sync is required to // fire a sync event. // TODO(jkarlin): Unregister syncs when permission is revoked. // TODO(jkarlin): Create a background sync scheduler to actually run the // registered events. // TODO(jkarlin): Keep the browser alive if "Let Google Chrome Run in the // Background" is true and a sync is registered. class CONTENT_EXPORT BackgroundSyncManager : NON_EXPORTED_BASE(public ServiceWorkerContextObserver) { public: using StatusCallback = base::Callback<void(BackgroundSyncStatus)>; using StatusAndRegistrationCallback = base::Callback<void(BackgroundSyncStatus, const BackgroundSyncRegistration&)>; using StatusAndRegistrationsCallback = base::Callback<void(BackgroundSyncStatus, const std::vector<BackgroundSyncRegistration>&)>; static scoped_ptr<BackgroundSyncManager> Create( const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context); ~BackgroundSyncManager() override; // Stores the given background sync registration and adds it to the scheduling // queue. It will overwrite an existing registration with the same tag and // periodicity unless they're identical (save for the id). Calls |callback| // with BACKGROUND_SYNC_STATUS_OK and the accepted registration on success. // The accepted registration will have a unique id. It may also have altered // parameters if the user or UA chose different parameters than those // supplied. void Register(int64 sw_registration_id, const BackgroundSyncRegistrationOptions& options, const StatusAndRegistrationCallback& callback); // Removes the background sync with tag |sync_registration_tag|, periodicity // |periodicity|, and id |sync_registration_id|. Calls |callback| with // BACKGROUND_SYNC_STATUS_NOT_FOUND if no match is found. Calls |callback| // with BACKGROUND_SYNC_STATUS_OK on success. void Unregister( int64 sw_registration_id, const std::string& sync_registration_tag, SyncPeriodicity periodicity, BackgroundSyncRegistration::RegistrationId sync_registration_id, const StatusCallback& callback); // Finds the background sync registration associated with // |sw_registration_id| with periodicity |periodicity|. Calls // |callback| with BACKGROUND_SYNC_STATUS_NOT_FOUND if it doesn't exist. Calls // |callback| with BACKGROUND_SYNC_STATUS_OK on success. void GetRegistration(int64 sw_registration_id, const std::string& sync_registration_tag, SyncPeriodicity periodicity, const StatusAndRegistrationCallback& callback); void GetRegistrations(int64 sw_registration_id, SyncPeriodicity periodicity, const StatusAndRegistrationsCallback& callback); // ServiceWorkerContextObserver overrides. void OnRegistrationDeleted(int64 registration_id, const GURL& pattern) override; void OnStorageWiped() override; protected: explicit BackgroundSyncManager( const scoped_refptr<ServiceWorkerContextWrapper>& context); // Init must be called before any public member function. Only call it once. void Init(); // The following methods are virtual for testing. virtual void StoreDataInBackend( int64 sw_registration_id, const GURL& origin, const std::string& backend_key, const std::string& data, const ServiceWorkerStorage::StatusCallback& callback); virtual void GetDataFromBackend( const std::string& backend_key, const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback& callback); virtual void FireOneShotSync( const BackgroundSyncRegistration& registration, const scoped_refptr<ServiceWorkerVersion>& active_version, const ServiceWorkerVersion::StatusCallback& callback); private: class RegistrationKey { public: explicit RegistrationKey(const BackgroundSyncRegistration& registration); explicit RegistrationKey(const BackgroundSyncRegistrationOptions& options); RegistrationKey(const std::string& tag, SyncPeriodicity periodicity); RegistrationKey(const RegistrationKey& other) = default; RegistrationKey& operator=(const RegistrationKey& other) = default; bool operator<(const RegistrationKey& rhs) const { return value_ < rhs.value_; } private: std::string value_; }; struct BackgroundSyncRegistrations { using RegistrationMap = std::map<RegistrationKey, BackgroundSyncRegistration>; BackgroundSyncRegistrations(); ~BackgroundSyncRegistrations(); RegistrationMap registration_map; BackgroundSyncRegistration::RegistrationId next_id; GURL origin; }; using PermissionStatusCallback = base::Callback<void(bool)>; using SWIdToRegistrationsMap = std::map<int64, BackgroundSyncRegistrations>; // Disable the manager. Already queued operations will abort once they start // to run (in their impl methods). Future operations will not queue. Any // registrations are cleared from memory and the backend (if it's still // functioning). The manager will reenable itself once it receives the // OnStorageWiped message or on browser restart. void DisableAndClearManager(const base::Closure& callback); void DisableAndClearDidGetRegistrations( const base::Closure& callback, const std::vector<std::pair<int64, std::string>>& user_data, ServiceWorkerStatusCode status); void DisableAndClearManagerClearedOne(const base::Closure& barrier_closure, ServiceWorkerStatusCode status); // Returns the existing registration in |existing_registration| if it is not // null. BackgroundSyncRegistration* LookupRegistration( int64 sw_registration_id, const RegistrationKey& registration_key); // Store all registrations for a given |sw_registration_id|. void StoreRegistrations(int64 sw_registration_id, const ServiceWorkerStorage::StatusCallback& callback); // Removes the registration if it is in the map. void RemoveRegistrationFromMap(int64 sw_registration_id, const RegistrationKey& registration_key); void AddRegistrationToMap( int64 sw_registration_id, const GURL& origin, const BackgroundSyncRegistration& sync_registration); void InitImpl(const base::Closure& callback); void InitDidGetDataFromBackend( const base::Closure& callback, const std::vector<std::pair<int64, std::string>>& user_data, ServiceWorkerStatusCode status); // Register callbacks void RegisterImpl(int64 sw_registration_id, const BackgroundSyncRegistrationOptions& options, const StatusAndRegistrationCallback& callback); void RegisterDidStore(int64 sw_registration_id, const BackgroundSyncRegistration& sync_registration, const StatusAndRegistrationCallback& callback, ServiceWorkerStatusCode status); // Unregister callbacks void UnregisterImpl( int64 sw_registration_id, const RegistrationKey& registration_key, BackgroundSyncRegistration::RegistrationId sync_registration_id, SyncPeriodicity periodicity, const StatusCallback& callback); void UnregisterDidStore(int64 sw_registration_id, SyncPeriodicity periodicity, const StatusCallback& callback, ServiceWorkerStatusCode status); // GetRegistration callbacks void GetRegistrationImpl(int64 sw_registration_id, const RegistrationKey& registration_key, const StatusAndRegistrationCallback& callback); // GetRegistrations callbacks void GetRegistrationsImpl(int64 sw_registration_id, SyncPeriodicity periodicity, const StatusAndRegistrationsCallback& callback); bool AreOptionConditionsMet(const BackgroundSyncRegistrationOptions& options); bool IsRegistrationReadyToFire( const BackgroundSyncRegistration& registration); // Schedules pending registrations to run in the future. For one-shots this // means keeping the browser alive so that network connectivity events can be // seen (on Android the browser is instead woken up the next time it goes // online). For periodic syncs this means creating an alarm. void SchedulePendingRegistrations(); // FireReadyEvents and callbacks void FireReadyEvents(); void FireReadyEventsImpl(const base::Closure& callback); void FireReadyEventsDidFindRegistration( const RegistrationKey& registration_key, BackgroundSyncRegistration::RegistrationId registration_id, const base::Closure& event_fired_callback, const base::Closure& event_completed_callback, ServiceWorkerStatusCode service_worker_status, const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration); // Called when a sync event has completed. void EventComplete( const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration, int64 service_worker_id, const RegistrationKey& key, BackgroundSyncRegistration::RegistrationId sync_registration_id, const base::Closure& callback, ServiceWorkerStatusCode status_code); void EventCompleteImpl( int64 service_worker_id, const RegistrationKey& key, BackgroundSyncRegistration::RegistrationId sync_registration_id, ServiceWorkerStatusCode status_code, const base::Closure& callback); void EventCompleteDidStore(int64 service_worker_id, const base::Closure& callback, ServiceWorkerStatusCode status_code); // Called when all sync events have completed. static void OnAllSyncEventsCompleted(const base::TimeTicks& start_time, int number_of_batched_sync_events); // OnRegistrationDeleted callbacks void OnRegistrationDeletedImpl(int64 registration_id, const base::Closure& callback); // OnStorageWiped callbacks void OnStorageWipedImpl(const base::Closure& callback); void OnNetworkChanged(); void OnPowerChanged(); // Operation Scheduling callback and convenience functions. template <typename CallbackT, typename... Params> void CompleteOperationCallback(const CallbackT& callback, Params... parameters); base::Closure MakeEmptyCompletion(); base::Closure MakeClosureCompletion(const base::Closure& callback); StatusAndRegistrationCallback MakeStatusAndRegistrationCompletion( const StatusAndRegistrationCallback& callback); StatusAndRegistrationsCallback MakeStatusAndRegistrationsCompletion( const StatusAndRegistrationsCallback& callback); BackgroundSyncManager::StatusCallback MakeStatusCompletion( const StatusCallback& callback); SWIdToRegistrationsMap sw_to_registrations_map_; CacheStorageScheduler op_scheduler_; scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; bool disabled_; scoped_ptr<BackgroundSyncNetworkObserver> network_observer_; scoped_ptr<BackgroundSyncPowerObserver> power_observer_; base::WeakPtrFactory<BackgroundSyncManager> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(BackgroundSyncManager); }; } // namespace content #endif // CONTENT_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_MANAGER_H_