| Index: content/browser/background_sync/background_sync_manager.cc
|
| diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7ea194f1af92dd463d56a59fbc1527c99842d81f
|
| --- /dev/null
|
| +++ b/content/browser/background_sync/background_sync_manager.cc
|
| @@ -0,0 +1,414 @@
|
| +// 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.
|
| +
|
| +#include "content/browser/background_sync/background_sync_manager.h"
|
| +
|
| +#include "base/barrier_closure.h"
|
| +#include "base/bind.h"
|
| +#include "content/browser/background_sync/background_sync.pb.h"
|
| +#include "content/browser/service_worker/service_worker_context_wrapper.h"
|
| +#include "content/browser/service_worker/service_worker_storage.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +
|
| +namespace {
|
| +const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
|
| +}
|
| +
|
| +namespace content {
|
| +
|
| +const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
|
| + BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId =
|
| + -1;
|
| +
|
| +const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
|
| + BackgroundSyncManager::BackgroundSyncRegistrations::kInitialId = 0;
|
| +
|
| +BackgroundSyncManager::BackgroundSyncRegistrations::
|
| + BackgroundSyncRegistrations()
|
| + : next_id(kInitialId) {
|
| +}
|
| +BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations(
|
| + BackgroundSyncRegistration::RegistrationId next_id)
|
| + : next_id(next_id) {
|
| +}
|
| +BackgroundSyncManager::BackgroundSyncRegistrations::
|
| + ~BackgroundSyncRegistrations() {
|
| +}
|
| +
|
| +// static
|
| +scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
|
| + const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
|
| + BackgroundSyncManager* sync_manager =
|
| + new BackgroundSyncManager(service_worker_context);
|
| + sync_manager->Init();
|
| + return make_scoped_ptr(sync_manager);
|
| +}
|
| +
|
| +BackgroundSyncManager::~BackgroundSyncManager() {
|
| +}
|
| +
|
| +void BackgroundSyncManager::Register(
|
| + const GURL& origin,
|
| + int64 sw_registration_id,
|
| + const BackgroundSyncRegistration& sync_registration,
|
| + const StatusAndRegistrationCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId,
|
| + sync_registration.id);
|
| +
|
| + StatusAndRegistrationCallback pending_callback =
|
| + base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback,
|
| + weak_ptr_factory_.GetWeakPtr(), callback);
|
| +
|
| + op_scheduler_.ScheduleOperation(base::Bind(
|
| + &BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(),
|
| + origin, sw_registration_id, sync_registration, pending_callback));
|
| +}
|
| +
|
| +void BackgroundSyncManager::Unregister(
|
| + const GURL& origin,
|
| + int64 sw_registration_id,
|
| + const std::string& sync_registration_name,
|
| + BackgroundSyncRegistration::RegistrationId sync_registration_id,
|
| + const StatusCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + StatusCallback pending_callback =
|
| + base::Bind(&BackgroundSyncManager::PendingStatusCallback,
|
| + weak_ptr_factory_.GetWeakPtr(), callback);
|
| +
|
| + op_scheduler_.ScheduleOperation(base::Bind(
|
| + &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(),
|
| + origin, sw_registration_id, sync_registration_name, sync_registration_id,
|
| + pending_callback));
|
| +}
|
| +
|
| +void BackgroundSyncManager::GetRegistration(
|
| + const GURL& origin,
|
| + int64 sw_registration_id,
|
| + const std::string sync_registration_name,
|
| + const StatusAndRegistrationCallback& callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + StatusAndRegistrationCallback pending_callback =
|
| + base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback,
|
| + weak_ptr_factory_.GetWeakPtr(), callback);
|
| +
|
| + op_scheduler_.ScheduleOperation(
|
| + base::Bind(&BackgroundSyncManager::GetRegistrationImpl,
|
| + weak_ptr_factory_.GetWeakPtr(), origin, sw_registration_id,
|
| + sync_registration_name, pending_callback));
|
| +}
|
| +
|
| +BackgroundSyncManager::BackgroundSyncManager(
|
| + const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
|
| + : service_worker_context_(service_worker_context), weak_ptr_factory_(this) {
|
| +}
|
| +
|
| +void BackgroundSyncManager::Init() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| + DCHECK(!op_scheduler_.ScheduledOperations());
|
| +
|
| + op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void BackgroundSyncManager::InitImpl() {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + GetDataFromBackend(
|
| + kBackgroundSyncUserDataKey,
|
| + base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend,
|
| + weak_ptr_factory_.GetWeakPtr()));
|
| +}
|
| +
|
| +void BackgroundSyncManager::InitDidGetDataFromBackend(
|
| + const std::vector<std::pair<int64, std::string>>& user_data,
|
| + ServiceWorkerStatusCode status) {
|
| + if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND)
|
| + LOG(ERROR) << "Background Sync Failed to load from backend.";
|
| +
|
| + bool corruption_detected = false;
|
| + for (const std::pair<int64, std::string>& data : user_data) {
|
| + BackgroundSyncRegistrationsProto registrations_proto;
|
| + if (registrations_proto.ParseFromString(data.second)) {
|
| + sw_to_registrations_map_[data.first] = BackgroundSyncRegistrations(
|
| + registrations_proto.next_registration_id());
|
| + BackgroundSyncRegistrations* registrations =
|
| + &sw_to_registrations_map_[data.first];
|
| +
|
| + for (int i = 0, max = registrations_proto.registration_size(); i < max;
|
| + ++i) {
|
| + const BackgroundSyncRegistrationProto& registration_proto =
|
| + registrations_proto.registration(i);
|
| +
|
| + if (registration_proto.id() >= registrations->next_id) {
|
| + corruption_detected = true;
|
| + break;
|
| + }
|
| +
|
| + BackgroundSyncRegistration registration(registration_proto.id(),
|
| + registration_proto.name());
|
| + if (registration_proto.has_min_period())
|
| + registration.min_period = registration_proto.min_period();
|
| + registrations->name_to_registration_map[registration_proto.name()] =
|
| + registration;
|
| + }
|
| + }
|
| +
|
| + if (corruption_detected)
|
| + break;
|
| + }
|
| +
|
| + if (corruption_detected) {
|
| + LOG(ERROR) << "Corruption detected in background sync backend";
|
| + sw_to_registrations_map_.clear();
|
| + }
|
| +
|
| + // TODO(jkarlin): Call the scheduling algorithm here.
|
| +
|
| + op_scheduler_.CompleteOperationAndRunNext();
|
| +}
|
| +
|
| +void BackgroundSyncManager::RegisterImpl(
|
| + const GURL& origin,
|
| + int64 sw_registration_id,
|
| + const BackgroundSyncRegistration& sync_registration,
|
| + const StatusAndRegistrationCallback& callback) {
|
| + BackgroundSyncRegistration existing_registration;
|
| + if (LookupRegistration(sw_registration_id, sync_registration.name,
|
| + &existing_registration)) {
|
| + if (existing_registration.Equals(sync_registration)) {
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(callback, ERROR_TYPE_OK, existing_registration));
|
| + return;
|
| + }
|
| + }
|
| +
|
| + BackgroundSyncRegistration new_registration = sync_registration;
|
| + BackgroundSyncRegistrations* registrations =
|
| + &sw_to_registrations_map_[sw_registration_id];
|
| + new_registration.id = registrations->next_id++;
|
| +
|
| + AddRegistrationToMap(sw_registration_id, new_registration);
|
| +
|
| + StoreRegistrations(
|
| + origin, sw_registration_id,
|
| + base::Bind(&BackgroundSyncManager::RegisterDidStore,
|
| + weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
|
| + new_registration, existing_registration, callback));
|
| +}
|
| +
|
| +bool BackgroundSyncManager::LookupRegistration(
|
| + int64 sw_registration_id,
|
| + const std::string& sync_registration_name,
|
| + BackgroundSyncRegistration* existing_registration) {
|
| + SWIdToRegistrationsMap::iterator it =
|
| + sw_to_registrations_map_.find(sw_registration_id);
|
| + if (it == sw_to_registrations_map_.end())
|
| + return false;
|
| +
|
| + const BackgroundSyncRegistrations& registrations = it->second;
|
| + const auto name_and_registration_iter =
|
| + registrations.name_to_registration_map.find(sync_registration_name);
|
| + if (name_and_registration_iter ==
|
| + registrations.name_to_registration_map.end())
|
| + return false;
|
| +
|
| + if (existing_registration)
|
| + *existing_registration = name_and_registration_iter->second;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void BackgroundSyncManager::StoreRegistrations(
|
| + const GURL& origin,
|
| + int64 sw_registration_id,
|
| + const ServiceWorkerStorage::StatusCallback& callback) {
|
| + // Serialize the data.
|
| + const BackgroundSyncRegistrations& registrations =
|
| + sw_to_registrations_map_[sw_registration_id];
|
| + BackgroundSyncRegistrationsProto registrations_proto;
|
| + registrations_proto.set_next_registration_id(registrations.next_id);
|
| +
|
| + for (const auto& name_and_registration :
|
| + registrations.name_to_registration_map) {
|
| + const BackgroundSyncRegistration& registration =
|
| + name_and_registration.second;
|
| + BackgroundSyncRegistrationProto* registration_proto =
|
| + registrations_proto.add_registration();
|
| + registration_proto->set_id(registration.id);
|
| + registration_proto->set_name(registration.name);
|
| + if (registration.min_period != 0)
|
| + registration_proto->set_min_period(registration.min_period);
|
| + }
|
| + std::string serialized;
|
| + bool success = registrations_proto.SerializeToString(&serialized);
|
| + DCHECK(success);
|
| +
|
| + StoreDataInBackend(sw_registration_id, origin, kBackgroundSyncUserDataKey,
|
| + serialized, callback);
|
| +}
|
| +
|
| +void BackgroundSyncManager::RegisterDidStore(
|
| + int64 sw_registration_id,
|
| + const BackgroundSyncRegistration& new_registration,
|
| + const BackgroundSyncRegistration& previous_registration,
|
| + const StatusAndRegistrationCallback& callback,
|
| + ServiceWorkerStatusCode status) {
|
| + if (status != SERVICE_WORKER_OK) {
|
| + // Restore the previous state.
|
| + if (previous_registration.id !=
|
| + BackgroundSyncRegistration::kInvalidRegistrationId) {
|
| + AddRegistrationToMap(sw_registration_id, previous_registration);
|
| + } else {
|
| + RemoveRegistrationFromMap(sw_registration_id, new_registration.name,
|
| + nullptr);
|
| + }
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
|
| + return;
|
| + }
|
| +
|
| + // TODO(jkarlin): Run the registration algorithm.
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration));
|
| +}
|
| +
|
| +void BackgroundSyncManager::RemoveRegistrationFromMap(
|
| + int64 sw_registration_id,
|
| + const std::string& sync_registration_name,
|
| + BackgroundSyncRegistration* old_registration) {
|
| + DCHECK(
|
| + LookupRegistration(sw_registration_id, sync_registration_name, nullptr));
|
| +
|
| + BackgroundSyncRegistrations* registrations =
|
| + &sw_to_registrations_map_[sw_registration_id];
|
| +
|
| + const auto name_and_registration_iter =
|
| + registrations->name_to_registration_map.find(sync_registration_name);
|
| + if (old_registration)
|
| + *old_registration = name_and_registration_iter->second;
|
| +
|
| + registrations->name_to_registration_map.erase(name_and_registration_iter);
|
| +}
|
| +
|
| +void BackgroundSyncManager::AddRegistrationToMap(
|
| + int64 sw_registration_id,
|
| + const BackgroundSyncRegistration& sync_registration) {
|
| + DCHECK_NE(BackgroundSyncRegistration::kInvalidRegistrationId,
|
| + sw_registration_id);
|
| +
|
| + BackgroundSyncRegistrations* registrations =
|
| + &sw_to_registrations_map_[sw_registration_id];
|
| + registrations->name_to_registration_map[sync_registration.name] =
|
| + sync_registration;
|
| +}
|
| +
|
| +void BackgroundSyncManager::StoreDataInBackend(
|
| + int64 sw_registration_id,
|
| + const GURL& origin,
|
| + const std::string& key,
|
| + const std::string& data,
|
| + const ServiceWorkerStorage::StatusCallback& callback) {
|
| + service_worker_context_->context()->storage()->StoreUserData(
|
| + sw_registration_id, origin, key, data, callback);
|
| +}
|
| +
|
| +void BackgroundSyncManager::GetDataFromBackend(
|
| + const std::string& key,
|
| + const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
|
| + callback) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + service_worker_context_->context()->storage()->GetUserDataForAllRegistrations(
|
| + key, callback);
|
| +}
|
| +
|
| +void BackgroundSyncManager::UnregisterImpl(
|
| + const GURL& origin,
|
| + int64 sw_registration_id,
|
| + const std::string& sync_registration_name,
|
| + BackgroundSyncRegistration::RegistrationId sync_registration_id,
|
| + const StatusCallback& callback) {
|
| + BackgroundSyncRegistration existing_registration;
|
| + if (!LookupRegistration(sw_registration_id, sync_registration_name,
|
| + &existing_registration) ||
|
| + existing_registration.id != sync_registration_id) {
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND));
|
| + return;
|
| + }
|
| +
|
| + BackgroundSyncRegistration old_sync_registration;
|
| + RemoveRegistrationFromMap(sw_registration_id, sync_registration_name,
|
| + &old_sync_registration);
|
| +
|
| + StoreRegistrations(
|
| + origin, sw_registration_id,
|
| + base::Bind(&BackgroundSyncManager::UnregisterDidStore,
|
| + weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
|
| + old_sync_registration, callback));
|
| +}
|
| +
|
| +void BackgroundSyncManager::UnregisterDidStore(
|
| + int64 sw_registration_id,
|
| + const BackgroundSyncRegistration& old_sync_registration,
|
| + const StatusCallback& callback,
|
| + ServiceWorkerStatusCode status) {
|
| + if (status != SERVICE_WORKER_OK) {
|
| + // Restore the previous state.
|
| + AddRegistrationToMap(sw_registration_id, old_sync_registration);
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
|
| + return;
|
| + }
|
| +
|
| + // TODO(jkarlin): Run the registration algorithm.
|
| + base::MessageLoop::current()->PostTask(FROM_HERE,
|
| + base::Bind(callback, ERROR_TYPE_OK));
|
| +}
|
| +
|
| +void BackgroundSyncManager::GetRegistrationImpl(
|
| + const GURL& origin,
|
| + int64 sw_registration_id,
|
| + const std::string sync_registration_name,
|
| + const StatusAndRegistrationCallback& callback) {
|
| + BackgroundSyncRegistration out_registration;
|
| + if (!LookupRegistration(sw_registration_id, sync_registration_name,
|
| + &out_registration)) {
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND,
|
| + BackgroundSyncRegistration()));
|
| + return;
|
| + }
|
| +
|
| + base::MessageLoop::current()->PostTask(
|
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registration));
|
| +}
|
| +
|
| +void BackgroundSyncManager::PendingStatusAndRegistrationCallback(
|
| + const StatusAndRegistrationCallback& callback,
|
| + ErrorType error,
|
| + const BackgroundSyncRegistration& sync_registration) {
|
| + // The callback might delete this object, so hang onto a weak ptr to find out.
|
| + base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr();
|
| + callback.Run(error, sync_registration);
|
| + if (manager)
|
| + op_scheduler_.CompleteOperationAndRunNext();
|
| +}
|
| +
|
| +void BackgroundSyncManager::PendingStatusCallback(
|
| + const StatusCallback& callback,
|
| + ErrorType error) {
|
| + // The callback might delete this object, so hang onto a weak ptr to find out.
|
| + base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr();
|
| + callback.Run(error);
|
| + if (manager)
|
| + op_scheduler_.CompleteOperationAndRunNext();
|
| +}
|
| +
|
| +} // namespace content
|
|
|