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"
9 #include "content/browser/service_worker/service_worker_context_wrapper.h"
10 #include "content/browser/service_worker/service_worker_storage.h"
11 #include "content/public/browser/browser_thread.h"
14 const char kBackgroundSyncUserDataKey
[] = "BackgroundSyncUserData";
19 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
20 BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId
=
23 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
24 BackgroundSyncManager::BackgroundSyncRegistrations::kInitialId
= 0;
26 BackgroundSyncManager::BackgroundSyncRegistrations::
27 BackgroundSyncRegistrations()
28 : next_id(kInitialId
) {
30 BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations(
31 BackgroundSyncRegistration::RegistrationId next_id
)
34 BackgroundSyncManager::BackgroundSyncRegistrations::
35 ~BackgroundSyncRegistrations() {
39 scoped_ptr
<BackgroundSyncManager
> BackgroundSyncManager::Create(
40 const scoped_refptr
<ServiceWorkerContextWrapper
>& service_worker_context
) {
41 BackgroundSyncManager
* sync_manager
=
42 new BackgroundSyncManager(service_worker_context
);
44 return make_scoped_ptr(sync_manager
);
47 BackgroundSyncManager::~BackgroundSyncManager() {
48 service_worker_context_
->RemoveObserver(this);
51 void BackgroundSyncManager::Register(
53 int64 sw_registration_id
,
54 const BackgroundSyncRegistration
& sync_registration
,
55 const StatusAndRegistrationCallback
& callback
) {
56 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
57 DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId
,
58 sync_registration
.id
);
61 base::MessageLoop::current()->PostTask(
63 base::Bind(callback
, ERROR_TYPE_STORAGE
, BackgroundSyncRegistration()));
67 op_scheduler_
.ScheduleOperation(base::Bind(
68 &BackgroundSyncManager::RegisterImpl
, weak_ptr_factory_
.GetWeakPtr(),
69 origin
, sw_registration_id
, sync_registration
,
70 MakeStatusAndRegistrationCompletion(callback
)));
73 void BackgroundSyncManager::Unregister(
75 int64 sw_registration_id
,
76 const std::string
& sync_registration_name
,
77 BackgroundSyncRegistration::RegistrationId sync_registration_id
,
78 const StatusCallback
& callback
) {
79 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
82 base::MessageLoop::current()->PostTask(
83 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_STORAGE
));
87 op_scheduler_
.ScheduleOperation(base::Bind(
88 &BackgroundSyncManager::UnregisterImpl
, weak_ptr_factory_
.GetWeakPtr(),
89 origin
, sw_registration_id
, sync_registration_name
, sync_registration_id
,
90 MakeStatusCompletion(callback
)));
93 void BackgroundSyncManager::GetRegistration(
95 int64 sw_registration_id
,
96 const std::string sync_registration_name
,
97 const StatusAndRegistrationCallback
& callback
) {
98 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
101 base::MessageLoop::current()->PostTask(
103 base::Bind(callback
, ERROR_TYPE_STORAGE
, BackgroundSyncRegistration()));
107 op_scheduler_
.ScheduleOperation(base::Bind(
108 &BackgroundSyncManager::GetRegistrationImpl
,
109 weak_ptr_factory_
.GetWeakPtr(), origin
, sw_registration_id
,
110 sync_registration_name
, MakeStatusAndRegistrationCompletion(callback
)));
113 void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id
,
114 const GURL
& pattern
) {
115 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
117 // Operations already in the queue will either fail when they write to storage
118 // or return stale results based on registrations loaded in memory. This is
119 // inconsequential since the service worker is gone.
120 op_scheduler_
.ScheduleOperation(base::Bind(
121 &BackgroundSyncManager::OnRegistrationDeletedImpl
,
122 weak_ptr_factory_
.GetWeakPtr(), registration_id
, MakeEmptyCompletion()));
125 void BackgroundSyncManager::OnStorageWiped() {
126 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
127 // Operations already in the queue will either fail when they write to storage
128 // or return stale results based on registrations loaded in memory. This is
129 // inconsequential since the service workers are gone.
130 op_scheduler_
.ScheduleOperation(
131 base::Bind(&BackgroundSyncManager::OnStorageWipedImpl
,
132 weak_ptr_factory_
.GetWeakPtr(), MakeEmptyCompletion()));
135 BackgroundSyncManager::BackgroundSyncManager(
136 const scoped_refptr
<ServiceWorkerContextWrapper
>& service_worker_context
)
137 : service_worker_context_(service_worker_context
),
139 weak_ptr_factory_(this) {
140 service_worker_context_
->AddObserver(this);
143 void BackgroundSyncManager::Init() {
144 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
145 DCHECK(!op_scheduler_
.ScheduledOperations());
148 op_scheduler_
.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl
,
149 weak_ptr_factory_
.GetWeakPtr(),
150 MakeEmptyCompletion()));
153 void BackgroundSyncManager::InitImpl(const base::Closure
& callback
) {
154 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
157 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(callback
));
162 kBackgroundSyncUserDataKey
,
163 base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend
,
164 weak_ptr_factory_
.GetWeakPtr(), callback
));
167 void BackgroundSyncManager::InitDidGetDataFromBackend(
168 const base::Closure
& callback
,
169 const std::vector
<std::pair
<int64
, std::string
>>& user_data
,
170 ServiceWorkerStatusCode status
) {
171 if (status
!= SERVICE_WORKER_OK
&& status
!= SERVICE_WORKER_ERROR_NOT_FOUND
) {
172 LOG(ERROR
) << "BackgroundSync failed to init due to backend failure.";
173 DisableAndClearManager(base::Bind(callback
));
177 bool corruption_detected
= false;
178 for (const std::pair
<int64
, std::string
>& data
: user_data
) {
179 BackgroundSyncRegistrationsProto registrations_proto
;
180 if (registrations_proto
.ParseFromString(data
.second
)) {
181 sw_to_registrations_map_
[data
.first
] = BackgroundSyncRegistrations(
182 registrations_proto
.next_registration_id());
183 BackgroundSyncRegistrations
* registrations
=
184 &sw_to_registrations_map_
[data
.first
];
186 for (int i
= 0, max
= registrations_proto
.registration_size(); i
< max
;
188 const BackgroundSyncRegistrationProto
& registration_proto
=
189 registrations_proto
.registration(i
);
191 if (registration_proto
.id() >= registrations
->next_id
) {
192 corruption_detected
= true;
196 BackgroundSyncRegistration
* registration
=
197 ®istrations
->name_to_registration_map
[registration_proto
.name()];
199 registration
->id
= registration_proto
.id();
200 registration
->name
= registration_proto
.name();
201 registration
->fire_once
= registration_proto
.fire_once();
202 registration
->min_period
= registration_proto
.min_period();
203 registration
->network_state
= registration_proto
.network_state();
204 registration
->power_state
= registration_proto
.power_state();
208 if (corruption_detected
)
212 if (corruption_detected
) {
213 LOG(ERROR
) << "Corruption detected in background sync backend";
214 DisableAndClearManager(base::Bind(callback
));
218 // TODO(jkarlin): Call the scheduling algorithm here.
220 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(callback
));
223 void BackgroundSyncManager::RegisterImpl(
225 int64 sw_registration_id
,
226 const BackgroundSyncRegistration
& sync_registration
,
227 const StatusAndRegistrationCallback
& callback
) {
229 base::MessageLoop::current()->PostTask(
231 base::Bind(callback
, ERROR_TYPE_STORAGE
, BackgroundSyncRegistration()));
235 BackgroundSyncRegistration existing_registration
;
236 if (LookupRegistration(sw_registration_id
, sync_registration
.name
,
237 &existing_registration
)) {
238 if (existing_registration
.Equals(sync_registration
)) {
239 base::MessageLoop::current()->PostTask(
241 base::Bind(callback
, ERROR_TYPE_OK
, existing_registration
));
246 BackgroundSyncRegistration new_registration
= sync_registration
;
247 BackgroundSyncRegistrations
* registrations
=
248 &sw_to_registrations_map_
[sw_registration_id
];
249 new_registration
.id
= registrations
->next_id
++;
251 AddRegistrationToMap(sw_registration_id
, new_registration
);
254 origin
, sw_registration_id
,
255 base::Bind(&BackgroundSyncManager::RegisterDidStore
,
256 weak_ptr_factory_
.GetWeakPtr(), sw_registration_id
,
257 new_registration
, callback
));
260 void BackgroundSyncManager::DisableAndClearManager(
261 const base::Closure
& callback
) {
263 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(callback
));
268 sw_to_registrations_map_
.clear();
270 // Delete all backend entries. The memory representation of registered syncs
271 // may be out of sync with storage (e.g., due to corruption detection on
272 // loading from storage), so reload the registrations from storage again.
274 kBackgroundSyncUserDataKey
,
275 base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations
,
276 weak_ptr_factory_
.GetWeakPtr(), callback
));
279 void BackgroundSyncManager::DisableAndClearDidGetRegistrations(
280 const base::Closure
& callback
,
281 const std::vector
<std::pair
<int64
, std::string
>>& user_data
,
282 ServiceWorkerStatusCode status
) {
283 if (status
!= SERVICE_WORKER_OK
|| user_data
.empty()) {
284 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(callback
));
288 base::Closure barrier_closure
=
289 base::BarrierClosure(user_data
.size(), base::Bind(callback
));
291 for (const auto& sw_id_and_regs
: user_data
) {
292 service_worker_context_
->context()->storage()->ClearUserData(
293 sw_id_and_regs
.first
, kBackgroundSyncUserDataKey
,
294 base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne
,
295 weak_ptr_factory_
.GetWeakPtr(), barrier_closure
));
299 void BackgroundSyncManager::DisableAndClearManagerClearedOne(
300 const base::Closure
& barrier_closure
,
301 ServiceWorkerStatusCode status
) {
302 // The status doesn't matter at this point, there is nothing else to be done.
303 base::MessageLoop::current()->PostTask(FROM_HERE
,
304 base::Bind(barrier_closure
));
307 bool BackgroundSyncManager::LookupRegistration(
308 int64 sw_registration_id
,
309 const std::string
& sync_registration_name
,
310 BackgroundSyncRegistration
* existing_registration
) {
311 SWIdToRegistrationsMap::iterator it
=
312 sw_to_registrations_map_
.find(sw_registration_id
);
313 if (it
== sw_to_registrations_map_
.end())
316 const BackgroundSyncRegistrations
& registrations
= it
->second
;
317 const auto name_and_registration_iter
=
318 registrations
.name_to_registration_map
.find(sync_registration_name
);
319 if (name_and_registration_iter
==
320 registrations
.name_to_registration_map
.end())
323 if (existing_registration
)
324 *existing_registration
= name_and_registration_iter
->second
;
329 void BackgroundSyncManager::StoreRegistrations(
331 int64 sw_registration_id
,
332 const ServiceWorkerStorage::StatusCallback
& callback
) {
333 // Serialize the data.
334 const BackgroundSyncRegistrations
& registrations
=
335 sw_to_registrations_map_
[sw_registration_id
];
336 BackgroundSyncRegistrationsProto registrations_proto
;
337 registrations_proto
.set_next_registration_id(registrations
.next_id
);
339 for (const auto& name_and_registration
:
340 registrations
.name_to_registration_map
) {
341 const BackgroundSyncRegistration
& registration
=
342 name_and_registration
.second
;
343 BackgroundSyncRegistrationProto
* registration_proto
=
344 registrations_proto
.add_registration();
345 registration_proto
->set_id(registration
.id
);
346 registration_proto
->set_name(registration
.name
);
347 registration_proto
->set_fire_once(registration
.fire_once
);
348 registration_proto
->set_min_period(registration
.min_period
);
349 registration_proto
->set_network_state(registration
.network_state
);
350 registration_proto
->set_power_state(registration
.power_state
);
352 std::string serialized
;
353 bool success
= registrations_proto
.SerializeToString(&serialized
);
356 StoreDataInBackend(sw_registration_id
, origin
, kBackgroundSyncUserDataKey
,
357 serialized
, callback
);
360 void BackgroundSyncManager::RegisterDidStore(
361 int64 sw_registration_id
,
362 const BackgroundSyncRegistration
& new_registration
,
363 const StatusAndRegistrationCallback
& callback
,
364 ServiceWorkerStatusCode status
) {
365 if (status
== SERVICE_WORKER_ERROR_NOT_FOUND
) {
366 // The registration is gone.
367 sw_to_registrations_map_
.erase(sw_registration_id
);
368 base::MessageLoop::current()->PostTask(
370 base::Bind(callback
, ERROR_TYPE_STORAGE
, BackgroundSyncRegistration()));
374 if (status
!= SERVICE_WORKER_OK
) {
375 LOG(ERROR
) << "BackgroundSync failed to store registration due to backend "
377 DisableAndClearManager(
378 base::Bind(callback
, ERROR_TYPE_STORAGE
, BackgroundSyncRegistration()));
382 // TODO(jkarlin): Run the registration algorithm.
383 base::MessageLoop::current()->PostTask(
384 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_OK
, new_registration
));
387 void BackgroundSyncManager::RemoveRegistrationFromMap(
388 int64 sw_registration_id
,
389 const std::string
& sync_registration_name
) {
391 LookupRegistration(sw_registration_id
, sync_registration_name
, nullptr));
393 BackgroundSyncRegistrations
* registrations
=
394 &sw_to_registrations_map_
[sw_registration_id
];
396 registrations
->name_to_registration_map
.erase(sync_registration_name
);
399 void BackgroundSyncManager::AddRegistrationToMap(
400 int64 sw_registration_id
,
401 const BackgroundSyncRegistration
& sync_registration
) {
402 DCHECK_NE(BackgroundSyncRegistration::kInvalidRegistrationId
,
405 BackgroundSyncRegistrations
* registrations
=
406 &sw_to_registrations_map_
[sw_registration_id
];
407 registrations
->name_to_registration_map
[sync_registration
.name
] =
411 void BackgroundSyncManager::StoreDataInBackend(
412 int64 sw_registration_id
,
414 const std::string
& key
,
415 const std::string
& data
,
416 const ServiceWorkerStorage::StatusCallback
& callback
) {
417 service_worker_context_
->context()->storage()->StoreUserData(
418 sw_registration_id
, origin
, key
, data
, callback
);
421 void BackgroundSyncManager::GetDataFromBackend(
422 const std::string
& key
,
423 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback
&
425 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
427 service_worker_context_
->context()->storage()->GetUserDataForAllRegistrations(
431 void BackgroundSyncManager::UnregisterImpl(
433 int64 sw_registration_id
,
434 const std::string
& sync_registration_name
,
435 BackgroundSyncRegistration::RegistrationId sync_registration_id
,
436 const StatusCallback
& callback
) {
438 base::MessageLoop::current()->PostTask(
439 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_STORAGE
));
443 BackgroundSyncRegistration existing_registration
;
444 if (!LookupRegistration(sw_registration_id
, sync_registration_name
,
445 &existing_registration
) ||
446 existing_registration
.id
!= sync_registration_id
) {
447 base::MessageLoop::current()->PostTask(
448 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_NOT_FOUND
));
452 RemoveRegistrationFromMap(sw_registration_id
, sync_registration_name
);
455 origin
, sw_registration_id
,
456 base::Bind(&BackgroundSyncManager::UnregisterDidStore
,
457 weak_ptr_factory_
.GetWeakPtr(), sw_registration_id
, callback
));
460 void BackgroundSyncManager::UnregisterDidStore(
461 int64 sw_registration_id
,
462 const StatusCallback
& callback
,
463 ServiceWorkerStatusCode status
) {
464 if (status
== SERVICE_WORKER_ERROR_NOT_FOUND
) {
465 // ServiceWorker was unregistered.
466 sw_to_registrations_map_
.erase(sw_registration_id
);
467 base::MessageLoop::current()->PostTask(
468 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_STORAGE
));
472 if (status
!= SERVICE_WORKER_OK
) {
473 LOG(ERROR
) << "BackgroundSync failed to unregister due to backend failure.";
474 DisableAndClearManager(base::Bind(callback
, ERROR_TYPE_STORAGE
));
478 // TODO(jkarlin): Run the registration algorithm.
479 base::MessageLoop::current()->PostTask(FROM_HERE
,
480 base::Bind(callback
, ERROR_TYPE_OK
));
483 void BackgroundSyncManager::GetRegistrationImpl(
485 int64 sw_registration_id
,
486 const std::string sync_registration_name
,
487 const StatusAndRegistrationCallback
& callback
) {
489 base::MessageLoop::current()->PostTask(
491 base::Bind(callback
, ERROR_TYPE_STORAGE
, BackgroundSyncRegistration()));
495 BackgroundSyncRegistration out_registration
;
496 if (!LookupRegistration(sw_registration_id
, sync_registration_name
,
497 &out_registration
)) {
498 base::MessageLoop::current()->PostTask(
499 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_NOT_FOUND
,
500 BackgroundSyncRegistration()));
504 base::MessageLoop::current()->PostTask(
505 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_OK
, out_registration
));
508 void BackgroundSyncManager::OnRegistrationDeletedImpl(
509 int64 registration_id
,
510 const base::Closure
& callback
) {
511 // The backend (ServiceWorkerStorage) will delete the data, so just delete the
512 // memory representation here.
513 sw_to_registrations_map_
.erase(registration_id
);
514 base::MessageLoop::current()->PostTask(FROM_HERE
, base::Bind(callback
));
517 void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure
& callback
) {
518 sw_to_registrations_map_
.clear();
523 void BackgroundSyncManager::PendingStatusAndRegistrationCallback(
524 const StatusAndRegistrationCallback
& callback
,
526 const BackgroundSyncRegistration
& sync_registration
) {
527 // The callback might delete this object, so hang onto a weak ptr to find out.
528 base::WeakPtr
<BackgroundSyncManager
> manager
= weak_ptr_factory_
.GetWeakPtr();
529 callback
.Run(error
, sync_registration
);
531 op_scheduler_
.CompleteOperationAndRunNext();
534 void BackgroundSyncManager::PendingStatusCallback(
535 const StatusCallback
& callback
,
537 // The callback might delete this object, so hang onto a weak ptr to find out.
538 base::WeakPtr
<BackgroundSyncManager
> manager
= weak_ptr_factory_
.GetWeakPtr();
541 op_scheduler_
.CompleteOperationAndRunNext();
544 void BackgroundSyncManager::PendingClosure(const base::Closure
& callback
) {
545 // The callback might delete this object, so hang onto a weak ptr to find out.
546 base::WeakPtr
<BackgroundSyncManager
> manager
= weak_ptr_factory_
.GetWeakPtr();
549 op_scheduler_
.CompleteOperationAndRunNext();
552 base::Closure
BackgroundSyncManager::MakeEmptyCompletion() {
553 return base::Bind(&BackgroundSyncManager::PendingClosure
,
554 weak_ptr_factory_
.GetWeakPtr(),
555 base::Bind(base::DoNothing
));
558 BackgroundSyncManager::StatusAndRegistrationCallback
559 BackgroundSyncManager::MakeStatusAndRegistrationCompletion(
560 const StatusAndRegistrationCallback
& callback
) {
562 &BackgroundSyncManager::PendingStatusAndRegistrationCallback
,
563 weak_ptr_factory_
.GetWeakPtr(), callback
);
566 BackgroundSyncManager::StatusCallback
567 BackgroundSyncManager::MakeStatusCompletion(const StatusCallback
& callback
) {
568 return base::Bind(&BackgroundSyncManager::PendingStatusCallback
,
569 weak_ptr_factory_
.GetWeakPtr(), callback
);
572 } // namespace content