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 |
| index 7ea194f1af92dd463d56a59fbc1527c99842d81f..1075e39fa3261bbab20146c94fea6886aa394b29 100644 |
| --- a/content/browser/background_sync/background_sync_manager.cc |
| +++ b/content/browser/background_sync/background_sync_manager.cc |
| @@ -46,6 +46,7 @@ scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create( |
| } |
| BackgroundSyncManager::~BackgroundSyncManager() { |
| + service_worker_context_->RemoveObserver(this); |
| } |
| void BackgroundSyncManager::Register( |
| @@ -57,6 +58,13 @@ void BackgroundSyncManager::Register( |
| DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId, |
| sync_registration.id); |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
| + return; |
| + } |
| + |
| StatusAndRegistrationCallback pending_callback = |
| base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback, |
| weak_ptr_factory_.GetWeakPtr(), callback); |
| @@ -74,6 +82,12 @@ void BackgroundSyncManager::Unregister( |
| const StatusCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE)); |
| + return; |
| + } |
| + |
| StatusCallback pending_callback = |
| base::Bind(&BackgroundSyncManager::PendingStatusCallback, |
| weak_ptr_factory_.GetWeakPtr(), callback); |
| @@ -91,6 +105,13 @@ void BackgroundSyncManager::GetRegistration( |
| const StatusAndRegistrationCallback& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
| + return; |
| + } |
| + |
| StatusAndRegistrationCallback pending_callback = |
| base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback, |
| weak_ptr_factory_.GetWeakPtr(), callback); |
| @@ -101,33 +122,81 @@ void BackgroundSyncManager::GetRegistration( |
| sync_registration_name, pending_callback)); |
| } |
| +void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id, |
| + const GURL& pattern) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + base::Closure pending_callback = |
|
jsbell
2015/04/01 21:54:54
Can you add a comment that this do-nothing callbac
jkarlin
2015/04/02 17:57:56
Nice suggestion. I made such functions for all of
michaeln
2015/04/02 23:06:20
Nice, those helpers help a lot.
|
| + base::Bind(&BackgroundSyncManager::PendingClosure, |
| + weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing)); |
| + |
| + // Operations already in the queue will either fail when they write to storage |
| + // or return stale results based on registrations loaded in memory. This is |
| + // inconsequential since the service worker is gone. |
| + op_scheduler_.ScheduleOperation(base::Bind( |
| + &BackgroundSyncManager::OnRegistrationDeletedImpl, |
| + weak_ptr_factory_.GetWeakPtr(), registration_id, pending_callback)); |
| +} |
| + |
| +void BackgroundSyncManager::OnStorageWiped() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + base::Closure pending_callback = |
| + base::Bind(&BackgroundSyncManager::PendingClosure, |
| + weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing)); |
| + |
| + // Operations already in the queue will either fail when they write to storage |
| + // or return stale results based on registrations loaded in memory. This is |
| + // inconsequential since the service workers are gone. |
| + op_scheduler_.ScheduleOperation( |
| + base::Bind(&BackgroundSyncManager::OnStorageWipedImpl, |
| + weak_ptr_factory_.GetWeakPtr(), pending_callback)); |
| +} |
| + |
| BackgroundSyncManager::BackgroundSyncManager( |
| const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) |
| - : service_worker_context_(service_worker_context), weak_ptr_factory_(this) { |
| + : service_worker_context_(service_worker_context), |
| + disabled_(false), |
| + weak_ptr_factory_(this) { |
| + service_worker_context_->AddObserver(this); |
| } |
| void BackgroundSyncManager::Init() { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| DCHECK(!op_scheduler_.ScheduledOperations()); |
| + DCHECK(!disabled_); |
| + |
| + base::Closure pending_callback = |
| + base::Bind(&BackgroundSyncManager::PendingClosure, |
| + weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing)); |
| op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl, |
| - weak_ptr_factory_.GetWeakPtr())); |
| + weak_ptr_factory_.GetWeakPtr(), |
| + pending_callback)); |
| } |
| -void BackgroundSyncManager::InitImpl() { |
| +void BackgroundSyncManager::InitImpl(const base::Closure& callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| + |
| GetDataFromBackend( |
| kBackgroundSyncUserDataKey, |
| base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend, |
| - weak_ptr_factory_.GetWeakPtr())); |
| + weak_ptr_factory_.GetWeakPtr(), callback)); |
| } |
| void BackgroundSyncManager::InitDidGetDataFromBackend( |
| + const base::Closure& callback, |
| 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."; |
| + if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) { |
| + LOG(ERROR) << "BackgroundSync failed to init due to backend failure."; |
| + DisableAndClearManager(); |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| bool corruption_detected = false; |
| for (const std::pair<int64, std::string>& data : user_data) { |
| @@ -163,12 +232,12 @@ void BackgroundSyncManager::InitDidGetDataFromBackend( |
| if (corruption_detected) { |
| LOG(ERROR) << "Corruption detected in background sync backend"; |
| - sw_to_registrations_map_.clear(); |
| + DisableAndClearManager(); |
| } |
| // TODO(jkarlin): Call the scheduling algorithm here. |
| - op_scheduler_.CompleteOperationAndRunNext(); |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| } |
| void BackgroundSyncManager::RegisterImpl( |
| @@ -176,6 +245,13 @@ void BackgroundSyncManager::RegisterImpl( |
| int64 sw_registration_id, |
| const BackgroundSyncRegistration& sync_registration, |
| const StatusAndRegistrationCallback& callback) { |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
| + return; |
| + } |
| + |
| BackgroundSyncRegistration existing_registration; |
| if (LookupRegistration(sw_registration_id, sync_registration.name, |
| &existing_registration)) { |
| @@ -198,7 +274,60 @@ void BackgroundSyncManager::RegisterImpl( |
| origin, sw_registration_id, |
| base::Bind(&BackgroundSyncManager::RegisterDidStore, |
| weak_ptr_factory_.GetWeakPtr(), sw_registration_id, |
| - new_registration, existing_registration, callback)); |
| + new_registration, callback)); |
| +} |
| + |
| +void BackgroundSyncManager::DisableAndClearManager() { |
| + disabled_ = true; |
| + base::Closure pending_callback = |
| + base::Bind(&BackgroundSyncManager::PendingClosure, |
| + weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing)); |
| + |
| + op_scheduler_.ScheduleOperation( |
| + base::Bind(&BackgroundSyncManager::DisableAndClearManagerImpl, |
| + weak_ptr_factory_.GetWeakPtr(), pending_callback)); |
| +} |
| + |
| +void BackgroundSyncManager::DisableAndClearManagerImpl( |
|
jsbell
2015/04/01 21:54:54
Out of curiosity, are there any relevant "I'm runn
jkarlin
2015/04/02 17:57:56
There is a check that an operation is currently ru
jsbell
2015/04/02 20:25:13
sgtm
|
| + const base::Closure& callback) { |
| + DCHECK(disabled_); |
|
michaeln
2015/04/01 21:37:30
Can BackgroundSyncManager::OnStorageWipedImpl happ
jkarlin
2015/04/02 17:57:56
Yes, there is a race on disabled_ if DisableAndCle
michaeln
2015/04/02 23:06:20
yup, that works!
|
| + |
| + sw_to_registrations_map_.clear(); |
| + |
| + // Delete all backend entries. The memory representation of registered syncs |
| + // may be corrupt so reload the registrations from storage again. |
|
jsbell
2015/04/01 21:54:54
Maybe clarify in the comment why memory is "corrup
jkarlin
2015/04/02 17:57:56
Done.
|
| + GetDataFromBackend( |
| + kBackgroundSyncUserDataKey, |
| + base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations, |
| + weak_ptr_factory_.GetWeakPtr(), callback)); |
| +} |
| + |
| +void BackgroundSyncManager::DisableAndClearDidGetRegistrations( |
| + const base::Closure& callback, |
| + const std::vector<std::pair<int64, std::string>>& user_data, |
| + ServiceWorkerStatusCode status) { |
| + if (status != SERVICE_WORKER_OK || user_data.empty()) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| + |
| + base::Closure barrier_closure = |
| + base::BarrierClosure(user_data.size(), base::Bind(callback)); |
| + |
| + for (const auto& sw_id_and_regs : user_data) { |
| + service_worker_context_->context()->storage()->ClearUserData( |
| + sw_id_and_regs.first, kBackgroundSyncUserDataKey, |
| + base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne, |
| + weak_ptr_factory_.GetWeakPtr(), barrier_closure)); |
| + } |
| +} |
| + |
| +void BackgroundSyncManager::DisableAndClearManagerClearedOne( |
| + const base::Closure& barrier_closure, |
| + ServiceWorkerStatusCode status) { |
| + // The status doesn't matter at this point, there is nothing else to be done. |
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(barrier_closure)); |
| } |
| bool BackgroundSyncManager::LookupRegistration( |
| @@ -255,18 +384,21 @@ void BackgroundSyncManager::StoreRegistrations( |
| void BackgroundSyncManager::RegisterDidStore( |
| int64 sw_registration_id, |
| const BackgroundSyncRegistration& new_registration, |
| - const BackgroundSyncRegistration& previous_registration, |
| const StatusAndRegistrationCallback& callback, |
| ServiceWorkerStatusCode status) { |
| + if (status == SERVICE_WORKER_ERROR_NOT_FOUND) { |
| + // The registration is gone. |
| + sw_to_registrations_map_.erase(sw_registration_id); |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
| + return; |
| + } |
| + |
| 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); |
| - } |
| + LOG(ERROR) << "BackgroundSync failed to store registration due to backend " |
| + "failure."; |
| + DisableAndClearManager(); |
| base::MessageLoop::current()->PostTask( |
| FROM_HERE, |
| base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
| @@ -334,6 +466,12 @@ void BackgroundSyncManager::UnregisterImpl( |
| const std::string& sync_registration_name, |
| BackgroundSyncRegistration::RegistrationId sync_registration_id, |
| const StatusCallback& callback) { |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE)); |
| + return; |
| + } |
| + |
| BackgroundSyncRegistration existing_registration; |
| if (!LookupRegistration(sw_registration_id, sync_registration_name, |
| &existing_registration) || |
| @@ -359,9 +497,17 @@ void BackgroundSyncManager::UnregisterDidStore( |
| const BackgroundSyncRegistration& old_sync_registration, |
| const StatusCallback& callback, |
| ServiceWorkerStatusCode status) { |
| + if (status == SERVICE_WORKER_ERROR_NOT_FOUND) { |
| + // ServiceWorker was unregistered. |
| + sw_to_registrations_map_.erase(sw_registration_id); |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE)); |
| + return; |
| + } |
| + |
| if (status != SERVICE_WORKER_OK) { |
| - // Restore the previous state. |
| - AddRegistrationToMap(sw_registration_id, old_sync_registration); |
| + LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure."; |
| + DisableAndClearManager(); |
| base::MessageLoop::current()->PostTask( |
| FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE)); |
| return; |
| @@ -377,6 +523,13 @@ void BackgroundSyncManager::GetRegistrationImpl( |
| int64 sw_registration_id, |
| const std::string sync_registration_name, |
| const StatusAndRegistrationCallback& callback) { |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
| + return; |
| + } |
| + |
| BackgroundSyncRegistration out_registration; |
| if (!LookupRegistration(sw_registration_id, sync_registration_name, |
| &out_registration)) { |
| @@ -390,6 +543,21 @@ void BackgroundSyncManager::GetRegistrationImpl( |
| FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registration)); |
| } |
| +void BackgroundSyncManager::OnRegistrationDeletedImpl( |
| + int64 registration_id, |
| + const base::Closure& callback) { |
| + // The backend (ServiceWorkerStorage) will delete the data, so just delete the |
| + // memory representation here. |
| + sw_to_registrations_map_.erase(registration_id); |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| +} |
| + |
| +void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) { |
| + sw_to_registrations_map_.clear(); |
| + disabled_ = false; |
|
michaeln
2015/04/01 21:37:30
would it make sense to schedule an op to reinit?
jkarlin
2015/04/02 17:57:56
Scheduling the op might allow some new requests to
|
| + InitImpl(callback); |
| +} |
| + |
| void BackgroundSyncManager::PendingStatusAndRegistrationCallback( |
| const StatusAndRegistrationCallback& callback, |
| ErrorType error, |
| @@ -411,4 +579,12 @@ void BackgroundSyncManager::PendingStatusCallback( |
| op_scheduler_.CompleteOperationAndRunNext(); |
| } |
| +void BackgroundSyncManager::PendingClosure(const base::Closure& callback) { |
| + // 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(); |
| + if (manager) |
| + op_scheduler_.CompleteOperationAndRunNext(); |
| +} |
| + |
| } // namespace content |