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/background_sync/background_sync.pb.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"
15 const char kBackgroundSyncUserDataKey
[] = "BackgroundSyncUserData";
20 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
21 BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId
=
24 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId
25 BackgroundSyncManager::BackgroundSyncRegistrations::kInitialId
= 0;
27 BackgroundSyncManager::BackgroundSyncRegistrations::
28 BackgroundSyncRegistrations()
29 : next_id(kInitialId
) {
31 BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations(
32 BackgroundSyncRegistration::RegistrationId next_id
)
35 BackgroundSyncManager::BackgroundSyncRegistrations::
36 ~BackgroundSyncRegistrations() {
40 scoped_ptr
<BackgroundSyncManager
> BackgroundSyncManager::Create(
41 const scoped_refptr
<ServiceWorkerContextWrapper
>& service_worker_context
) {
42 BackgroundSyncManager
* sync_manager
=
43 new BackgroundSyncManager(service_worker_context
);
45 return make_scoped_ptr(sync_manager
);
48 BackgroundSyncManager::~BackgroundSyncManager() {
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
);
60 StatusAndRegistrationCallback pending_callback
=
61 base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback
,
62 weak_ptr_factory_
.GetWeakPtr(), callback
);
64 op_scheduler_
.ScheduleOperation(base::Bind(
65 &BackgroundSyncManager::RegisterImpl
, weak_ptr_factory_
.GetWeakPtr(),
66 origin
, sw_registration_id
, sync_registration
, pending_callback
));
69 void BackgroundSyncManager::Unregister(
71 int64 sw_registration_id
,
72 const std::string
& sync_registration_name
,
73 BackgroundSyncRegistration::RegistrationId sync_registration_id
,
74 const StatusCallback
& callback
) {
75 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
77 StatusCallback pending_callback
=
78 base::Bind(&BackgroundSyncManager::PendingStatusCallback
,
79 weak_ptr_factory_
.GetWeakPtr(), callback
);
81 op_scheduler_
.ScheduleOperation(base::Bind(
82 &BackgroundSyncManager::UnregisterImpl
, weak_ptr_factory_
.GetWeakPtr(),
83 origin
, sw_registration_id
, sync_registration_name
, sync_registration_id
,
87 void BackgroundSyncManager::GetRegistration(
89 int64 sw_registration_id
,
90 const std::string sync_registration_name
,
91 const StatusAndRegistrationCallback
& callback
) {
92 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
94 StatusAndRegistrationCallback pending_callback
=
95 base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback
,
96 weak_ptr_factory_
.GetWeakPtr(), callback
);
98 op_scheduler_
.ScheduleOperation(
99 base::Bind(&BackgroundSyncManager::GetRegistrationImpl
,
100 weak_ptr_factory_
.GetWeakPtr(), origin
, sw_registration_id
,
101 sync_registration_name
, pending_callback
));
104 BackgroundSyncManager::BackgroundSyncManager(
105 const scoped_refptr
<ServiceWorkerContextWrapper
>& service_worker_context
)
106 : service_worker_context_(service_worker_context
), weak_ptr_factory_(this) {
109 void BackgroundSyncManager::Init() {
110 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
111 DCHECK(!op_scheduler_
.ScheduledOperations());
113 op_scheduler_
.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl
,
114 weak_ptr_factory_
.GetWeakPtr()));
117 void BackgroundSyncManager::InitImpl() {
118 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
121 kBackgroundSyncUserDataKey
,
122 base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend
,
123 weak_ptr_factory_
.GetWeakPtr()));
126 void BackgroundSyncManager::InitDidGetDataFromBackend(
127 const std::vector
<std::pair
<int64
, std::string
>>& user_data
,
128 ServiceWorkerStatusCode status
) {
129 if (status
!= SERVICE_WORKER_OK
&& status
!= SERVICE_WORKER_ERROR_NOT_FOUND
)
130 LOG(ERROR
) << "Background Sync Failed to load from backend.";
132 bool corruption_detected
= false;
133 for (const std::pair
<int64
, std::string
>& data
: user_data
) {
134 BackgroundSyncRegistrationsProto registrations_proto
;
135 if (registrations_proto
.ParseFromString(data
.second
)) {
136 sw_to_registrations_map_
[data
.first
] = BackgroundSyncRegistrations(
137 registrations_proto
.next_registration_id());
138 BackgroundSyncRegistrations
* registrations
=
139 &sw_to_registrations_map_
[data
.first
];
141 for (int i
= 0, max
= registrations_proto
.registration_size(); i
< max
;
143 const BackgroundSyncRegistrationProto
& registration_proto
=
144 registrations_proto
.registration(i
);
146 if (registration_proto
.id() >= registrations
->next_id
) {
147 corruption_detected
= true;
151 BackgroundSyncRegistration
registration(registration_proto
.id(),
152 registration_proto
.name());
153 if (registration_proto
.has_min_period())
154 registration
.min_period
= registration_proto
.min_period();
155 registrations
->name_to_registration_map
[registration_proto
.name()] =
160 if (corruption_detected
)
164 if (corruption_detected
) {
165 LOG(ERROR
) << "Corruption detected in background sync backend";
166 sw_to_registrations_map_
.clear();
169 // TODO(jkarlin): Call the scheduling algorithm here.
171 op_scheduler_
.CompleteOperationAndRunNext();
174 void BackgroundSyncManager::RegisterImpl(
176 int64 sw_registration_id
,
177 const BackgroundSyncRegistration
& sync_registration
,
178 const StatusAndRegistrationCallback
& callback
) {
179 BackgroundSyncRegistration existing_registration
;
180 if (LookupRegistration(sw_registration_id
, sync_registration
.name
,
181 &existing_registration
)) {
182 if (existing_registration
.Equals(sync_registration
)) {
183 base::MessageLoop::current()->PostTask(
185 base::Bind(callback
, ERROR_TYPE_OK
, existing_registration
));
190 BackgroundSyncRegistration new_registration
= sync_registration
;
191 BackgroundSyncRegistrations
* registrations
=
192 &sw_to_registrations_map_
[sw_registration_id
];
193 new_registration
.id
= registrations
->next_id
++;
195 AddRegistrationToMap(sw_registration_id
, new_registration
);
198 origin
, sw_registration_id
,
199 base::Bind(&BackgroundSyncManager::RegisterDidStore
,
200 weak_ptr_factory_
.GetWeakPtr(), sw_registration_id
,
201 new_registration
, existing_registration
, callback
));
204 bool BackgroundSyncManager::LookupRegistration(
205 int64 sw_registration_id
,
206 const std::string
& sync_registration_name
,
207 BackgroundSyncRegistration
* existing_registration
) {
208 SWIdToRegistrationsMap::iterator it
=
209 sw_to_registrations_map_
.find(sw_registration_id
);
210 if (it
== sw_to_registrations_map_
.end())
213 const BackgroundSyncRegistrations
& registrations
= it
->second
;
214 const auto name_and_registration_iter
=
215 registrations
.name_to_registration_map
.find(sync_registration_name
);
216 if (name_and_registration_iter
==
217 registrations
.name_to_registration_map
.end())
220 if (existing_registration
)
221 *existing_registration
= name_and_registration_iter
->second
;
226 void BackgroundSyncManager::StoreRegistrations(
228 int64 sw_registration_id
,
229 const ServiceWorkerStorage::StatusCallback
& callback
) {
230 // Serialize the data.
231 const BackgroundSyncRegistrations
& registrations
=
232 sw_to_registrations_map_
[sw_registration_id
];
233 BackgroundSyncRegistrationsProto registrations_proto
;
234 registrations_proto
.set_next_registration_id(registrations
.next_id
);
236 for (const auto& name_and_registration
:
237 registrations
.name_to_registration_map
) {
238 const BackgroundSyncRegistration
& registration
=
239 name_and_registration
.second
;
240 BackgroundSyncRegistrationProto
* registration_proto
=
241 registrations_proto
.add_registration();
242 registration_proto
->set_id(registration
.id
);
243 registration_proto
->set_name(registration
.name
);
244 if (registration
.min_period
!= 0)
245 registration_proto
->set_min_period(registration
.min_period
);
247 std::string serialized
;
248 bool success
= registrations_proto
.SerializeToString(&serialized
);
251 StoreDataInBackend(sw_registration_id
, origin
, kBackgroundSyncUserDataKey
,
252 serialized
, callback
);
255 void BackgroundSyncManager::RegisterDidStore(
256 int64 sw_registration_id
,
257 const BackgroundSyncRegistration
& new_registration
,
258 const BackgroundSyncRegistration
& previous_registration
,
259 const StatusAndRegistrationCallback
& callback
,
260 ServiceWorkerStatusCode status
) {
261 if (status
!= SERVICE_WORKER_OK
) {
262 // Restore the previous state.
263 if (previous_registration
.id
!=
264 BackgroundSyncRegistration::kInvalidRegistrationId
) {
265 AddRegistrationToMap(sw_registration_id
, previous_registration
);
267 RemoveRegistrationFromMap(sw_registration_id
, new_registration
.name
,
270 base::MessageLoop::current()->PostTask(
272 base::Bind(callback
, ERROR_TYPE_STORAGE
, BackgroundSyncRegistration()));
276 // TODO(jkarlin): Run the registration algorithm.
277 base::MessageLoop::current()->PostTask(
278 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_OK
, new_registration
));
281 void BackgroundSyncManager::RemoveRegistrationFromMap(
282 int64 sw_registration_id
,
283 const std::string
& sync_registration_name
,
284 BackgroundSyncRegistration
* old_registration
) {
286 LookupRegistration(sw_registration_id
, sync_registration_name
, nullptr));
288 BackgroundSyncRegistrations
* registrations
=
289 &sw_to_registrations_map_
[sw_registration_id
];
291 const auto name_and_registration_iter
=
292 registrations
->name_to_registration_map
.find(sync_registration_name
);
293 if (old_registration
)
294 *old_registration
= name_and_registration_iter
->second
;
296 registrations
->name_to_registration_map
.erase(name_and_registration_iter
);
299 void BackgroundSyncManager::AddRegistrationToMap(
300 int64 sw_registration_id
,
301 const BackgroundSyncRegistration
& sync_registration
) {
302 DCHECK_NE(BackgroundSyncRegistration::kInvalidRegistrationId
,
305 BackgroundSyncRegistrations
* registrations
=
306 &sw_to_registrations_map_
[sw_registration_id
];
307 registrations
->name_to_registration_map
[sync_registration
.name
] =
311 void BackgroundSyncManager::StoreDataInBackend(
312 int64 sw_registration_id
,
314 const std::string
& key
,
315 const std::string
& data
,
316 const ServiceWorkerStorage::StatusCallback
& callback
) {
317 service_worker_context_
->context()->storage()->StoreUserData(
318 sw_registration_id
, origin
, key
, data
, callback
);
321 void BackgroundSyncManager::GetDataFromBackend(
322 const std::string
& key
,
323 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback
&
325 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
327 service_worker_context_
->context()->storage()->GetUserDataForAllRegistrations(
331 void BackgroundSyncManager::UnregisterImpl(
333 int64 sw_registration_id
,
334 const std::string
& sync_registration_name
,
335 BackgroundSyncRegistration::RegistrationId sync_registration_id
,
336 const StatusCallback
& callback
) {
337 BackgroundSyncRegistration existing_registration
;
338 if (!LookupRegistration(sw_registration_id
, sync_registration_name
,
339 &existing_registration
) ||
340 existing_registration
.id
!= sync_registration_id
) {
341 base::MessageLoop::current()->PostTask(
342 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_NOT_FOUND
));
346 BackgroundSyncRegistration old_sync_registration
;
347 RemoveRegistrationFromMap(sw_registration_id
, sync_registration_name
,
348 &old_sync_registration
);
351 origin
, sw_registration_id
,
352 base::Bind(&BackgroundSyncManager::UnregisterDidStore
,
353 weak_ptr_factory_
.GetWeakPtr(), sw_registration_id
,
354 old_sync_registration
, callback
));
357 void BackgroundSyncManager::UnregisterDidStore(
358 int64 sw_registration_id
,
359 const BackgroundSyncRegistration
& old_sync_registration
,
360 const StatusCallback
& callback
,
361 ServiceWorkerStatusCode status
) {
362 if (status
!= SERVICE_WORKER_OK
) {
363 // Restore the previous state.
364 AddRegistrationToMap(sw_registration_id
, old_sync_registration
);
365 base::MessageLoop::current()->PostTask(
366 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_STORAGE
));
370 // TODO(jkarlin): Run the registration algorithm.
371 base::MessageLoop::current()->PostTask(FROM_HERE
,
372 base::Bind(callback
, ERROR_TYPE_OK
));
375 void BackgroundSyncManager::GetRegistrationImpl(
377 int64 sw_registration_id
,
378 const std::string sync_registration_name
,
379 const StatusAndRegistrationCallback
& callback
) {
380 BackgroundSyncRegistration out_registration
;
381 if (!LookupRegistration(sw_registration_id
, sync_registration_name
,
382 &out_registration
)) {
383 base::MessageLoop::current()->PostTask(
384 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_NOT_FOUND
,
385 BackgroundSyncRegistration()));
389 base::MessageLoop::current()->PostTask(
390 FROM_HERE
, base::Bind(callback
, ERROR_TYPE_OK
, out_registration
));
393 void BackgroundSyncManager::PendingStatusAndRegistrationCallback(
394 const StatusAndRegistrationCallback
& callback
,
396 const BackgroundSyncRegistration
& sync_registration
) {
397 // The callback might delete this object, so hang onto a weak ptr to find out.
398 base::WeakPtr
<BackgroundSyncManager
> manager
= weak_ptr_factory_
.GetWeakPtr();
399 callback
.Run(error
, sync_registration
);
401 op_scheduler_
.CompleteOperationAndRunNext();
404 void BackgroundSyncManager::PendingStatusCallback(
405 const StatusCallback
& callback
,
407 // The callback might delete this object, so hang onto a weak ptr to find out.
408 base::WeakPtr
<BackgroundSyncManager
> manager
= weak_ptr_factory_
.GetWeakPtr();
411 op_scheduler_
.CompleteOperationAndRunNext();
414 } // namespace content