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(), |