content: Remove use of MessageLoopProxy and deprecated MessageLoop APIs
[chromium-blink-merge.git] / content / browser / background_sync / background_sync_manager.cc
blobb82103d59b7ce4ef04d1f6c511c8c77ee890bf0c
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/background_sync/background_sync_manager.h"
7 #include "base/barrier_closure.h"
8 #include "base/bind.h"
9 #include "base/location.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "content/browser/background_sync/background_sync_network_observer.h"
13 #include "content/browser/background_sync/background_sync_power_observer.h"
14 #include "content/browser/service_worker/service_worker_context_wrapper.h"
15 #include "content/browser/service_worker/service_worker_storage.h"
16 #include "content/public/browser/browser_thread.h"
18 #if defined(OS_ANDROID)
19 #include "content/browser/android/background_sync_launcher_android.h"
20 #endif
22 namespace {
23 const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
26 namespace content {
28 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
29 BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId =
30 -1;
32 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
33 BackgroundSyncManager::BackgroundSyncRegistration::kInitialId = 0;
35 BackgroundSyncManager::BackgroundSyncRegistrations::
36 BackgroundSyncRegistrations()
37 : next_id(BackgroundSyncRegistration::kInitialId) {
40 BackgroundSyncManager::BackgroundSyncRegistrations::
41 ~BackgroundSyncRegistrations() {
44 // static
45 scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
46 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
47 DCHECK_CURRENTLY_ON(BrowserThread::IO);
49 BackgroundSyncManager* sync_manager =
50 new BackgroundSyncManager(service_worker_context);
51 sync_manager->Init();
52 return make_scoped_ptr(sync_manager);
55 BackgroundSyncManager::~BackgroundSyncManager() {
56 DCHECK_CURRENTLY_ON(BrowserThread::IO);
58 service_worker_context_->RemoveObserver(this);
61 BackgroundSyncManager::RegistrationKey::RegistrationKey(
62 const BackgroundSyncRegistration& registration)
63 : RegistrationKey(registration.tag, registration.periodicity) {
66 BackgroundSyncManager::RegistrationKey::RegistrationKey(
67 const std::string& tag,
68 SyncPeriodicity periodicity)
69 : value_(periodicity == SYNC_ONE_SHOT ? "o_" + tag : "p_" + tag) {
72 void BackgroundSyncManager::Register(
73 int64 sw_registration_id,
74 const BackgroundSyncRegistration& sync_registration,
75 const StatusAndRegistrationCallback& callback) {
76 DCHECK_CURRENTLY_ON(BrowserThread::IO);
77 DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId,
78 sync_registration.id);
80 if (disabled_) {
81 base::ThreadTaskRunnerHandle::Get()->PostTask(
82 FROM_HERE,
83 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
84 return;
87 op_scheduler_.ScheduleOperation(base::Bind(
88 &BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(),
89 sw_registration_id, sync_registration,
90 MakeStatusAndRegistrationCompletion(callback)));
93 void BackgroundSyncManager::Unregister(
94 int64 sw_registration_id,
95 const std::string& sync_registration_tag,
96 SyncPeriodicity periodicity,
97 BackgroundSyncRegistration::RegistrationId sync_registration_id,
98 const StatusCallback& callback) {
99 DCHECK_CURRENTLY_ON(BrowserThread::IO);
101 if (disabled_) {
102 base::ThreadTaskRunnerHandle::Get()->PostTask(
103 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
104 return;
107 RegistrationKey registration_key(sync_registration_tag, periodicity);
109 op_scheduler_.ScheduleOperation(base::Bind(
110 &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(),
111 sw_registration_id, registration_key, sync_registration_id,
112 MakeStatusCompletion(callback)));
115 void BackgroundSyncManager::GetRegistration(
116 int64 sw_registration_id,
117 const std::string& sync_registration_tag,
118 SyncPeriodicity periodicity,
119 const StatusAndRegistrationCallback& callback) {
120 DCHECK_CURRENTLY_ON(BrowserThread::IO);
122 if (disabled_) {
123 base::ThreadTaskRunnerHandle::Get()->PostTask(
124 FROM_HERE,
125 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
126 return;
129 RegistrationKey registration_key(sync_registration_tag, periodicity);
131 op_scheduler_.ScheduleOperation(base::Bind(
132 &BackgroundSyncManager::GetRegistrationImpl,
133 weak_ptr_factory_.GetWeakPtr(), sw_registration_id, registration_key,
134 MakeStatusAndRegistrationCompletion(callback)));
137 void BackgroundSyncManager::GetRegistrations(
138 int64 sw_registration_id,
139 SyncPeriodicity periodicity,
140 const StatusAndRegistrationsCallback& callback) {
141 DCHECK_CURRENTLY_ON(BrowserThread::IO);
143 if (disabled_) {
144 base::ThreadTaskRunnerHandle::Get()->PostTask(
145 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE,
146 std::vector<BackgroundSyncRegistration>()));
147 return;
150 op_scheduler_.ScheduleOperation(
151 base::Bind(&BackgroundSyncManager::GetRegistrationsImpl,
152 weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
153 periodicity, MakeStatusAndRegistrationsCompletion(callback)));
156 void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id,
157 const GURL& pattern) {
158 DCHECK_CURRENTLY_ON(BrowserThread::IO);
160 // Operations already in the queue will either fail when they write to storage
161 // or return stale results based on registrations loaded in memory. This is
162 // inconsequential since the service worker is gone.
163 op_scheduler_.ScheduleOperation(base::Bind(
164 &BackgroundSyncManager::OnRegistrationDeletedImpl,
165 weak_ptr_factory_.GetWeakPtr(), registration_id, MakeEmptyCompletion()));
168 void BackgroundSyncManager::OnStorageWiped() {
169 DCHECK_CURRENTLY_ON(BrowserThread::IO);
171 // Operations already in the queue will either fail when they write to storage
172 // or return stale results based on registrations loaded in memory. This is
173 // inconsequential since the service workers are gone.
174 op_scheduler_.ScheduleOperation(
175 base::Bind(&BackgroundSyncManager::OnStorageWipedImpl,
176 weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
179 BackgroundSyncManager::BackgroundSyncManager(
180 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
181 : service_worker_context_(service_worker_context),
182 disabled_(false),
183 weak_ptr_factory_(this) {
184 DCHECK_CURRENTLY_ON(BrowserThread::IO);
186 service_worker_context_->AddObserver(this);
188 network_observer_.reset(new BackgroundSyncNetworkObserver(
189 base::Bind(&BackgroundSyncManager::OnNetworkChanged,
190 weak_ptr_factory_.GetWeakPtr())));
191 power_observer_.reset(new BackgroundSyncPowerObserver(base::Bind(
192 &BackgroundSyncManager::OnPowerChanged, weak_ptr_factory_.GetWeakPtr())));
195 void BackgroundSyncManager::Init() {
196 DCHECK_CURRENTLY_ON(BrowserThread::IO);
197 DCHECK(!op_scheduler_.ScheduledOperations());
198 DCHECK(!disabled_);
200 op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl,
201 weak_ptr_factory_.GetWeakPtr(),
202 MakeEmptyCompletion()));
205 void BackgroundSyncManager::InitImpl(const base::Closure& callback) {
206 DCHECK_CURRENTLY_ON(BrowserThread::IO);
208 if (disabled_) {
209 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
210 base::Bind(callback));
211 return;
214 GetDataFromBackend(
215 kBackgroundSyncUserDataKey,
216 base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend,
217 weak_ptr_factory_.GetWeakPtr(), callback));
220 void BackgroundSyncManager::InitDidGetDataFromBackend(
221 const base::Closure& callback,
222 const std::vector<std::pair<int64, std::string>>& user_data,
223 ServiceWorkerStatusCode status) {
224 DCHECK_CURRENTLY_ON(BrowserThread::IO);
226 if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
227 LOG(ERROR) << "BackgroundSync failed to init due to backend failure.";
228 DisableAndClearManager(base::Bind(callback));
229 return;
232 bool corruption_detected = false;
233 for (const std::pair<int64, std::string>& data : user_data) {
234 BackgroundSyncRegistrationsProto registrations_proto;
235 if (registrations_proto.ParseFromString(data.second)) {
236 BackgroundSyncRegistrations* registrations =
237 &sw_to_registrations_map_[data.first];
238 registrations->next_id = registrations_proto.next_registration_id();
239 registrations->origin = GURL(registrations_proto.origin());
241 for (int i = 0, max = registrations_proto.registration_size(); i < max;
242 ++i) {
243 const BackgroundSyncRegistrationProto& registration_proto =
244 registrations_proto.registration(i);
246 if (registration_proto.id() >= registrations->next_id) {
247 corruption_detected = true;
248 break;
251 RegistrationKey registration_key(registration_proto.tag(),
252 registration_proto.periodicity());
253 BackgroundSyncRegistration* registration =
254 &registrations->registration_map[registration_key];
256 registration->id = registration_proto.id();
257 registration->tag = registration_proto.tag();
258 registration->periodicity = registration_proto.periodicity();
259 registration->min_period = registration_proto.min_period();
260 registration->network_state = registration_proto.network_state();
261 registration->power_state = registration_proto.power_state();
262 registration->sync_state = registration_proto.sync_state();
263 if (registration->sync_state == SYNC_STATE_FIRING) {
264 // If the browser (or worker) closed while firing the event, consider
265 // it pending again>
266 registration->sync_state = SYNC_STATE_PENDING;
271 if (corruption_detected)
272 break;
275 if (corruption_detected) {
276 LOG(ERROR) << "Corruption detected in background sync backend";
277 DisableAndClearManager(base::Bind(callback));
278 return;
281 FireReadyEvents();
283 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
284 base::Bind(callback));
287 void BackgroundSyncManager::RegisterImpl(
288 int64 sw_registration_id,
289 const BackgroundSyncRegistration& sync_registration,
290 const StatusAndRegistrationCallback& callback) {
291 DCHECK_CURRENTLY_ON(BrowserThread::IO);
293 if (disabled_) {
294 base::ThreadTaskRunnerHandle::Get()->PostTask(
295 FROM_HERE,
296 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
297 return;
300 const BackgroundSyncRegistration* existing_registration = LookupRegistration(
301 sw_registration_id, RegistrationKey(sync_registration));
302 if (existing_registration &&
303 existing_registration->Equals(sync_registration)) {
304 base::ThreadTaskRunnerHandle::Get()->PostTask(
305 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *existing_registration));
306 return;
309 BackgroundSyncRegistration new_registration = sync_registration;
310 BackgroundSyncRegistrations* registrations =
311 &sw_to_registrations_map_[sw_registration_id];
312 new_registration.id = registrations->next_id++;
314 ServiceWorkerRegistration* sw_registration =
315 service_worker_context_->GetLiveRegistration(sw_registration_id);
316 if (!sw_registration || !sw_registration->active_version()) {
317 base::ThreadTaskRunnerHandle::Get()->PostTask(
318 FROM_HERE, base::Bind(callback, ERROR_TYPE_NO_SERVICE_WORKER,
319 BackgroundSyncRegistration()));
320 return;
323 AddRegistrationToMap(sw_registration_id,
324 sw_registration->pattern().GetOrigin(),
325 new_registration);
327 StoreRegistrations(
328 sw_registration_id,
329 base::Bind(&BackgroundSyncManager::RegisterDidStore,
330 weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
331 new_registration, callback));
334 void BackgroundSyncManager::DisableAndClearManager(
335 const base::Closure& callback) {
336 DCHECK_CURRENTLY_ON(BrowserThread::IO);
338 if (disabled_) {
339 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
340 base::Bind(callback));
341 return;
344 disabled_ = true;
345 sw_to_registrations_map_.clear();
347 // Delete all backend entries. The memory representation of registered syncs
348 // may be out of sync with storage (e.g., due to corruption detection on
349 // loading from storage), so reload the registrations from storage again.
350 GetDataFromBackend(
351 kBackgroundSyncUserDataKey,
352 base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations,
353 weak_ptr_factory_.GetWeakPtr(), callback));
356 void BackgroundSyncManager::DisableAndClearDidGetRegistrations(
357 const base::Closure& callback,
358 const std::vector<std::pair<int64, std::string>>& user_data,
359 ServiceWorkerStatusCode status) {
360 DCHECK_CURRENTLY_ON(BrowserThread::IO);
362 if (status != SERVICE_WORKER_OK || user_data.empty()) {
363 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
364 base::Bind(callback));
365 return;
368 base::Closure barrier_closure =
369 base::BarrierClosure(user_data.size(), base::Bind(callback));
371 for (const auto& sw_id_and_regs : user_data) {
372 service_worker_context_->ClearRegistrationUserData(
373 sw_id_and_regs.first, kBackgroundSyncUserDataKey,
374 base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne,
375 weak_ptr_factory_.GetWeakPtr(), barrier_closure));
379 void BackgroundSyncManager::DisableAndClearManagerClearedOne(
380 const base::Closure& barrier_closure,
381 ServiceWorkerStatusCode status) {
382 DCHECK_CURRENTLY_ON(BrowserThread::IO);
384 // The status doesn't matter at this point, there is nothing else to be done.
385 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
386 base::Bind(barrier_closure));
389 BackgroundSyncManager::BackgroundSyncRegistration*
390 BackgroundSyncManager::LookupRegistration(
391 int64 sw_registration_id,
392 const RegistrationKey& registration_key) {
393 DCHECK_CURRENTLY_ON(BrowserThread::IO);
395 SWIdToRegistrationsMap::iterator it =
396 sw_to_registrations_map_.find(sw_registration_id);
397 if (it == sw_to_registrations_map_.end())
398 return nullptr;
400 BackgroundSyncRegistrations& registrations = it->second;
401 DCHECK_LE(BackgroundSyncRegistration::kInitialId, registrations.next_id);
402 DCHECK(!registrations.origin.is_empty());
404 auto key_and_registration_iter =
405 registrations.registration_map.find(registration_key);
406 if (key_and_registration_iter == registrations.registration_map.end())
407 return nullptr;
409 return &key_and_registration_iter->second;
412 void BackgroundSyncManager::StoreRegistrations(
413 int64 sw_registration_id,
414 const ServiceWorkerStorage::StatusCallback& callback) {
415 DCHECK_CURRENTLY_ON(BrowserThread::IO);
417 // Serialize the data.
418 const BackgroundSyncRegistrations& registrations =
419 sw_to_registrations_map_[sw_registration_id];
420 BackgroundSyncRegistrationsProto registrations_proto;
421 registrations_proto.set_next_registration_id(registrations.next_id);
422 registrations_proto.set_origin(registrations.origin.spec());
424 for (const auto& key_and_registration : registrations.registration_map) {
425 const BackgroundSyncRegistration& registration =
426 key_and_registration.second;
427 BackgroundSyncRegistrationProto* registration_proto =
428 registrations_proto.add_registration();
429 registration_proto->set_id(registration.id);
430 registration_proto->set_tag(registration.tag);
431 registration_proto->set_periodicity(registration.periodicity);
432 registration_proto->set_min_period(registration.min_period);
433 registration_proto->set_network_state(registration.network_state);
434 registration_proto->set_power_state(registration.power_state);
435 registration_proto->set_sync_state(registration.sync_state);
437 std::string serialized;
438 bool success = registrations_proto.SerializeToString(&serialized);
439 DCHECK(success);
441 StoreDataInBackend(sw_registration_id, registrations.origin,
442 kBackgroundSyncUserDataKey, serialized, callback);
445 void BackgroundSyncManager::RegisterDidStore(
446 int64 sw_registration_id,
447 const BackgroundSyncRegistration& new_registration,
448 const StatusAndRegistrationCallback& callback,
449 ServiceWorkerStatusCode status) {
450 DCHECK_CURRENTLY_ON(BrowserThread::IO);
452 if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
453 // The registration is gone.
454 sw_to_registrations_map_.erase(sw_registration_id);
455 base::ThreadTaskRunnerHandle::Get()->PostTask(
456 FROM_HERE,
457 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
458 return;
461 if (status != SERVICE_WORKER_OK) {
462 LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
463 "failure.";
464 DisableAndClearManager(
465 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
466 return;
469 FireReadyEvents();
470 base::ThreadTaskRunnerHandle::Get()->PostTask(
471 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration));
474 void BackgroundSyncManager::RemoveRegistrationFromMap(
475 int64 sw_registration_id,
476 const RegistrationKey& registration_key) {
477 DCHECK_CURRENTLY_ON(BrowserThread::IO);
478 DCHECK(LookupRegistration(sw_registration_id, registration_key));
480 BackgroundSyncRegistrations* registrations =
481 &sw_to_registrations_map_[sw_registration_id];
483 registrations->registration_map.erase(registration_key);
486 void BackgroundSyncManager::AddRegistrationToMap(
487 int64 sw_registration_id,
488 const GURL& origin,
489 const BackgroundSyncRegistration& sync_registration) {
490 DCHECK_CURRENTLY_ON(BrowserThread::IO);
491 DCHECK_NE(BackgroundSyncRegistration::kInvalidRegistrationId,
492 sw_registration_id);
494 BackgroundSyncRegistrations* registrations =
495 &sw_to_registrations_map_[sw_registration_id];
496 registrations->origin = origin;
498 RegistrationKey registration_key(sync_registration);
499 registrations->registration_map[registration_key] = sync_registration;
502 void BackgroundSyncManager::StoreDataInBackend(
503 int64 sw_registration_id,
504 const GURL& origin,
505 const std::string& backend_key,
506 const std::string& data,
507 const ServiceWorkerStorage::StatusCallback& callback) {
508 DCHECK_CURRENTLY_ON(BrowserThread::IO);
510 service_worker_context_->StoreRegistrationUserData(
511 sw_registration_id, origin, backend_key, data, callback);
514 void BackgroundSyncManager::GetDataFromBackend(
515 const std::string& backend_key,
516 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
517 callback) {
518 DCHECK_CURRENTLY_ON(BrowserThread::IO);
520 service_worker_context_->GetUserDataForAllRegistrations(backend_key,
521 callback);
524 void BackgroundSyncManager::FireOneShotSync(
525 const scoped_refptr<ServiceWorkerVersion>& active_version,
526 const ServiceWorkerVersion::StatusCallback& callback) {
527 DCHECK_CURRENTLY_ON(BrowserThread::IO);
529 active_version->DispatchSyncEvent(callback);
532 void BackgroundSyncManager::UnregisterImpl(
533 int64 sw_registration_id,
534 const RegistrationKey& registration_key,
535 BackgroundSyncRegistration::RegistrationId sync_registration_id,
536 const StatusCallback& callback) {
537 DCHECK_CURRENTLY_ON(BrowserThread::IO);
539 if (disabled_) {
540 base::ThreadTaskRunnerHandle::Get()->PostTask(
541 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
542 return;
545 const BackgroundSyncRegistration* existing_registration =
546 LookupRegistration(sw_registration_id, registration_key);
547 if (!existing_registration ||
548 existing_registration->id != sync_registration_id) {
549 base::ThreadTaskRunnerHandle::Get()->PostTask(
550 FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND));
551 return;
554 RemoveRegistrationFromMap(sw_registration_id, registration_key);
556 StoreRegistrations(
557 sw_registration_id,
558 base::Bind(&BackgroundSyncManager::UnregisterDidStore,
559 weak_ptr_factory_.GetWeakPtr(), sw_registration_id, callback));
562 void BackgroundSyncManager::UnregisterDidStore(
563 int64 sw_registration_id,
564 const StatusCallback& callback,
565 ServiceWorkerStatusCode status) {
566 DCHECK_CURRENTLY_ON(BrowserThread::IO);
568 if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
569 // ServiceWorker was unregistered.
570 sw_to_registrations_map_.erase(sw_registration_id);
571 base::ThreadTaskRunnerHandle::Get()->PostTask(
572 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
573 return;
576 if (status != SERVICE_WORKER_OK) {
577 LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure.";
578 DisableAndClearManager(base::Bind(callback, ERROR_TYPE_STORAGE));
579 return;
582 base::ThreadTaskRunnerHandle::Get()->PostTask(
583 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK));
586 void BackgroundSyncManager::GetRegistrationImpl(
587 int64 sw_registration_id,
588 const RegistrationKey& registration_key,
589 const StatusAndRegistrationCallback& callback) {
590 DCHECK_CURRENTLY_ON(BrowserThread::IO);
592 if (disabled_) {
593 base::ThreadTaskRunnerHandle::Get()->PostTask(
594 FROM_HERE,
595 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
596 return;
599 const BackgroundSyncRegistration* out_registration =
600 LookupRegistration(sw_registration_id, registration_key);
601 if (!out_registration) {
602 base::ThreadTaskRunnerHandle::Get()->PostTask(
603 FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND,
604 BackgroundSyncRegistration()));
605 return;
608 base::ThreadTaskRunnerHandle::Get()->PostTask(
609 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *out_registration));
612 void BackgroundSyncManager::GetRegistrationsImpl(
613 int64 sw_registration_id,
614 SyncPeriodicity periodicity,
615 const StatusAndRegistrationsCallback& callback) {
616 DCHECK_CURRENTLY_ON(BrowserThread::IO);
618 std::vector<BackgroundSyncRegistration> out_registrations;
620 if (disabled_) {
621 base::ThreadTaskRunnerHandle::Get()->PostTask(
622 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE, out_registrations));
623 return;
626 SWIdToRegistrationsMap::iterator it =
627 sw_to_registrations_map_.find(sw_registration_id);
629 if (it != sw_to_registrations_map_.end()) {
630 const BackgroundSyncRegistrations& registrations = it->second;
631 for (const auto& tag_and_registration : registrations.registration_map) {
632 const BackgroundSyncRegistration& registration =
633 tag_and_registration.second;
634 if (registration.periodicity == periodicity)
635 out_registrations.push_back(registration);
639 base::ThreadTaskRunnerHandle::Get()->PostTask(
640 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registrations));
643 bool BackgroundSyncManager::IsRegistrationReadyToFire(
644 const BackgroundSyncRegistration& registration) {
645 DCHECK_CURRENTLY_ON(BrowserThread::IO);
647 // TODO(jkarlin): Add support for firing periodic registrations.
648 if (registration.periodicity == SYNC_PERIODIC)
649 return false;
651 if (registration.sync_state != SYNC_STATE_PENDING)
652 return false;
654 DCHECK_EQ(SYNC_ONE_SHOT, registration.periodicity);
656 return network_observer_->NetworkSufficient(registration.network_state) &&
657 power_observer_->PowerSufficient(registration.power_state);
660 void BackgroundSyncManager::SchedulePendingRegistrations() {
661 #if defined(OS_ANDROID)
662 bool keep_browser_alive_for_one_shot = false;
664 for (const auto& sw_id_and_registrations : sw_to_registrations_map_) {
665 for (const auto& key_and_registration :
666 sw_id_and_registrations.second.registration_map) {
667 const BackgroundSyncRegistration& registration =
668 key_and_registration.second;
669 if (registration.sync_state == SYNC_STATE_PENDING) {
670 if (registration.periodicity == SYNC_ONE_SHOT) {
671 keep_browser_alive_for_one_shot = true;
672 } else {
673 // TODO(jkarlin): Support keeping the browser alive for periodic
674 // syncs.
680 // TODO(jkarlin): Use the context's path instead of the 'this' pointer as an
681 // identifier. See crbug.com/489705.
682 BrowserThread::PostTask(
683 BrowserThread::UI, FROM_HERE,
684 base::Bind(&BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnline,
685 this, keep_browser_alive_for_one_shot));
686 #else
687 // TODO(jkarlin): Toggle Chrome's background mode.
688 #endif
691 void BackgroundSyncManager::FireReadyEvents() {
692 DCHECK_CURRENTLY_ON(BrowserThread::IO);
694 if (disabled_)
695 return;
697 op_scheduler_.ScheduleOperation(
698 base::Bind(&BackgroundSyncManager::FireReadyEventsImpl,
699 weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
702 void BackgroundSyncManager::FireReadyEventsImpl(const base::Closure& callback) {
703 DCHECK_CURRENTLY_ON(BrowserThread::IO);
705 if (disabled_) {
706 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
707 base::Bind(callback));
708 return;
711 // Find the registrations that are ready to run.
712 std::vector<std::pair<int64, RegistrationKey>> sw_id_and_keys_to_fire;
714 for (auto& sw_id_and_registrations : sw_to_registrations_map_) {
715 const int64 service_worker_id = sw_id_and_registrations.first;
716 for (auto& key_and_registration :
717 sw_id_and_registrations.second.registration_map) {
718 BackgroundSyncRegistration* registration = &key_and_registration.second;
719 if (IsRegistrationReadyToFire(*registration)) {
720 sw_id_and_keys_to_fire.push_back(
721 std::make_pair(service_worker_id, key_and_registration.first));
722 // The state change is not saved to persistent storage because
723 // if the sync event is killed mid-sync then it should return to
724 // SYNC_STATE_PENDING.
725 registration->sync_state = SYNC_STATE_FIRING;
730 // Fire the sync event of the ready registrations and run |callback| once
731 // they're all done.
732 base::Closure barrier_closure =
733 base::BarrierClosure(sw_id_and_keys_to_fire.size(), base::Bind(callback));
735 for (const auto& sw_id_and_key : sw_id_and_keys_to_fire) {
736 int64 service_worker_id = sw_id_and_key.first;
737 const BackgroundSyncRegistration* registration =
738 LookupRegistration(service_worker_id, sw_id_and_key.second);
740 service_worker_context_->FindRegistrationForId(
741 service_worker_id, sw_to_registrations_map_[service_worker_id].origin,
742 base::Bind(&BackgroundSyncManager::FireReadyEventsDidFindRegistration,
743 weak_ptr_factory_.GetWeakPtr(), sw_id_and_key.second,
744 registration->id, barrier_closure));
747 SchedulePendingRegistrations();
750 void BackgroundSyncManager::FireReadyEventsDidFindRegistration(
751 const RegistrationKey& registration_key,
752 BackgroundSyncRegistration::RegistrationId registration_id,
753 const base::Closure& callback,
754 ServiceWorkerStatusCode service_worker_status,
755 const scoped_refptr<ServiceWorkerRegistration>&
756 service_worker_registration) {
757 DCHECK_CURRENTLY_ON(BrowserThread::IO);
759 if (service_worker_status != SERVICE_WORKER_OK) {
760 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
761 base::Bind(callback));
762 return;
765 FireOneShotSync(
766 service_worker_registration->active_version(),
767 base::Bind(&BackgroundSyncManager::EventComplete,
768 weak_ptr_factory_.GetWeakPtr(), service_worker_registration,
769 service_worker_registration->id(), registration_key,
770 registration_id));
772 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
773 base::Bind(callback));
776 // |service_worker_registration| is just to keep the registration alive
777 // while the event is firing.
778 void BackgroundSyncManager::EventComplete(
779 const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
780 int64 service_worker_id,
781 const RegistrationKey& key,
782 BackgroundSyncRegistration::RegistrationId sync_registration_id,
783 ServiceWorkerStatusCode status_code) {
784 DCHECK_CURRENTLY_ON(BrowserThread::IO);
786 if (disabled_)
787 return;
789 op_scheduler_.ScheduleOperation(
790 base::Bind(&BackgroundSyncManager::EventCompleteImpl,
791 weak_ptr_factory_.GetWeakPtr(), service_worker_id, key,
792 sync_registration_id, status_code, MakeEmptyCompletion()));
795 void BackgroundSyncManager::EventCompleteImpl(
796 int64 service_worker_id,
797 const RegistrationKey& key,
798 BackgroundSyncRegistration::RegistrationId sync_registration_id,
799 ServiceWorkerStatusCode status_code,
800 const base::Closure& callback) {
801 DCHECK_CURRENTLY_ON(BrowserThread::IO);
803 if (disabled_) {
804 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
805 base::Bind(callback));
806 return;
809 BackgroundSyncRegistration* registration =
810 LookupRegistration(service_worker_id, key);
811 if (!registration || registration->id != sync_registration_id) {
812 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
813 base::Bind(callback));
814 return;
817 if (registration->periodicity == SYNC_ONE_SHOT) {
818 if (status_code != SERVICE_WORKER_OK) {
819 // TODO(jkarlin) Fire the sync event on the next page load controlled by
820 // this registration. (crbug.com/479665)
821 registration->sync_state = SYNC_STATE_FAILED;
822 } else {
823 registration = nullptr;
824 RemoveRegistrationFromMap(service_worker_id, key);
826 } else {
827 // TODO(jkarlin): Add support for running periodic syncs. (crbug.com/479674)
828 NOTREACHED();
831 StoreRegistrations(
832 service_worker_id,
833 base::Bind(&BackgroundSyncManager::EventCompleteDidStore,
834 weak_ptr_factory_.GetWeakPtr(), service_worker_id, callback));
837 void BackgroundSyncManager::EventCompleteDidStore(
838 int64 service_worker_id,
839 const base::Closure& callback,
840 ServiceWorkerStatusCode status_code) {
841 DCHECK_CURRENTLY_ON(BrowserThread::IO);
843 if (status_code == SERVICE_WORKER_ERROR_NOT_FOUND) {
844 // The registration is gone.
845 sw_to_registrations_map_.erase(service_worker_id);
846 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
847 base::Bind(callback));
848 return;
851 if (status_code != SERVICE_WORKER_OK) {
852 LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
853 "failure.";
854 DisableAndClearManager(base::Bind(callback));
855 return;
858 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
859 base::Bind(callback));
862 void BackgroundSyncManager::OnRegistrationDeletedImpl(
863 int64 registration_id,
864 const base::Closure& callback) {
865 DCHECK_CURRENTLY_ON(BrowserThread::IO);
867 // The backend (ServiceWorkerStorage) will delete the data, so just delete the
868 // memory representation here.
869 sw_to_registrations_map_.erase(registration_id);
870 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
871 base::Bind(callback));
874 void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) {
875 DCHECK_CURRENTLY_ON(BrowserThread::IO);
877 sw_to_registrations_map_.clear();
878 disabled_ = false;
879 InitImpl(callback);
882 void BackgroundSyncManager::OnNetworkChanged() {
883 DCHECK_CURRENTLY_ON(BrowserThread::IO);
885 FireReadyEvents();
888 void BackgroundSyncManager::OnPowerChanged() {
889 DCHECK_CURRENTLY_ON(BrowserThread::IO);
891 FireReadyEvents();
894 template <typename CallbackT, typename... Params>
895 void BackgroundSyncManager::CompleteOperationCallback(const CallbackT& callback,
896 Params... parameters) {
897 DCHECK_CURRENTLY_ON(BrowserThread::IO);
899 callback.Run(parameters...);
900 op_scheduler_.CompleteOperationAndRunNext();
903 base::Closure BackgroundSyncManager::MakeEmptyCompletion() {
904 DCHECK_CURRENTLY_ON(BrowserThread::IO);
906 return base::Bind(
907 &BackgroundSyncManager::CompleteOperationCallback<base::Closure>,
908 weak_ptr_factory_.GetWeakPtr(), base::Bind(base::DoNothing));
911 BackgroundSyncManager::StatusAndRegistrationCallback
912 BackgroundSyncManager::MakeStatusAndRegistrationCompletion(
913 const StatusAndRegistrationCallback& callback) {
914 DCHECK_CURRENTLY_ON(BrowserThread::IO);
916 return base::Bind(&BackgroundSyncManager::CompleteOperationCallback<
917 StatusAndRegistrationCallback, ErrorType,
918 const BackgroundSyncRegistration&>,
919 weak_ptr_factory_.GetWeakPtr(), callback);
922 BackgroundSyncManager::StatusAndRegistrationsCallback
923 BackgroundSyncManager::MakeStatusAndRegistrationsCompletion(
924 const StatusAndRegistrationsCallback& callback) {
925 DCHECK_CURRENTLY_ON(BrowserThread::IO);
927 return base::Bind(&BackgroundSyncManager::CompleteOperationCallback<
928 StatusAndRegistrationsCallback, ErrorType,
929 const std::vector<BackgroundSyncRegistration>&>,
930 weak_ptr_factory_.GetWeakPtr(), callback);
933 BackgroundSyncManager::StatusCallback
934 BackgroundSyncManager::MakeStatusCompletion(const StatusCallback& callback) {
935 DCHECK_CURRENTLY_ON(BrowserThread::IO);
937 return base::Bind(
938 &BackgroundSyncManager::CompleteOperationCallback<StatusCallback,
939 ErrorType>,
940 weak_ptr_factory_.GetWeakPtr(), callback);
943 } // namespace content