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 a23792f161076cfa4f7ef3f3039c9a3688408ba7..9b4f5c83fa7b0801908b3db0595d148a135f771c 100644 |
| --- a/content/browser/background_sync/background_sync_manager.cc |
| +++ b/content/browser/background_sync/background_sync_manager.cc |
| @@ -229,6 +229,12 @@ void BackgroundSyncManager::InitDidGetDataFromBackend( |
| registration->min_period = registration_proto.min_period(); |
| registration->network_state = registration_proto.network_state(); |
| registration->power_state = registration_proto.power_state(); |
| + registration->sync_state = registration_proto.sync_state(); |
| + if (registration->sync_state == SYNC_STATE_FIRING) { |
| + // If the browser (or worker) closed while firing the event, consider |
| + // it pending again> |
| + registration->sync_state = SYNC_STATE_PENDING; |
| + } |
| } |
| } |
| @@ -242,7 +248,7 @@ void BackgroundSyncManager::InitDidGetDataFromBackend( |
| return; |
| } |
| - // TODO(jkarlin): Call the scheduling algorithm here. |
| + FireReadyEvents(); |
| base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| } |
| @@ -371,6 +377,7 @@ void BackgroundSyncManager::StoreRegistrations( |
| registration_proto->set_min_period(registration.min_period); |
| registration_proto->set_network_state(registration.network_state); |
| registration_proto->set_power_state(registration.power_state); |
| + registration_proto->set_sync_state(registration.sync_state); |
| } |
| std::string serialized; |
| bool success = registrations_proto.SerializeToString(&serialized); |
| @@ -402,7 +409,7 @@ void BackgroundSyncManager::RegisterDidStore( |
| return; |
| } |
| - // TODO(jkarlin): Run the registration algorithm. |
| + FireReadyEvents(); |
| base::MessageLoop::current()->PostTask( |
| FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration)); |
| } |
| @@ -453,6 +460,14 @@ void BackgroundSyncManager::GetDataFromBackend( |
| callback); |
| } |
| +void BackgroundSyncManager::FireOneShotSync( |
| + const scoped_refptr<ServiceWorkerVersion>& active_version, |
| + const ServiceWorkerVersion::StatusCallback& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + |
| + active_version->DispatchSyncEvent(callback); |
| +} |
| + |
| void BackgroundSyncManager::UnregisterImpl( |
| const GURL& origin, |
| int64 sw_registration_id, |
| @@ -500,7 +515,6 @@ void BackgroundSyncManager::UnregisterDidStore( |
| return; |
| } |
| - // TODO(jkarlin): Run the registration algorithm. |
| base::MessageLoop::current()->PostTask(FROM_HERE, |
| base::Bind(callback, ERROR_TYPE_OK)); |
| } |
| @@ -546,8 +560,7 @@ void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) { |
| } |
| void BackgroundSyncManager::OnNetworkChanged() { |
| - // TODO(jkarlin): Run the scheduling algorithm here if initialized and not |
| - // disabled. |
| + FireReadyEvents(); |
| } |
| void BackgroundSyncManager::PendingStatusAndRegistrationCallback( |
| @@ -579,6 +592,178 @@ void BackgroundSyncManager::PendingClosure(const base::Closure& callback) { |
| op_scheduler_.CompleteOperationAndRunNext(); |
| } |
| +bool BackgroundSyncManager::IsRegistrationReadyToFire( |
| + const BackgroundSyncRegistration& registration) { |
| + // TODO(jkarlin): Add support for firing periodic registrations. |
| + if (registration.periodicity == SYNC_PERIODIC) |
| + return false; |
| + |
| + if (registration.sync_state != SYNC_STATE_PENDING) |
| + return false; |
| + |
| + DCHECK_EQ(SYNC_ONE_SHOT, registration.periodicity); |
| + |
| + return network_observer_->NetworkSufficient(registration.network_state); |
| +} |
| + |
| +void BackgroundSyncManager::FireReadyEvents() { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + if (disabled_) |
| + return; |
| + |
| + op_scheduler_.ScheduleOperation( |
| + base::Bind(&BackgroundSyncManager::FireReadyEventsImpl, |
| + weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion())); |
| +} |
| + |
| +void BackgroundSyncManager::FireReadyEventsImpl(const base::Closure& callback) { |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| + |
| + // Find the registrations that are ready to run. |
| + std::vector<std::pair<int64, RegistrationKey>> sw_id_and_keys_to_fire; |
| + |
| + for (auto& sw_id_and_registrations : sw_to_registrations_map_) { |
| + const int64 service_worker_id = sw_id_and_registrations.first; |
| + for (auto& key_and_registration : |
| + sw_id_and_registrations.second.registration_map) { |
| + BackgroundSyncRegistration* registration = &key_and_registration.second; |
| + if (IsRegistrationReadyToFire(*registration)) { |
| + sw_id_and_keys_to_fire.push_back( |
| + std::make_pair(service_worker_id, key_and_registration.first)); |
| + // The state change is not saved to persistent storage because |
| + // if the sync event is killed mid-sync then it should return to |
| + // SYNC_STATE_PENDING. |
| + registration->sync_state = SYNC_STATE_FIRING; |
| + } |
| + } |
| + } |
| + |
| + // Fire the sync event of the ready registrations and run |callback| once |
| + // they're all done. |
| + base::Closure barrier_closure = |
| + base::BarrierClosure(sw_id_and_keys_to_fire.size(), base::Bind(callback)); |
| + |
| + for (const auto& sw_id_and_key : sw_id_and_keys_to_fire) { |
| + int64 service_worker_id = sw_id_and_key.first; |
| + const BackgroundSyncRegistration* registration = |
| + LookupRegistration(service_worker_id, sw_id_and_key.second); |
| + |
| + service_worker_context_->FindRegistrationForId( |
| + service_worker_id, sw_to_registrations_map_[service_worker_id].origin, |
| + base::Bind(&BackgroundSyncManager::FireReadyEventsDidFindRegistration, |
| + weak_ptr_factory_.GetWeakPtr(), sw_id_and_key.second, |
| + registration->id, barrier_closure)); |
| + } |
| +} |
| + |
| +void BackgroundSyncManager::FireReadyEventsDidFindRegistration( |
| + const RegistrationKey& registration_key, |
| + BackgroundSyncRegistration::RegistrationId registration_id, |
| + const base::Closure& callback, |
| + ServiceWorkerStatusCode service_worker_status, |
| + const scoped_refptr<ServiceWorkerRegistration>& |
| + service_worker_registration) { |
| + if (service_worker_status != SERVICE_WORKER_OK) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| + |
| + ServiceWorkerVersion* active_version = |
| + service_worker_registration->active_version(); |
| + if (!active_version) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
|
iclelland
2015/04/28 02:48:53
Will this happen if the service worker is still ac
jkarlin
2015/04/28 14:41:00
Ah, good point. I'll check for active registration
jkarlin
2015/04/28 16:39:22
Followup CL is here: https://crrev.com/1110993003
|
| + return; |
| + } |
| + |
| + FireOneShotSync(active_version, |
| + base::Bind(&BackgroundSyncManager::EventComplete, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + service_worker_registration->id(), |
| + registration_key, registration_id)); |
| + |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| +} |
| + |
| +void BackgroundSyncManager::EventComplete( |
| + int64 service_worker_id, |
| + const RegistrationKey& key, |
| + BackgroundSyncRegistration::RegistrationId sync_registration_id, |
| + ServiceWorkerStatusCode status_code) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + |
| + if (disabled_) |
| + return; |
| + |
| + op_scheduler_.ScheduleOperation( |
| + base::Bind(&BackgroundSyncManager::EventCompleteImpl, |
| + weak_ptr_factory_.GetWeakPtr(), service_worker_id, key, |
| + sync_registration_id, status_code, MakeEmptyCompletion())); |
| +} |
| + |
| +void BackgroundSyncManager::EventCompleteImpl( |
|
iclelland
2015/04/28 02:48:53
It looks like there are situations here where the
jkarlin
2015/04/28 14:41:00
Are you referring to the early returns below? In a
iclelland
2015/04/28 18:50:39
Yes, those ones. So if I'm following the code corr
jkarlin
2015/04/28 21:00:08
We should be good. If it's disabled_ then all memo
|
| + int64 service_worker_id, |
| + const RegistrationKey& key, |
| + BackgroundSyncRegistration::RegistrationId sync_registration_id, |
| + ServiceWorkerStatusCode status_code, |
| + const base::Closure& callback) { |
| + DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| + |
| + if (disabled_) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| + |
| + BackgroundSyncRegistration* registration = |
| + LookupRegistration(service_worker_id, key); |
| + if (!registration || registration->id != sync_registration_id) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| + |
| + if (registration->periodicity == SYNC_ONE_SHOT) { |
| + if (status_code != SERVICE_WORKER_OK) { |
| + // TODO(jkarlin) Fire the sync event on the next page load controlled by |
| + // this registration. (crbug.com/479665) |
| + registration->sync_state = SYNC_STATE_FAILED; |
| + } else { |
| + registration = nullptr; |
| + RemoveRegistrationFromMap(service_worker_id, key); |
| + } |
| + } else { |
| + // TODO(jkarlin): Add support for running periodic syncs. (crbug.com/479674) |
| + NOTREACHED(); |
| + } |
| + |
| + StoreRegistrations( |
| + service_worker_id, |
| + base::Bind(&BackgroundSyncManager::EventCompleteDidStore, |
| + weak_ptr_factory_.GetWeakPtr(), service_worker_id, callback)); |
| +} |
| + |
| +void BackgroundSyncManager::EventCompleteDidStore( |
| + int64 service_worker_id, |
| + const base::Closure& callback, |
| + ServiceWorkerStatusCode status_code) { |
| + if (status_code == SERVICE_WORKER_ERROR_NOT_FOUND) { |
| + // The registration is gone. |
| + sw_to_registrations_map_.erase(service_worker_id); |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| + return; |
| + } |
| + |
| + if (status_code != SERVICE_WORKER_OK) { |
| + LOG(ERROR) << "BackgroundSync failed to store registration due to backend " |
| + "failure."; |
| + DisableAndClearManager(base::Bind(callback)); |
| + return; |
| + } |
| + |
| + base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback)); |
| +} |
| + |
| base::Closure BackgroundSyncManager::MakeEmptyCompletion() { |
| return base::Bind(&BackgroundSyncManager::PendingClosure, |
| weak_ptr_factory_.GetWeakPtr(), |