Chromium Code Reviews| 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..715493523a512f2050068e2e7490a0a1bd64183c |
| --- /dev/null |
| +++ b/content/browser/background_sync/background_sync_manager.cc |
| @@ -0,0 +1,394 @@ |
| +// 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 { |
| + |
| +BackgroundSyncManager::BackgroundSyncRegistrations:: |
| + BackgroundSyncRegistrations() |
| + : id_counter(kInitialCounterId) { |
| +} |
| +BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations( |
| + BackgroundSyncRegistration::RegistrationId id_counter) |
| + : id_counter(id_counter) { |
| +} |
| +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(sync_registration.id == |
|
davidben
2015/03/25 16:01:09
Nit: DCHECK -> DCHECK_EQ
jkarlin
2015/03/25 19:24:18
Done.
|
| + BackgroundSyncRegistration::kInvalidRegistrationId); |
| + |
| + 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) { |
| + 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.registration_id_counter()); |
| + 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); |
| + BackgroundSyncRegistration registration(registration_proto.id(), |
| + registration_proto.name()); |
|
davidben
2015/03/25 16:01:09
Optional: since this data comes from disk, is it w
jkarlin
2015/03/25 19:24:18
Done.
|
| + if (registration_proto.has_min_period()) |
| + registration.min_period = registration_proto.min_period(); |
| + registrations->name_to_registration_map[registration_proto.name()] = |
| + registration; |
| + } |
| + } |
| + } |
| + |
| + // 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 (HasRegistration(sw_registration_id, sync_registration.name, |
| + &existing_registration)) { |
| + if (existing_registration.Equals(sync_registration)) { |
|
davidben
2015/03/25 16:01:10
This check gives an interesting interaction with U
jkarlin
2015/03/25 19:24:18
Interesting. The race potential is there, sync fun
davidben
2015/03/25 19:42:03
Sounds good.
|
| + 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->id_counter++; |
| + |
| + 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::HasRegistration( |
| + 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 BackgroundSyncRegistrations::NameToRegistrationMap::const_iterator |
|
davidben
2015/03/25 16:01:09
Nit/optional: This type name is probably a prime c
jkarlin
2015/03/25 19:24:18
Done.
|
| + reg_iter = |
| + registrations.name_to_registration_map.find(sync_registration_name); |
| + if (reg_iter == registrations.name_to_registration_map.end()) |
| + return false; |
| + |
| + if (existing_registration) |
| + *existing_registration = reg_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_registration_id_counter(registrations.id_counter); |
| + |
| + 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& sync_registration, |
|
davidben
2015/03/25 16:01:09
Nit: new_registration, to match the rename in the
jkarlin
2015/03/25 19:24:18
Done.
|
| + 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, sync_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, sync_registration)); |
| +} |
| + |
| +void BackgroundSyncManager::RemoveRegistrationFromMap( |
| + int64 sw_registration_id, |
| + const std::string& sync_registration_name, |
| + BackgroundSyncRegistration* old_registration) { |
|
davidben
2015/03/25 16:01:09
This never writes the old entry to old_registratio
jkarlin
2015/03/25 19:24:18
!!!!
Done.
|
| + DCHECK(HasRegistration(sw_registration_id, sync_registration_name, nullptr)); |
| + |
| + BackgroundSyncRegistrations* registrations = |
| + &sw_to_registrations_map_[sw_registration_id]; |
| + registrations->name_to_registration_map.erase(sync_registration_name); |
| +} |
| + |
| +void BackgroundSyncManager::AddRegistrationToMap( |
| + int64 sw_registration_id, |
| + const BackgroundSyncRegistration& sync_registration) { |
| + DCHECK(sw_registration_id != |
|
davidben
2015/03/25 16:01:09
Nit: DCHECK_NE
jkarlin
2015/03/25 19:24:18
Done.
|
| + BackgroundSyncRegistration::kInvalidRegistrationId); |
| + |
| + 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 (!HasRegistration(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) { |
|
davidben
2015/03/25 16:01:09
I think this function can just call HasRegistratio
jkarlin
2015/03/25 19:24:18
Done.
|
| + SWIdToRegistrationsMap::const_iterator it = |
| + sw_to_registrations_map_.find(sw_registration_id); |
| + |
| + if (it == sw_to_registrations_map_.end()) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND, |
| + BackgroundSyncRegistration())); |
| + return; |
| + } |
| + |
| + const BackgroundSyncRegistrations& registrations = it->second; |
| + const BackgroundSyncRegistrations::NameToRegistrationMap::const_iterator |
|
davidben
2015/03/25 16:01:10
Optional/nit: ditto about maybe using auto here.
jkarlin
2015/03/25 19:24:18
no longer needed
|
| + reg_iter = |
| + registrations.name_to_registration_map.find(sync_registration_name); |
| + if (reg_iter == registrations.name_to_registration_map.end()) { |
| + 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, reg_iter->second)); |
| +} |
| + |
| +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 |