Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / content / browser / background_sync / background_sync_manager.cc
blobd99765240d478ccee3f97b2e585a96a25dcd156b
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 "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"
13 namespace {
14 const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
17 namespace content {
19 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
20 BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId =
21 -1;
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)
32 : next_id(next_id) {
34 BackgroundSyncManager::BackgroundSyncRegistrations::
35 ~BackgroundSyncRegistrations() {
38 // static
39 scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
40 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
41 BackgroundSyncManager* sync_manager =
42 new BackgroundSyncManager(service_worker_context);
43 sync_manager->Init();
44 return make_scoped_ptr(sync_manager);
47 BackgroundSyncManager::~BackgroundSyncManager() {
48 service_worker_context_->RemoveObserver(this);
51 void BackgroundSyncManager::Register(
52 const GURL& origin,
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);
60 if (disabled_) {
61 base::MessageLoop::current()->PostTask(
62 FROM_HERE,
63 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
64 return;
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(
74 const GURL& origin,
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);
81 if (disabled_) {
82 base::MessageLoop::current()->PostTask(
83 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
84 return;
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(
94 const GURL& origin,
95 int64 sw_registration_id,
96 const std::string sync_registration_name,
97 const StatusAndRegistrationCallback& callback) {
98 DCHECK_CURRENTLY_ON(BrowserThread::IO);
100 if (disabled_) {
101 base::MessageLoop::current()->PostTask(
102 FROM_HERE,
103 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
104 return;
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),
138 disabled_(false),
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());
146 DCHECK(!disabled_);
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);
156 if (disabled_) {
157 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
158 return;
161 GetDataFromBackend(
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));
174 return;
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;
187 ++i) {
188 const BackgroundSyncRegistrationProto& registration_proto =
189 registrations_proto.registration(i);
191 if (registration_proto.id() >= registrations->next_id) {
192 corruption_detected = true;
193 break;
196 BackgroundSyncRegistration* registration =
197 &registrations->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)
209 break;
212 if (corruption_detected) {
213 LOG(ERROR) << "Corruption detected in background sync backend";
214 DisableAndClearManager(base::Bind(callback));
215 return;
218 // TODO(jkarlin): Call the scheduling algorithm here.
220 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
223 void BackgroundSyncManager::RegisterImpl(
224 const GURL& origin,
225 int64 sw_registration_id,
226 const BackgroundSyncRegistration& sync_registration,
227 const StatusAndRegistrationCallback& callback) {
228 if (disabled_) {
229 base::MessageLoop::current()->PostTask(
230 FROM_HERE,
231 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
232 return;
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(
240 FROM_HERE,
241 base::Bind(callback, ERROR_TYPE_OK, existing_registration));
242 return;
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);
253 StoreRegistrations(
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) {
262 if (disabled_) {
263 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
264 return;
267 disabled_ = true;
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.
273 GetDataFromBackend(
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));
285 return;
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())
314 return false;
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())
321 return false;
323 if (existing_registration)
324 *existing_registration = name_and_registration_iter->second;
326 return true;
329 void BackgroundSyncManager::StoreRegistrations(
330 const GURL& origin,
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);
354 DCHECK(success);
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(
369 FROM_HERE,
370 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
371 return;
374 if (status != SERVICE_WORKER_OK) {
375 LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
376 "failure.";
377 DisableAndClearManager(
378 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
379 return;
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) {
390 DCHECK(
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,
403 sw_registration_id);
405 BackgroundSyncRegistrations* registrations =
406 &sw_to_registrations_map_[sw_registration_id];
407 registrations->name_to_registration_map[sync_registration.name] =
408 sync_registration;
411 void BackgroundSyncManager::StoreDataInBackend(
412 int64 sw_registration_id,
413 const GURL& origin,
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&
424 callback) {
425 DCHECK_CURRENTLY_ON(BrowserThread::IO);
427 service_worker_context_->context()->storage()->GetUserDataForAllRegistrations(
428 key, callback);
431 void BackgroundSyncManager::UnregisterImpl(
432 const GURL& origin,
433 int64 sw_registration_id,
434 const std::string& sync_registration_name,
435 BackgroundSyncRegistration::RegistrationId sync_registration_id,
436 const StatusCallback& callback) {
437 if (disabled_) {
438 base::MessageLoop::current()->PostTask(
439 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
440 return;
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));
449 return;
452 RemoveRegistrationFromMap(sw_registration_id, sync_registration_name);
454 StoreRegistrations(
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));
469 return;
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));
475 return;
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(
484 const GURL& origin,
485 int64 sw_registration_id,
486 const std::string sync_registration_name,
487 const StatusAndRegistrationCallback& callback) {
488 if (disabled_) {
489 base::MessageLoop::current()->PostTask(
490 FROM_HERE,
491 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
492 return;
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()));
501 return;
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();
519 disabled_ = false;
520 InitImpl(callback);
523 void BackgroundSyncManager::PendingStatusAndRegistrationCallback(
524 const StatusAndRegistrationCallback& callback,
525 ErrorType error,
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);
530 if (manager)
531 op_scheduler_.CompleteOperationAndRunNext();
534 void BackgroundSyncManager::PendingStatusCallback(
535 const StatusCallback& callback,
536 ErrorType error) {
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();
539 callback.Run(error);
540 if (manager)
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();
547 callback.Run();
548 if (manager)
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) {
561 return base::Bind(
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