Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / background_sync / background_sync_manager.cc
blob6c33d51a08506248c881ba0c13865b6beffe88b1
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_metrics.h"
13 #include "content/browser/background_sync/background_sync_network_observer.h"
14 #include "content/browser/background_sync/background_sync_power_observer.h"
15 #include "content/browser/background_sync/background_sync_registration_options.h"
16 #include "content/browser/service_worker/service_worker_context_wrapper.h"
17 #include "content/browser/service_worker/service_worker_storage.h"
18 #include "content/public/browser/browser_thread.h"
20 #if defined(OS_ANDROID)
21 #include "content/browser/android/background_sync_launcher_android.h"
22 #endif
24 namespace {
25 const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
28 namespace content {
30 BackgroundSyncManager::BackgroundSyncRegistrations::
31 BackgroundSyncRegistrations()
32 : next_id(BackgroundSyncRegistration::kInitialId) {
35 BackgroundSyncManager::BackgroundSyncRegistrations::
36 ~BackgroundSyncRegistrations() {
39 // static
40 scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
41 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
42 DCHECK_CURRENTLY_ON(BrowserThread::IO);
44 BackgroundSyncManager* sync_manager =
45 new BackgroundSyncManager(service_worker_context);
46 sync_manager->Init();
47 return make_scoped_ptr(sync_manager);
50 BackgroundSyncManager::~BackgroundSyncManager() {
51 DCHECK_CURRENTLY_ON(BrowserThread::IO);
53 service_worker_context_->RemoveObserver(this);
56 BackgroundSyncManager::RegistrationKey::RegistrationKey(
57 const BackgroundSyncRegistration& registration)
58 : RegistrationKey(registration.options()->tag,
59 registration.options()->periodicity) {
62 BackgroundSyncManager::RegistrationKey::RegistrationKey(
63 const BackgroundSyncRegistrationOptions& options)
64 : RegistrationKey(options.tag, options.periodicity) {
67 BackgroundSyncManager::RegistrationKey::RegistrationKey(
68 const std::string& tag,
69 SyncPeriodicity periodicity)
70 : value_(periodicity == SYNC_ONE_SHOT ? "o_" + tag : "p_" + tag) {
73 void BackgroundSyncManager::Register(
74 int64 sw_registration_id,
75 const BackgroundSyncRegistrationOptions& options,
76 const StatusAndRegistrationCallback& callback) {
77 DCHECK_CURRENTLY_ON(BrowserThread::IO);
79 // For UMA, determine here whether the sync could fire immediately
80 BackgroundSyncMetrics::RegistrationCouldFire registration_could_fire =
81 AreOptionConditionsMet(options)
82 ? BackgroundSyncMetrics::REGISTRATION_COULD_FIRE
83 : BackgroundSyncMetrics::REGISTRATION_COULD_NOT_FIRE;
85 if (disabled_) {
86 BackgroundSyncMetrics::CountRegister(
87 options.periodicity, registration_could_fire,
88 BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE,
89 ERROR_TYPE_STORAGE);
90 base::ThreadTaskRunnerHandle::Get()->PostTask(
91 FROM_HERE,
92 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
93 return;
96 op_scheduler_.ScheduleOperation(
97 base::Bind(&BackgroundSyncManager::RegisterImpl,
98 weak_ptr_factory_.GetWeakPtr(), sw_registration_id, options,
99 MakeStatusAndRegistrationCompletion(callback)));
102 void BackgroundSyncManager::Unregister(
103 int64 sw_registration_id,
104 const std::string& sync_registration_tag,
105 SyncPeriodicity periodicity,
106 BackgroundSyncRegistration::RegistrationId sync_registration_id,
107 const StatusCallback& callback) {
108 DCHECK_CURRENTLY_ON(BrowserThread::IO);
110 if (disabled_) {
111 BackgroundSyncMetrics::CountUnregister(periodicity, ERROR_TYPE_STORAGE);
112 base::ThreadTaskRunnerHandle::Get()->PostTask(
113 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
114 return;
117 RegistrationKey registration_key(sync_registration_tag, periodicity);
119 op_scheduler_.ScheduleOperation(base::Bind(
120 &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(),
121 sw_registration_id, registration_key, sync_registration_id, periodicity,
122 MakeStatusCompletion(callback)));
125 void BackgroundSyncManager::GetRegistration(
126 int64 sw_registration_id,
127 const std::string& sync_registration_tag,
128 SyncPeriodicity periodicity,
129 const StatusAndRegistrationCallback& callback) {
130 DCHECK_CURRENTLY_ON(BrowserThread::IO);
132 if (disabled_) {
133 base::ThreadTaskRunnerHandle::Get()->PostTask(
134 FROM_HERE,
135 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
136 return;
139 RegistrationKey registration_key(sync_registration_tag, periodicity);
141 op_scheduler_.ScheduleOperation(base::Bind(
142 &BackgroundSyncManager::GetRegistrationImpl,
143 weak_ptr_factory_.GetWeakPtr(), sw_registration_id, registration_key,
144 MakeStatusAndRegistrationCompletion(callback)));
147 void BackgroundSyncManager::GetRegistrations(
148 int64 sw_registration_id,
149 SyncPeriodicity periodicity,
150 const StatusAndRegistrationsCallback& callback) {
151 DCHECK_CURRENTLY_ON(BrowserThread::IO);
153 if (disabled_) {
154 base::ThreadTaskRunnerHandle::Get()->PostTask(
155 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE,
156 std::vector<BackgroundSyncRegistration>()));
157 return;
160 op_scheduler_.ScheduleOperation(
161 base::Bind(&BackgroundSyncManager::GetRegistrationsImpl,
162 weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
163 periodicity, MakeStatusAndRegistrationsCompletion(callback)));
166 void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id,
167 const GURL& pattern) {
168 DCHECK_CURRENTLY_ON(BrowserThread::IO);
170 // Operations already in the queue will either fail when they write to storage
171 // or return stale results based on registrations loaded in memory. This is
172 // inconsequential since the service worker is gone.
173 op_scheduler_.ScheduleOperation(base::Bind(
174 &BackgroundSyncManager::OnRegistrationDeletedImpl,
175 weak_ptr_factory_.GetWeakPtr(), registration_id, MakeEmptyCompletion()));
178 void BackgroundSyncManager::OnStorageWiped() {
179 DCHECK_CURRENTLY_ON(BrowserThread::IO);
181 // Operations already in the queue will either fail when they write to storage
182 // or return stale results based on registrations loaded in memory. This is
183 // inconsequential since the service workers are gone.
184 op_scheduler_.ScheduleOperation(
185 base::Bind(&BackgroundSyncManager::OnStorageWipedImpl,
186 weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
189 BackgroundSyncManager::BackgroundSyncManager(
190 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
191 : service_worker_context_(service_worker_context),
192 disabled_(false),
193 weak_ptr_factory_(this) {
194 DCHECK_CURRENTLY_ON(BrowserThread::IO);
196 service_worker_context_->AddObserver(this);
198 network_observer_.reset(new BackgroundSyncNetworkObserver(
199 base::Bind(&BackgroundSyncManager::OnNetworkChanged,
200 weak_ptr_factory_.GetWeakPtr())));
201 power_observer_.reset(new BackgroundSyncPowerObserver(base::Bind(
202 &BackgroundSyncManager::OnPowerChanged, weak_ptr_factory_.GetWeakPtr())));
205 void BackgroundSyncManager::Init() {
206 DCHECK_CURRENTLY_ON(BrowserThread::IO);
207 DCHECK(!op_scheduler_.ScheduledOperations());
208 DCHECK(!disabled_);
210 op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl,
211 weak_ptr_factory_.GetWeakPtr(),
212 MakeEmptyCompletion()));
215 void BackgroundSyncManager::InitImpl(const base::Closure& callback) {
216 DCHECK_CURRENTLY_ON(BrowserThread::IO);
218 if (disabled_) {
219 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
220 base::Bind(callback));
221 return;
224 GetDataFromBackend(
225 kBackgroundSyncUserDataKey,
226 base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend,
227 weak_ptr_factory_.GetWeakPtr(), callback));
230 void BackgroundSyncManager::InitDidGetDataFromBackend(
231 const base::Closure& callback,
232 const std::vector<std::pair<int64, std::string>>& user_data,
233 ServiceWorkerStatusCode status) {
234 DCHECK_CURRENTLY_ON(BrowserThread::IO);
236 if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
237 LOG(ERROR) << "BackgroundSync failed to init due to backend failure.";
238 DisableAndClearManager(base::Bind(callback));
239 return;
242 bool corruption_detected = false;
243 for (const std::pair<int64, std::string>& data : user_data) {
244 BackgroundSyncRegistrationsProto registrations_proto;
245 if (registrations_proto.ParseFromString(data.second)) {
246 BackgroundSyncRegistrations* registrations =
247 &sw_to_registrations_map_[data.first];
248 registrations->next_id = registrations_proto.next_registration_id();
249 registrations->origin = GURL(registrations_proto.origin());
251 for (int i = 0, max = registrations_proto.registration_size(); i < max;
252 ++i) {
253 const BackgroundSyncRegistrationProto& registration_proto =
254 registrations_proto.registration(i);
256 if (registration_proto.id() >= registrations->next_id) {
257 corruption_detected = true;
258 break;
261 RegistrationKey registration_key(registration_proto.tag(),
262 registration_proto.periodicity());
263 BackgroundSyncRegistration* registration =
264 &registrations->registration_map[registration_key];
266 BackgroundSyncRegistrationOptions* options = registration->options();
267 options->tag = registration_proto.tag();
268 options->periodicity = registration_proto.periodicity();
269 options->min_period = registration_proto.min_period();
270 options->network_state = registration_proto.network_state();
271 options->power_state = registration_proto.power_state();
273 registration->set_id(registration_proto.id());
274 registration->set_sync_state(registration_proto.sync_state());
276 if (registration->sync_state() == SYNC_STATE_FIRING) {
277 // If the browser (or worker) closed while firing the event, consider
278 // it pending again>
279 registration->set_sync_state(SYNC_STATE_PENDING);
284 if (corruption_detected)
285 break;
288 if (corruption_detected) {
289 LOG(ERROR) << "Corruption detected in background sync backend";
290 DisableAndClearManager(base::Bind(callback));
291 return;
294 FireReadyEvents();
296 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
297 base::Bind(callback));
300 void BackgroundSyncManager::RegisterImpl(
301 int64 sw_registration_id,
302 const BackgroundSyncRegistrationOptions& options,
303 const StatusAndRegistrationCallback& callback) {
304 DCHECK_CURRENTLY_ON(BrowserThread::IO);
306 // For UMA, determine here whether the sync could fire immediately
307 BackgroundSyncMetrics::RegistrationCouldFire registration_could_fire =
308 AreOptionConditionsMet(options)
309 ? BackgroundSyncMetrics::REGISTRATION_COULD_FIRE
310 : BackgroundSyncMetrics::REGISTRATION_COULD_NOT_FIRE;
312 if (disabled_) {
313 BackgroundSyncMetrics::CountRegister(
314 options.periodicity, registration_could_fire,
315 BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE,
316 ERROR_TYPE_STORAGE);
317 base::ThreadTaskRunnerHandle::Get()->PostTask(
318 FROM_HERE,
319 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
320 return;
323 ServiceWorkerRegistration* sw_registration =
324 service_worker_context_->GetLiveRegistration(sw_registration_id);
325 if (!sw_registration || !sw_registration->active_version()) {
326 BackgroundSyncMetrics::CountRegister(
327 options.periodicity, registration_could_fire,
328 BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE,
329 ERROR_TYPE_NO_SERVICE_WORKER);
330 base::ThreadTaskRunnerHandle::Get()->PostTask(
331 FROM_HERE, base::Bind(callback, ERROR_TYPE_NO_SERVICE_WORKER,
332 BackgroundSyncRegistration()));
333 return;
336 if (!sw_registration->active_version()->HasWindowClients()) {
337 base::ThreadTaskRunnerHandle::Get()->PostTask(
338 FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_ALLOWED,
339 BackgroundSyncRegistration()));
340 return;
343 BackgroundSyncRegistration* existing_registration =
344 LookupRegistration(sw_registration_id, RegistrationKey(options));
345 if (existing_registration &&
346 existing_registration->options()->Equals(options)) {
347 if (existing_registration->sync_state() == SYNC_STATE_FAILED) {
348 existing_registration->set_sync_state(SYNC_STATE_PENDING);
349 StoreRegistrations(
350 sw_registration_id,
351 base::Bind(&BackgroundSyncManager::RegisterDidStore,
352 weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
353 *existing_registration, callback));
354 return;
357 // Record the duplicated registration
358 BackgroundSyncMetrics::CountRegister(
359 existing_registration->options()->periodicity, registration_could_fire,
360 BackgroundSyncMetrics::REGISTRATION_IS_DUPLICATE, ERROR_TYPE_OK);
362 base::ThreadTaskRunnerHandle::Get()->PostTask(
363 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *existing_registration));
364 return;
367 BackgroundSyncRegistration new_registration;
368 *new_registration.options() = options;
370 BackgroundSyncRegistrations* registrations =
371 &sw_to_registrations_map_[sw_registration_id];
372 new_registration.set_id(registrations->next_id++);
374 AddRegistrationToMap(sw_registration_id,
375 sw_registration->pattern().GetOrigin(),
376 new_registration);
378 StoreRegistrations(
379 sw_registration_id,
380 base::Bind(&BackgroundSyncManager::RegisterDidStore,
381 weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
382 new_registration, callback));
385 void BackgroundSyncManager::DisableAndClearManager(
386 const base::Closure& callback) {
387 DCHECK_CURRENTLY_ON(BrowserThread::IO);
389 if (disabled_) {
390 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
391 base::Bind(callback));
392 return;
395 disabled_ = true;
396 sw_to_registrations_map_.clear();
398 // Delete all backend entries. The memory representation of registered syncs
399 // may be out of sync with storage (e.g., due to corruption detection on
400 // loading from storage), so reload the registrations from storage again.
401 GetDataFromBackend(
402 kBackgroundSyncUserDataKey,
403 base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations,
404 weak_ptr_factory_.GetWeakPtr(), callback));
407 void BackgroundSyncManager::DisableAndClearDidGetRegistrations(
408 const base::Closure& callback,
409 const std::vector<std::pair<int64, std::string>>& user_data,
410 ServiceWorkerStatusCode status) {
411 DCHECK_CURRENTLY_ON(BrowserThread::IO);
413 if (status != SERVICE_WORKER_OK || user_data.empty()) {
414 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
415 base::Bind(callback));
416 return;
419 base::Closure barrier_closure =
420 base::BarrierClosure(user_data.size(), base::Bind(callback));
422 for (const auto& sw_id_and_regs : user_data) {
423 service_worker_context_->ClearRegistrationUserData(
424 sw_id_and_regs.first, kBackgroundSyncUserDataKey,
425 base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne,
426 weak_ptr_factory_.GetWeakPtr(), barrier_closure));
430 void BackgroundSyncManager::DisableAndClearManagerClearedOne(
431 const base::Closure& barrier_closure,
432 ServiceWorkerStatusCode status) {
433 DCHECK_CURRENTLY_ON(BrowserThread::IO);
435 // The status doesn't matter at this point, there is nothing else to be done.
436 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
437 base::Bind(barrier_closure));
440 BackgroundSyncRegistration* BackgroundSyncManager::LookupRegistration(
441 int64 sw_registration_id,
442 const RegistrationKey& registration_key) {
443 DCHECK_CURRENTLY_ON(BrowserThread::IO);
445 SWIdToRegistrationsMap::iterator it =
446 sw_to_registrations_map_.find(sw_registration_id);
447 if (it == sw_to_registrations_map_.end())
448 return nullptr;
450 BackgroundSyncRegistrations& registrations = it->second;
451 DCHECK_LE(BackgroundSyncRegistration::kInitialId, registrations.next_id);
452 DCHECK(!registrations.origin.is_empty());
454 auto key_and_registration_iter =
455 registrations.registration_map.find(registration_key);
456 if (key_and_registration_iter == registrations.registration_map.end())
457 return nullptr;
459 return &key_and_registration_iter->second;
462 void BackgroundSyncManager::StoreRegistrations(
463 int64 sw_registration_id,
464 const ServiceWorkerStorage::StatusCallback& callback) {
465 DCHECK_CURRENTLY_ON(BrowserThread::IO);
467 // Serialize the data.
468 const BackgroundSyncRegistrations& registrations =
469 sw_to_registrations_map_[sw_registration_id];
470 BackgroundSyncRegistrationsProto registrations_proto;
471 registrations_proto.set_next_registration_id(registrations.next_id);
472 registrations_proto.set_origin(registrations.origin.spec());
474 for (const auto& key_and_registration : registrations.registration_map) {
475 const BackgroundSyncRegistration& registration =
476 key_and_registration.second;
477 BackgroundSyncRegistrationProto* registration_proto =
478 registrations_proto.add_registration();
479 registration_proto->set_id(registration.id());
480 registration_proto->set_sync_state(registration.sync_state());
481 registration_proto->set_tag(registration.options()->tag);
482 registration_proto->set_periodicity(registration.options()->periodicity);
483 registration_proto->set_min_period(registration.options()->min_period);
484 registration_proto->set_network_state(
485 registration.options()->network_state);
486 registration_proto->set_power_state(registration.options()->power_state);
488 std::string serialized;
489 bool success = registrations_proto.SerializeToString(&serialized);
490 DCHECK(success);
492 StoreDataInBackend(sw_registration_id, registrations.origin,
493 kBackgroundSyncUserDataKey, serialized, callback);
496 void BackgroundSyncManager::RegisterDidStore(
497 int64 sw_registration_id,
498 const BackgroundSyncRegistration& new_registration,
499 const StatusAndRegistrationCallback& callback,
500 ServiceWorkerStatusCode status) {
501 DCHECK_CURRENTLY_ON(BrowserThread::IO);
503 // For UMA, determine here whether the sync could fire immediately
504 BackgroundSyncMetrics::RegistrationCouldFire registration_could_fire =
505 AreOptionConditionsMet(*new_registration.options())
506 ? BackgroundSyncMetrics::REGISTRATION_COULD_FIRE
507 : BackgroundSyncMetrics::REGISTRATION_COULD_NOT_FIRE;
509 if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
510 // The service worker registration is gone.
511 BackgroundSyncMetrics::CountRegister(
512 new_registration.options()->periodicity, registration_could_fire,
513 BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE,
514 ERROR_TYPE_STORAGE);
515 sw_to_registrations_map_.erase(sw_registration_id);
516 base::ThreadTaskRunnerHandle::Get()->PostTask(
517 FROM_HERE,
518 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
519 return;
522 if (status != SERVICE_WORKER_OK) {
523 LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
524 "failure.";
525 BackgroundSyncMetrics::CountRegister(
526 new_registration.options()->periodicity, registration_could_fire,
527 BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE,
528 ERROR_TYPE_STORAGE);
529 DisableAndClearManager(
530 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
531 return;
534 BackgroundSyncMetrics::CountRegister(
535 new_registration.options()->periodicity, registration_could_fire,
536 BackgroundSyncMetrics::REGISTRATION_IS_NOT_DUPLICATE, ERROR_TYPE_OK);
537 FireReadyEvents();
538 base::ThreadTaskRunnerHandle::Get()->PostTask(
539 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration));
542 void BackgroundSyncManager::RemoveRegistrationFromMap(
543 int64 sw_registration_id,
544 const RegistrationKey& registration_key) {
545 DCHECK_CURRENTLY_ON(BrowserThread::IO);
546 DCHECK(LookupRegistration(sw_registration_id, registration_key));
548 BackgroundSyncRegistrations* registrations =
549 &sw_to_registrations_map_[sw_registration_id];
551 registrations->registration_map.erase(registration_key);
554 void BackgroundSyncManager::AddRegistrationToMap(
555 int64 sw_registration_id,
556 const GURL& origin,
557 const BackgroundSyncRegistration& sync_registration) {
558 DCHECK_CURRENTLY_ON(BrowserThread::IO);
559 DCHECK(sync_registration.IsValid());
561 BackgroundSyncRegistrations* registrations =
562 &sw_to_registrations_map_[sw_registration_id];
563 registrations->origin = origin;
565 RegistrationKey registration_key(sync_registration);
566 registrations->registration_map[registration_key] = sync_registration;
569 void BackgroundSyncManager::StoreDataInBackend(
570 int64 sw_registration_id,
571 const GURL& origin,
572 const std::string& backend_key,
573 const std::string& data,
574 const ServiceWorkerStorage::StatusCallback& callback) {
575 DCHECK_CURRENTLY_ON(BrowserThread::IO);
577 service_worker_context_->StoreRegistrationUserData(
578 sw_registration_id, origin, backend_key, data, callback);
581 void BackgroundSyncManager::GetDataFromBackend(
582 const std::string& backend_key,
583 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
584 callback) {
585 DCHECK_CURRENTLY_ON(BrowserThread::IO);
587 service_worker_context_->GetUserDataForAllRegistrations(backend_key,
588 callback);
591 void BackgroundSyncManager::FireOneShotSync(
592 const BackgroundSyncRegistration& registration,
593 const scoped_refptr<ServiceWorkerVersion>& active_version,
594 const ServiceWorkerVersion::StatusCallback& callback) {
595 DCHECK_CURRENTLY_ON(BrowserThread::IO);
597 active_version->DispatchSyncEvent(
598 mojo::ConvertTo<SyncRegistrationPtr>(registration), callback);
601 void BackgroundSyncManager::UnregisterImpl(
602 int64 sw_registration_id,
603 const RegistrationKey& registration_key,
604 BackgroundSyncRegistration::RegistrationId sync_registration_id,
605 SyncPeriodicity periodicity,
606 const StatusCallback& callback) {
607 DCHECK_CURRENTLY_ON(BrowserThread::IO);
609 if (disabled_) {
610 BackgroundSyncMetrics::CountUnregister(periodicity, ERROR_TYPE_STORAGE);
611 base::ThreadTaskRunnerHandle::Get()->PostTask(
612 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
613 return;
616 const BackgroundSyncRegistration* existing_registration =
617 LookupRegistration(sw_registration_id, registration_key);
618 if (!existing_registration ||
619 existing_registration->id() != sync_registration_id) {
620 BackgroundSyncMetrics::CountUnregister(periodicity, ERROR_TYPE_NOT_FOUND);
621 base::ThreadTaskRunnerHandle::Get()->PostTask(
622 FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND));
623 return;
626 RemoveRegistrationFromMap(sw_registration_id, registration_key);
628 StoreRegistrations(sw_registration_id,
629 base::Bind(&BackgroundSyncManager::UnregisterDidStore,
630 weak_ptr_factory_.GetWeakPtr(),
631 sw_registration_id, periodicity, callback));
634 void BackgroundSyncManager::UnregisterDidStore(int64 sw_registration_id,
635 SyncPeriodicity periodicity,
636 const StatusCallback& callback,
637 ServiceWorkerStatusCode status) {
638 DCHECK_CURRENTLY_ON(BrowserThread::IO);
640 if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
641 // ServiceWorker was unregistered.
642 BackgroundSyncMetrics::CountUnregister(periodicity, ERROR_TYPE_STORAGE);
643 sw_to_registrations_map_.erase(sw_registration_id);
644 base::ThreadTaskRunnerHandle::Get()->PostTask(
645 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
646 return;
649 if (status != SERVICE_WORKER_OK) {
650 LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure.";
651 BackgroundSyncMetrics::CountUnregister(periodicity, ERROR_TYPE_STORAGE);
652 DisableAndClearManager(base::Bind(callback, ERROR_TYPE_STORAGE));
653 return;
656 BackgroundSyncMetrics::CountUnregister(periodicity, ERROR_TYPE_OK);
657 base::ThreadTaskRunnerHandle::Get()->PostTask(
658 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK));
661 void BackgroundSyncManager::GetRegistrationImpl(
662 int64 sw_registration_id,
663 const RegistrationKey& registration_key,
664 const StatusAndRegistrationCallback& callback) {
665 DCHECK_CURRENTLY_ON(BrowserThread::IO);
667 if (disabled_) {
668 base::ThreadTaskRunnerHandle::Get()->PostTask(
669 FROM_HERE,
670 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
671 return;
674 const BackgroundSyncRegistration* out_registration =
675 LookupRegistration(sw_registration_id, registration_key);
676 if (!out_registration) {
677 base::ThreadTaskRunnerHandle::Get()->PostTask(
678 FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND,
679 BackgroundSyncRegistration()));
680 return;
683 base::ThreadTaskRunnerHandle::Get()->PostTask(
684 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *out_registration));
687 void BackgroundSyncManager::GetRegistrationsImpl(
688 int64 sw_registration_id,
689 SyncPeriodicity periodicity,
690 const StatusAndRegistrationsCallback& callback) {
691 DCHECK_CURRENTLY_ON(BrowserThread::IO);
693 std::vector<BackgroundSyncRegistration> out_registrations;
695 if (disabled_) {
696 base::ThreadTaskRunnerHandle::Get()->PostTask(
697 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE, out_registrations));
698 return;
701 SWIdToRegistrationsMap::iterator it =
702 sw_to_registrations_map_.find(sw_registration_id);
704 if (it != sw_to_registrations_map_.end()) {
705 const BackgroundSyncRegistrations& registrations = it->second;
706 for (const auto& tag_and_registration : registrations.registration_map) {
707 const BackgroundSyncRegistration& registration =
708 tag_and_registration.second;
709 if (registration.options()->periodicity == periodicity)
710 out_registrations.push_back(registration);
714 base::ThreadTaskRunnerHandle::Get()->PostTask(
715 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registrations));
718 bool BackgroundSyncManager::AreOptionConditionsMet(
719 const BackgroundSyncRegistrationOptions& options) {
720 DCHECK_CURRENTLY_ON(BrowserThread::IO);
721 return network_observer_->NetworkSufficient(options.network_state) &&
722 power_observer_->PowerSufficient(options.power_state);
725 bool BackgroundSyncManager::IsRegistrationReadyToFire(
726 const BackgroundSyncRegistration& registration) {
727 DCHECK_CURRENTLY_ON(BrowserThread::IO);
729 // TODO(jkarlin): Add support for firing periodic registrations.
730 if (registration.options()->periodicity == SYNC_PERIODIC)
731 return false;
733 if (registration.sync_state() != SYNC_STATE_PENDING)
734 return false;
736 DCHECK_EQ(SYNC_ONE_SHOT, registration.options()->periodicity);
738 return AreOptionConditionsMet(*registration.options());
741 void BackgroundSyncManager::SchedulePendingRegistrations() {
742 #if defined(OS_ANDROID)
743 bool keep_browser_alive_for_one_shot = false;
745 for (const auto& sw_id_and_registrations : sw_to_registrations_map_) {
746 for (const auto& key_and_registration :
747 sw_id_and_registrations.second.registration_map) {
748 const BackgroundSyncRegistration& registration =
749 key_and_registration.second;
750 if (registration.sync_state() == SYNC_STATE_PENDING) {
751 if (registration.options()->periodicity == SYNC_ONE_SHOT) {
752 keep_browser_alive_for_one_shot = true;
753 } else {
754 // TODO(jkarlin): Support keeping the browser alive for periodic
755 // syncs.
761 // TODO(jkarlin): Use the context's path instead of the 'this' pointer as an
762 // identifier. See crbug.com/489705.
763 BrowserThread::PostTask(
764 BrowserThread::UI, FROM_HERE,
765 base::Bind(&BackgroundSyncLauncherAndroid::LaunchBrowserWhenNextOnline,
766 this, keep_browser_alive_for_one_shot));
767 #else
768 // TODO(jkarlin): Toggle Chrome's background mode.
769 #endif
772 void BackgroundSyncManager::FireReadyEvents() {
773 DCHECK_CURRENTLY_ON(BrowserThread::IO);
775 if (disabled_)
776 return;
778 op_scheduler_.ScheduleOperation(
779 base::Bind(&BackgroundSyncManager::FireReadyEventsImpl,
780 weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
783 void BackgroundSyncManager::FireReadyEventsImpl(const base::Closure& callback) {
784 DCHECK_CURRENTLY_ON(BrowserThread::IO);
786 if (disabled_) {
787 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
788 base::Bind(callback));
789 return;
792 // Find the registrations that are ready to run.
793 std::vector<std::pair<int64, RegistrationKey>> sw_id_and_keys_to_fire;
795 for (auto& sw_id_and_registrations : sw_to_registrations_map_) {
796 const int64 service_worker_id = sw_id_and_registrations.first;
797 for (auto& key_and_registration :
798 sw_id_and_registrations.second.registration_map) {
799 BackgroundSyncRegistration* registration = &key_and_registration.second;
800 if (IsRegistrationReadyToFire(*registration)) {
801 sw_id_and_keys_to_fire.push_back(
802 std::make_pair(service_worker_id, key_and_registration.first));
803 // The state change is not saved to persistent storage because
804 // if the sync event is killed mid-sync then it should return to
805 // SYNC_STATE_PENDING.
806 registration->set_sync_state(SYNC_STATE_FIRING);
811 // If there are no registrations currently ready, then just run |callback|.
812 // Otherwise, fire them all, and record the result when done.
813 if (sw_id_and_keys_to_fire.size() == 0) {
814 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
815 base::Bind(callback));
816 } else {
817 base::TimeTicks start_time = base::TimeTicks::Now();
819 // Fire the sync event of the ready registrations and run |callback| once
820 // they're all done.
821 base::Closure events_fired_barrier_closure = base::BarrierClosure(
822 sw_id_and_keys_to_fire.size(), base::Bind(callback));
824 // Record the total time taken after all events have run to completion.
825 base::Closure events_completed_barrier_closure =
826 base::BarrierClosure(sw_id_and_keys_to_fire.size(),
827 base::Bind(&OnAllSyncEventsCompleted, start_time,
828 sw_id_and_keys_to_fire.size()));
830 for (const auto& sw_id_and_key : sw_id_and_keys_to_fire) {
831 int64 service_worker_id = sw_id_and_key.first;
832 const BackgroundSyncRegistration* registration =
833 LookupRegistration(service_worker_id, sw_id_and_key.second);
835 service_worker_context_->FindRegistrationForId(
836 service_worker_id, sw_to_registrations_map_[service_worker_id].origin,
837 base::Bind(&BackgroundSyncManager::FireReadyEventsDidFindRegistration,
838 weak_ptr_factory_.GetWeakPtr(), sw_id_and_key.second,
839 registration->id(), events_fired_barrier_closure,
840 events_completed_barrier_closure));
844 SchedulePendingRegistrations();
847 void BackgroundSyncManager::FireReadyEventsDidFindRegistration(
848 const RegistrationKey& registration_key,
849 BackgroundSyncRegistration::RegistrationId registration_id,
850 const base::Closure& event_fired_callback,
851 const base::Closure& event_completed_callback,
852 ServiceWorkerStatusCode service_worker_status,
853 const scoped_refptr<ServiceWorkerRegistration>&
854 service_worker_registration) {
855 DCHECK_CURRENTLY_ON(BrowserThread::IO);
856 if (service_worker_status != SERVICE_WORKER_OK) {
857 base::ThreadTaskRunnerHandle::Get()->PostTask(
858 FROM_HERE, base::Bind(event_fired_callback));
859 base::ThreadTaskRunnerHandle::Get()->PostTask(
860 FROM_HERE, base::Bind(event_completed_callback));
861 return;
864 BackgroundSyncRegistration* registration =
865 LookupRegistration(service_worker_registration->id(), registration_key);
867 FireOneShotSync(
868 *registration, service_worker_registration->active_version(),
869 base::Bind(&BackgroundSyncManager::EventComplete,
870 weak_ptr_factory_.GetWeakPtr(), service_worker_registration,
871 service_worker_registration->id(), registration_key,
872 registration_id, event_completed_callback));
874 base::ThreadTaskRunnerHandle::Get()->PostTask(
875 FROM_HERE, base::Bind(event_fired_callback));
878 // |service_worker_registration| is just to keep the registration alive
879 // while the event is firing.
880 void BackgroundSyncManager::EventComplete(
881 const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
882 int64 service_worker_id,
883 const RegistrationKey& key,
884 BackgroundSyncRegistration::RegistrationId sync_registration_id,
885 const base::Closure& callback,
886 ServiceWorkerStatusCode status_code) {
887 DCHECK_CURRENTLY_ON(BrowserThread::IO);
888 if (disabled_)
889 return;
891 op_scheduler_.ScheduleOperation(base::Bind(
892 &BackgroundSyncManager::EventCompleteImpl, weak_ptr_factory_.GetWeakPtr(),
893 service_worker_id, key, sync_registration_id, status_code,
894 MakeClosureCompletion(callback)));
897 void BackgroundSyncManager::EventCompleteImpl(
898 int64 service_worker_id,
899 const RegistrationKey& key,
900 BackgroundSyncRegistration::RegistrationId sync_registration_id,
901 ServiceWorkerStatusCode status_code,
902 const base::Closure& callback) {
903 DCHECK_CURRENTLY_ON(BrowserThread::IO);
905 if (disabled_) {
906 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
907 base::Bind(callback));
908 return;
911 BackgroundSyncRegistration* registration =
912 LookupRegistration(service_worker_id, key);
913 if (!registration || registration->id() != sync_registration_id) {
914 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
915 base::Bind(callback));
916 return;
919 // The event ran to completion, we should count it, no matter what happens
920 // from here.
921 BackgroundSyncMetrics::RecordEventResult(registration->options()->periodicity,
922 status_code == SERVICE_WORKER_OK);
924 if (registration->options()->periodicity == SYNC_ONE_SHOT) {
925 if (status_code != SERVICE_WORKER_OK) {
926 // TODO(jkarlin) Fire the sync event on the next page load controlled by
927 // this registration. (crbug.com/479665)
928 registration->set_sync_state(SYNC_STATE_FAILED);
929 } else {
930 registration = nullptr;
931 RemoveRegistrationFromMap(service_worker_id, key);
933 } else {
934 // TODO(jkarlin): Add support for running periodic syncs. (crbug.com/479674)
935 NOTREACHED();
938 StoreRegistrations(
939 service_worker_id,
940 base::Bind(&BackgroundSyncManager::EventCompleteDidStore,
941 weak_ptr_factory_.GetWeakPtr(), service_worker_id, callback));
944 void BackgroundSyncManager::EventCompleteDidStore(
945 int64 service_worker_id,
946 const base::Closure& callback,
947 ServiceWorkerStatusCode status_code) {
948 DCHECK_CURRENTLY_ON(BrowserThread::IO);
950 if (status_code == SERVICE_WORKER_ERROR_NOT_FOUND) {
951 // The registration is gone.
952 sw_to_registrations_map_.erase(service_worker_id);
953 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
954 base::Bind(callback));
955 return;
958 if (status_code != SERVICE_WORKER_OK) {
959 LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
960 "failure.";
961 DisableAndClearManager(base::Bind(callback));
962 return;
965 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
966 base::Bind(callback));
969 // static
970 void BackgroundSyncManager::OnAllSyncEventsCompleted(
971 const base::TimeTicks& start_time,
972 int number_of_batched_sync_events) {
973 // Record the combined time taken by all sync events.
974 BackgroundSyncMetrics::RecordBatchSyncEventComplete(
975 base::TimeTicks::Now() - start_time, number_of_batched_sync_events);
978 void BackgroundSyncManager::OnRegistrationDeletedImpl(
979 int64 registration_id,
980 const base::Closure& callback) {
981 DCHECK_CURRENTLY_ON(BrowserThread::IO);
983 // The backend (ServiceWorkerStorage) will delete the data, so just delete the
984 // memory representation here.
985 sw_to_registrations_map_.erase(registration_id);
986 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
987 base::Bind(callback));
990 void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) {
991 DCHECK_CURRENTLY_ON(BrowserThread::IO);
993 sw_to_registrations_map_.clear();
994 disabled_ = false;
995 InitImpl(callback);
998 void BackgroundSyncManager::OnNetworkChanged() {
999 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1001 FireReadyEvents();
1004 void BackgroundSyncManager::OnPowerChanged() {
1005 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1007 FireReadyEvents();
1010 template <typename CallbackT, typename... Params>
1011 void BackgroundSyncManager::CompleteOperationCallback(const CallbackT& callback,
1012 Params... parameters) {
1013 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1015 callback.Run(parameters...);
1016 op_scheduler_.CompleteOperationAndRunNext();
1019 base::Closure BackgroundSyncManager::MakeEmptyCompletion() {
1020 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1022 return MakeClosureCompletion(base::Bind(base::DoNothing));
1025 base::Closure BackgroundSyncManager::MakeClosureCompletion(
1026 const base::Closure& callback) {
1027 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1029 return base::Bind(
1030 &BackgroundSyncManager::CompleteOperationCallback<base::Closure>,
1031 weak_ptr_factory_.GetWeakPtr(), callback);
1034 BackgroundSyncManager::StatusAndRegistrationCallback
1035 BackgroundSyncManager::MakeStatusAndRegistrationCompletion(
1036 const StatusAndRegistrationCallback& callback) {
1037 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1039 return base::Bind(&BackgroundSyncManager::CompleteOperationCallback<
1040 StatusAndRegistrationCallback, ErrorType,
1041 const BackgroundSyncRegistration&>,
1042 weak_ptr_factory_.GetWeakPtr(), callback);
1045 BackgroundSyncManager::StatusAndRegistrationsCallback
1046 BackgroundSyncManager::MakeStatusAndRegistrationsCompletion(
1047 const StatusAndRegistrationsCallback& callback) {
1048 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1050 return base::Bind(&BackgroundSyncManager::CompleteOperationCallback<
1051 StatusAndRegistrationsCallback, ErrorType,
1052 const std::vector<BackgroundSyncRegistration>&>,
1053 weak_ptr_factory_.GetWeakPtr(), callback);
1056 BackgroundSyncManager::StatusCallback
1057 BackgroundSyncManager::MakeStatusCompletion(const StatusCallback& callback) {
1058 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1060 return base::Bind(
1061 &BackgroundSyncManager::CompleteOperationCallback<StatusCallback,
1062 ErrorType>,
1063 weak_ptr_factory_.GetWeakPtr(), callback);
1066 } // namespace content