Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / background_sync / background_sync_manager.cc
bloba23792f161076cfa4f7ef3f3039c9a3688408ba7
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/background_sync/background_sync_network_observer.h"
10 #include "content/browser/service_worker/service_worker_context_wrapper.h"
11 #include "content/browser/service_worker/service_worker_storage.h"
12 #include "content/public/browser/browser_thread.h"
14 namespace {
15 const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData";
18 namespace content {
20 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
21 BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId =
22 -1;
24 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
25 BackgroundSyncManager::BackgroundSyncRegistration::kInitialId = 0;
27 BackgroundSyncManager::BackgroundSyncRegistrations::
28 BackgroundSyncRegistrations()
29 : next_id(BackgroundSyncRegistration::kInitialId) {
32 BackgroundSyncManager::BackgroundSyncRegistrations::
33 ~BackgroundSyncRegistrations() {
36 // static
37 scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create(
38 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) {
39 DCHECK_CURRENTLY_ON(BrowserThread::IO);
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 DCHECK_CURRENTLY_ON(BrowserThread::IO);
50 service_worker_context_->RemoveObserver(this);
53 BackgroundSyncManager::RegistrationKey::RegistrationKey(
54 const BackgroundSyncRegistration& registration)
55 : RegistrationKey(registration.tag, registration.periodicity) {
58 BackgroundSyncManager::RegistrationKey::RegistrationKey(
59 const std::string& tag,
60 SyncPeriodicity periodicity)
61 : value_(periodicity == SYNC_ONE_SHOT ? "o_" + tag : "p_" + tag) {
64 void BackgroundSyncManager::Register(
65 const GURL& origin,
66 int64 sw_registration_id,
67 const BackgroundSyncRegistration& sync_registration,
68 const StatusAndRegistrationCallback& callback) {
69 DCHECK_CURRENTLY_ON(BrowserThread::IO);
70 DCHECK_EQ(BackgroundSyncRegistration::kInvalidRegistrationId,
71 sync_registration.id);
73 if (disabled_) {
74 base::MessageLoop::current()->PostTask(
75 FROM_HERE,
76 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
77 return;
80 op_scheduler_.ScheduleOperation(base::Bind(
81 &BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(),
82 origin, sw_registration_id, sync_registration,
83 MakeStatusAndRegistrationCompletion(callback)));
86 void BackgroundSyncManager::Unregister(
87 const GURL& origin,
88 int64 sw_registration_id,
89 const std::string& sync_registration_tag,
90 SyncPeriodicity periodicity,
91 BackgroundSyncRegistration::RegistrationId sync_registration_id,
92 const StatusCallback& callback) {
93 DCHECK_CURRENTLY_ON(BrowserThread::IO);
95 if (disabled_) {
96 base::MessageLoop::current()->PostTask(
97 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
98 return;
101 RegistrationKey registration_key(sync_registration_tag, periodicity);
103 op_scheduler_.ScheduleOperation(base::Bind(
104 &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(),
105 origin, sw_registration_id, registration_key, sync_registration_id,
106 MakeStatusCompletion(callback)));
109 void BackgroundSyncManager::GetRegistration(
110 const GURL& origin,
111 int64 sw_registration_id,
112 const std::string sync_registration_tag,
113 SyncPeriodicity periodicity,
114 const StatusAndRegistrationCallback& callback) {
115 DCHECK_CURRENTLY_ON(BrowserThread::IO);
117 if (disabled_) {
118 base::MessageLoop::current()->PostTask(
119 FROM_HERE,
120 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
121 return;
124 RegistrationKey registration_key(sync_registration_tag, periodicity);
126 op_scheduler_.ScheduleOperation(base::Bind(
127 &BackgroundSyncManager::GetRegistrationImpl,
128 weak_ptr_factory_.GetWeakPtr(), origin, sw_registration_id,
129 registration_key, MakeStatusAndRegistrationCompletion(callback)));
132 void BackgroundSyncManager::OnRegistrationDeleted(int64 registration_id,
133 const GURL& pattern) {
134 DCHECK_CURRENTLY_ON(BrowserThread::IO);
136 // Operations already in the queue will either fail when they write to storage
137 // or return stale results based on registrations loaded in memory. This is
138 // inconsequential since the service worker is gone.
139 op_scheduler_.ScheduleOperation(base::Bind(
140 &BackgroundSyncManager::OnRegistrationDeletedImpl,
141 weak_ptr_factory_.GetWeakPtr(), registration_id, MakeEmptyCompletion()));
144 void BackgroundSyncManager::OnStorageWiped() {
145 DCHECK_CURRENTLY_ON(BrowserThread::IO);
146 // Operations already in the queue will either fail when they write to storage
147 // or return stale results based on registrations loaded in memory. This is
148 // inconsequential since the service workers are gone.
149 op_scheduler_.ScheduleOperation(
150 base::Bind(&BackgroundSyncManager::OnStorageWipedImpl,
151 weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion()));
154 BackgroundSyncManager::BackgroundSyncManager(
155 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
156 : service_worker_context_(service_worker_context),
157 disabled_(false),
158 weak_ptr_factory_(this) {
159 DCHECK_CURRENTLY_ON(BrowserThread::IO);
161 service_worker_context_->AddObserver(this);
163 network_observer_.reset(new BackgroundSyncNetworkObserver(
164 base::Bind(&BackgroundSyncManager::OnNetworkChanged,
165 weak_ptr_factory_.GetWeakPtr())));
168 void BackgroundSyncManager::Init() {
169 DCHECK_CURRENTLY_ON(BrowserThread::IO);
170 DCHECK(!op_scheduler_.ScheduledOperations());
171 DCHECK(!disabled_);
173 op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl,
174 weak_ptr_factory_.GetWeakPtr(),
175 MakeEmptyCompletion()));
178 void BackgroundSyncManager::InitImpl(const base::Closure& callback) {
179 DCHECK_CURRENTLY_ON(BrowserThread::IO);
181 if (disabled_) {
182 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
183 return;
186 GetDataFromBackend(
187 kBackgroundSyncUserDataKey,
188 base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend,
189 weak_ptr_factory_.GetWeakPtr(), callback));
192 void BackgroundSyncManager::InitDidGetDataFromBackend(
193 const base::Closure& callback,
194 const std::vector<std::pair<int64, std::string>>& user_data,
195 ServiceWorkerStatusCode status) {
196 if (status != SERVICE_WORKER_OK && status != SERVICE_WORKER_ERROR_NOT_FOUND) {
197 LOG(ERROR) << "BackgroundSync failed to init due to backend failure.";
198 DisableAndClearManager(base::Bind(callback));
199 return;
202 bool corruption_detected = false;
203 for (const std::pair<int64, std::string>& data : user_data) {
204 BackgroundSyncRegistrationsProto registrations_proto;
205 if (registrations_proto.ParseFromString(data.second)) {
206 BackgroundSyncRegistrations* registrations =
207 &sw_to_registrations_map_[data.first];
208 registrations->next_id = registrations_proto.next_registration_id();
209 registrations->origin = GURL(registrations_proto.origin());
211 for (int i = 0, max = registrations_proto.registration_size(); i < max;
212 ++i) {
213 const BackgroundSyncRegistrationProto& registration_proto =
214 registrations_proto.registration(i);
216 if (registration_proto.id() >= registrations->next_id) {
217 corruption_detected = true;
218 break;
221 RegistrationKey registration_key(registration_proto.tag(),
222 registration_proto.periodicity());
223 BackgroundSyncRegistration* registration =
224 &registrations->registration_map[registration_key];
226 registration->id = registration_proto.id();
227 registration->tag = registration_proto.tag();
228 registration->periodicity = registration_proto.periodicity();
229 registration->min_period = registration_proto.min_period();
230 registration->network_state = registration_proto.network_state();
231 registration->power_state = registration_proto.power_state();
235 if (corruption_detected)
236 break;
239 if (corruption_detected) {
240 LOG(ERROR) << "Corruption detected in background sync backend";
241 DisableAndClearManager(base::Bind(callback));
242 return;
245 // TODO(jkarlin): Call the scheduling algorithm here.
247 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
250 void BackgroundSyncManager::RegisterImpl(
251 const GURL& origin,
252 int64 sw_registration_id,
253 const BackgroundSyncRegistration& sync_registration,
254 const StatusAndRegistrationCallback& callback) {
255 if (disabled_) {
256 base::MessageLoop::current()->PostTask(
257 FROM_HERE,
258 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
259 return;
262 const BackgroundSyncRegistration* existing_registration = LookupRegistration(
263 sw_registration_id, RegistrationKey(sync_registration));
264 if (existing_registration &&
265 existing_registration->Equals(sync_registration)) {
266 base::MessageLoop::current()->PostTask(
267 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *existing_registration));
268 return;
271 BackgroundSyncRegistration new_registration = sync_registration;
272 BackgroundSyncRegistrations* registrations =
273 &sw_to_registrations_map_[sw_registration_id];
274 new_registration.id = registrations->next_id++;
276 AddRegistrationToMap(sw_registration_id, origin, new_registration);
278 StoreRegistrations(
279 sw_registration_id,
280 base::Bind(&BackgroundSyncManager::RegisterDidStore,
281 weak_ptr_factory_.GetWeakPtr(), sw_registration_id,
282 new_registration, callback));
285 void BackgroundSyncManager::DisableAndClearManager(
286 const base::Closure& callback) {
287 if (disabled_) {
288 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
289 return;
292 disabled_ = true;
293 sw_to_registrations_map_.clear();
295 // Delete all backend entries. The memory representation of registered syncs
296 // may be out of sync with storage (e.g., due to corruption detection on
297 // loading from storage), so reload the registrations from storage again.
298 GetDataFromBackend(
299 kBackgroundSyncUserDataKey,
300 base::Bind(&BackgroundSyncManager::DisableAndClearDidGetRegistrations,
301 weak_ptr_factory_.GetWeakPtr(), callback));
304 void BackgroundSyncManager::DisableAndClearDidGetRegistrations(
305 const base::Closure& callback,
306 const std::vector<std::pair<int64, std::string>>& user_data,
307 ServiceWorkerStatusCode status) {
308 if (status != SERVICE_WORKER_OK || user_data.empty()) {
309 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
310 return;
313 base::Closure barrier_closure =
314 base::BarrierClosure(user_data.size(), base::Bind(callback));
316 for (const auto& sw_id_and_regs : user_data) {
317 service_worker_context_->ClearRegistrationUserData(
318 sw_id_and_regs.first, kBackgroundSyncUserDataKey,
319 base::Bind(&BackgroundSyncManager::DisableAndClearManagerClearedOne,
320 weak_ptr_factory_.GetWeakPtr(), barrier_closure));
324 void BackgroundSyncManager::DisableAndClearManagerClearedOne(
325 const base::Closure& barrier_closure,
326 ServiceWorkerStatusCode status) {
327 // The status doesn't matter at this point, there is nothing else to be done.
328 base::MessageLoop::current()->PostTask(FROM_HERE,
329 base::Bind(barrier_closure));
332 BackgroundSyncManager::BackgroundSyncRegistration*
333 BackgroundSyncManager::LookupRegistration(
334 int64 sw_registration_id,
335 const RegistrationKey& registration_key) {
336 SWIdToRegistrationsMap::iterator it =
337 sw_to_registrations_map_.find(sw_registration_id);
338 if (it == sw_to_registrations_map_.end())
339 return nullptr;
341 BackgroundSyncRegistrations& registrations = it->second;
342 DCHECK_LE(BackgroundSyncRegistration::kInitialId, registrations.next_id);
343 DCHECK(!registrations.origin.is_empty());
345 auto key_and_registration_iter =
346 registrations.registration_map.find(registration_key);
347 if (key_and_registration_iter == registrations.registration_map.end())
348 return nullptr;
350 return &key_and_registration_iter->second;
353 void BackgroundSyncManager::StoreRegistrations(
354 int64 sw_registration_id,
355 const ServiceWorkerStorage::StatusCallback& callback) {
356 // Serialize the data.
357 const BackgroundSyncRegistrations& registrations =
358 sw_to_registrations_map_[sw_registration_id];
359 BackgroundSyncRegistrationsProto registrations_proto;
360 registrations_proto.set_next_registration_id(registrations.next_id);
361 registrations_proto.set_origin(registrations.origin.spec());
363 for (const auto& key_and_registration : registrations.registration_map) {
364 const BackgroundSyncRegistration& registration =
365 key_and_registration.second;
366 BackgroundSyncRegistrationProto* registration_proto =
367 registrations_proto.add_registration();
368 registration_proto->set_id(registration.id);
369 registration_proto->set_tag(registration.tag);
370 registration_proto->set_periodicity(registration.periodicity);
371 registration_proto->set_min_period(registration.min_period);
372 registration_proto->set_network_state(registration.network_state);
373 registration_proto->set_power_state(registration.power_state);
375 std::string serialized;
376 bool success = registrations_proto.SerializeToString(&serialized);
377 DCHECK(success);
379 StoreDataInBackend(sw_registration_id, registrations.origin,
380 kBackgroundSyncUserDataKey, serialized, callback);
383 void BackgroundSyncManager::RegisterDidStore(
384 int64 sw_registration_id,
385 const BackgroundSyncRegistration& new_registration,
386 const StatusAndRegistrationCallback& callback,
387 ServiceWorkerStatusCode status) {
388 if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
389 // The registration is gone.
390 sw_to_registrations_map_.erase(sw_registration_id);
391 base::MessageLoop::current()->PostTask(
392 FROM_HERE,
393 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
394 return;
397 if (status != SERVICE_WORKER_OK) {
398 LOG(ERROR) << "BackgroundSync failed to store registration due to backend "
399 "failure.";
400 DisableAndClearManager(
401 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
402 return;
405 // TODO(jkarlin): Run the registration algorithm.
406 base::MessageLoop::current()->PostTask(
407 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration));
410 void BackgroundSyncManager::RemoveRegistrationFromMap(
411 int64 sw_registration_id,
412 const RegistrationKey& registration_key) {
413 DCHECK(LookupRegistration(sw_registration_id, registration_key));
415 BackgroundSyncRegistrations* registrations =
416 &sw_to_registrations_map_[sw_registration_id];
418 registrations->registration_map.erase(registration_key);
421 void BackgroundSyncManager::AddRegistrationToMap(
422 int64 sw_registration_id,
423 const GURL& origin,
424 const BackgroundSyncRegistration& sync_registration) {
425 DCHECK_NE(BackgroundSyncRegistration::kInvalidRegistrationId,
426 sw_registration_id);
428 BackgroundSyncRegistrations* registrations =
429 &sw_to_registrations_map_[sw_registration_id];
430 registrations->origin = origin;
432 RegistrationKey registration_key(sync_registration);
433 registrations->registration_map[registration_key] = sync_registration;
436 void BackgroundSyncManager::StoreDataInBackend(
437 int64 sw_registration_id,
438 const GURL& origin,
439 const std::string& backend_key,
440 const std::string& data,
441 const ServiceWorkerStorage::StatusCallback& callback) {
442 service_worker_context_->StoreRegistrationUserData(
443 sw_registration_id, origin, backend_key, data, callback);
446 void BackgroundSyncManager::GetDataFromBackend(
447 const std::string& backend_key,
448 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback&
449 callback) {
450 DCHECK_CURRENTLY_ON(BrowserThread::IO);
452 service_worker_context_->GetUserDataForAllRegistrations(backend_key,
453 callback);
456 void BackgroundSyncManager::UnregisterImpl(
457 const GURL& origin,
458 int64 sw_registration_id,
459 const RegistrationKey& registration_key,
460 BackgroundSyncRegistration::RegistrationId sync_registration_id,
461 const StatusCallback& callback) {
462 if (disabled_) {
463 base::MessageLoop::current()->PostTask(
464 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
465 return;
468 const BackgroundSyncRegistration* existing_registration =
469 LookupRegistration(sw_registration_id, registration_key);
470 if (!existing_registration ||
471 existing_registration->id != sync_registration_id) {
472 base::MessageLoop::current()->PostTask(
473 FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND));
474 return;
477 RemoveRegistrationFromMap(sw_registration_id, registration_key);
479 StoreRegistrations(
480 sw_registration_id,
481 base::Bind(&BackgroundSyncManager::UnregisterDidStore,
482 weak_ptr_factory_.GetWeakPtr(), sw_registration_id, callback));
485 void BackgroundSyncManager::UnregisterDidStore(
486 int64 sw_registration_id,
487 const StatusCallback& callback,
488 ServiceWorkerStatusCode status) {
489 if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
490 // ServiceWorker was unregistered.
491 sw_to_registrations_map_.erase(sw_registration_id);
492 base::MessageLoop::current()->PostTask(
493 FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
494 return;
497 if (status != SERVICE_WORKER_OK) {
498 LOG(ERROR) << "BackgroundSync failed to unregister due to backend failure.";
499 DisableAndClearManager(base::Bind(callback, ERROR_TYPE_STORAGE));
500 return;
503 // TODO(jkarlin): Run the registration algorithm.
504 base::MessageLoop::current()->PostTask(FROM_HERE,
505 base::Bind(callback, ERROR_TYPE_OK));
508 void BackgroundSyncManager::GetRegistrationImpl(
509 const GURL& origin,
510 int64 sw_registration_id,
511 const RegistrationKey& registration_key,
512 const StatusAndRegistrationCallback& callback) {
513 if (disabled_) {
514 base::MessageLoop::current()->PostTask(
515 FROM_HERE,
516 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
517 return;
520 const BackgroundSyncRegistration* out_registration =
521 LookupRegistration(sw_registration_id, registration_key);
522 if (!out_registration) {
523 base::MessageLoop::current()->PostTask(
524 FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND,
525 BackgroundSyncRegistration()));
526 return;
529 base::MessageLoop::current()->PostTask(
530 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *out_registration));
533 void BackgroundSyncManager::OnRegistrationDeletedImpl(
534 int64 registration_id,
535 const base::Closure& callback) {
536 // The backend (ServiceWorkerStorage) will delete the data, so just delete the
537 // memory representation here.
538 sw_to_registrations_map_.erase(registration_id);
539 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
542 void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) {
543 sw_to_registrations_map_.clear();
544 disabled_ = false;
545 InitImpl(callback);
548 void BackgroundSyncManager::OnNetworkChanged() {
549 // TODO(jkarlin): Run the scheduling algorithm here if initialized and not
550 // disabled.
553 void BackgroundSyncManager::PendingStatusAndRegistrationCallback(
554 const StatusAndRegistrationCallback& callback,
555 ErrorType error,
556 const BackgroundSyncRegistration& sync_registration) {
557 // The callback might delete this object, so hang onto a weak ptr to find out.
558 base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr();
559 callback.Run(error, sync_registration);
560 if (manager)
561 op_scheduler_.CompleteOperationAndRunNext();
564 void BackgroundSyncManager::PendingStatusCallback(
565 const StatusCallback& callback,
566 ErrorType error) {
567 // The callback might delete this object, so hang onto a weak ptr to find out.
568 base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr();
569 callback.Run(error);
570 if (manager)
571 op_scheduler_.CompleteOperationAndRunNext();
574 void BackgroundSyncManager::PendingClosure(const base::Closure& callback) {
575 // The callback might delete this object, so hang onto a weak ptr to find out.
576 base::WeakPtr<BackgroundSyncManager> manager = weak_ptr_factory_.GetWeakPtr();
577 callback.Run();
578 if (manager)
579 op_scheduler_.CompleteOperationAndRunNext();
582 base::Closure BackgroundSyncManager::MakeEmptyCompletion() {
583 return base::Bind(&BackgroundSyncManager::PendingClosure,
584 weak_ptr_factory_.GetWeakPtr(),
585 base::Bind(base::DoNothing));
588 BackgroundSyncManager::StatusAndRegistrationCallback
589 BackgroundSyncManager::MakeStatusAndRegistrationCompletion(
590 const StatusAndRegistrationCallback& callback) {
591 return base::Bind(
592 &BackgroundSyncManager::PendingStatusAndRegistrationCallback,
593 weak_ptr_factory_.GetWeakPtr(), callback);
596 BackgroundSyncManager::StatusCallback
597 BackgroundSyncManager::MakeStatusCompletion(const StatusCallback& callback) {
598 return base::Bind(&BackgroundSyncManager::PendingStatusCallback,
599 weak_ptr_factory_.GetWeakPtr(), callback);
602 } // namespace content