OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "content/browser/background_sync/background_sync_manager.h" |
| 6 |
| 7 #include "base/barrier_closure.h" |
| 8 #include "base/bind.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" |
| 13 |
| 14 namespace { |
| 15 const char kBackgroundSyncUserDataKey[] = "BackgroundSyncUserData"; |
| 16 } |
| 17 |
| 18 namespace content { |
| 19 |
| 20 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId |
| 21 BackgroundSyncManager::BackgroundSyncRegistration::kInvalidRegistrationId = |
| 22 -1; |
| 23 |
| 24 const BackgroundSyncManager::BackgroundSyncRegistration::RegistrationId |
| 25 BackgroundSyncManager::BackgroundSyncRegistrations::kInitialId = 0; |
| 26 |
| 27 BackgroundSyncManager::BackgroundSyncRegistrations:: |
| 28 BackgroundSyncRegistrations() |
| 29 : next_id(kInitialId) { |
| 30 } |
| 31 BackgroundSyncManager::BackgroundSyncRegistrations::BackgroundSyncRegistrations( |
| 32 BackgroundSyncRegistration::RegistrationId next_id) |
| 33 : next_id(next_id) { |
| 34 } |
| 35 BackgroundSyncManager::BackgroundSyncRegistrations:: |
| 36 ~BackgroundSyncRegistrations() { |
| 37 } |
| 38 |
| 39 // static |
| 40 scoped_ptr<BackgroundSyncManager> BackgroundSyncManager::Create( |
| 41 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) { |
| 42 BackgroundSyncManager* sync_manager = |
| 43 new BackgroundSyncManager(service_worker_context); |
| 44 sync_manager->Init(); |
| 45 return make_scoped_ptr(sync_manager); |
| 46 } |
| 47 |
| 48 BackgroundSyncManager::~BackgroundSyncManager() { |
| 49 } |
| 50 |
| 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); |
| 59 |
| 60 StatusAndRegistrationCallback pending_callback = |
| 61 base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback, |
| 62 weak_ptr_factory_.GetWeakPtr(), callback); |
| 63 |
| 64 op_scheduler_.ScheduleOperation(base::Bind( |
| 65 &BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(), |
| 66 origin, sw_registration_id, sync_registration, pending_callback)); |
| 67 } |
| 68 |
| 69 void BackgroundSyncManager::Unregister( |
| 70 const GURL& origin, |
| 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); |
| 76 |
| 77 StatusCallback pending_callback = |
| 78 base::Bind(&BackgroundSyncManager::PendingStatusCallback, |
| 79 weak_ptr_factory_.GetWeakPtr(), callback); |
| 80 |
| 81 op_scheduler_.ScheduleOperation(base::Bind( |
| 82 &BackgroundSyncManager::UnregisterImpl, weak_ptr_factory_.GetWeakPtr(), |
| 83 origin, sw_registration_id, sync_registration_name, sync_registration_id, |
| 84 pending_callback)); |
| 85 } |
| 86 |
| 87 void BackgroundSyncManager::GetRegistration( |
| 88 const GURL& origin, |
| 89 int64 sw_registration_id, |
| 90 const std::string sync_registration_name, |
| 91 const StatusAndRegistrationCallback& callback) { |
| 92 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 93 |
| 94 StatusAndRegistrationCallback pending_callback = |
| 95 base::Bind(&BackgroundSyncManager::PendingStatusAndRegistrationCallback, |
| 96 weak_ptr_factory_.GetWeakPtr(), callback); |
| 97 |
| 98 op_scheduler_.ScheduleOperation( |
| 99 base::Bind(&BackgroundSyncManager::GetRegistrationImpl, |
| 100 weak_ptr_factory_.GetWeakPtr(), origin, sw_registration_id, |
| 101 sync_registration_name, pending_callback)); |
| 102 } |
| 103 |
| 104 BackgroundSyncManager::BackgroundSyncManager( |
| 105 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) |
| 106 : service_worker_context_(service_worker_context), weak_ptr_factory_(this) { |
| 107 } |
| 108 |
| 109 void BackgroundSyncManager::Init() { |
| 110 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 111 DCHECK(!op_scheduler_.ScheduledOperations()); |
| 112 |
| 113 op_scheduler_.ScheduleOperation(base::Bind(&BackgroundSyncManager::InitImpl, |
| 114 weak_ptr_factory_.GetWeakPtr())); |
| 115 } |
| 116 |
| 117 void BackgroundSyncManager::InitImpl() { |
| 118 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 119 |
| 120 GetDataFromBackend( |
| 121 kBackgroundSyncUserDataKey, |
| 122 base::Bind(&BackgroundSyncManager::InitDidGetDataFromBackend, |
| 123 weak_ptr_factory_.GetWeakPtr())); |
| 124 } |
| 125 |
| 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."; |
| 131 |
| 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]; |
| 140 |
| 141 for (int i = 0, max = registrations_proto.registration_size(); i < max; |
| 142 ++i) { |
| 143 const BackgroundSyncRegistrationProto& registration_proto = |
| 144 registrations_proto.registration(i); |
| 145 |
| 146 if (registration_proto.id() >= registrations->next_id) { |
| 147 corruption_detected = true; |
| 148 break; |
| 149 } |
| 150 |
| 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()] = |
| 156 registration; |
| 157 } |
| 158 } |
| 159 |
| 160 if (corruption_detected) |
| 161 break; |
| 162 } |
| 163 |
| 164 if (corruption_detected) { |
| 165 LOG(ERROR) << "Corruption detected in background sync backend"; |
| 166 sw_to_registrations_map_.clear(); |
| 167 } |
| 168 |
| 169 // TODO(jkarlin): Call the scheduling algorithm here. |
| 170 |
| 171 op_scheduler_.CompleteOperationAndRunNext(); |
| 172 } |
| 173 |
| 174 void BackgroundSyncManager::RegisterImpl( |
| 175 const GURL& origin, |
| 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( |
| 184 FROM_HERE, |
| 185 base::Bind(callback, ERROR_TYPE_OK, existing_registration)); |
| 186 return; |
| 187 } |
| 188 } |
| 189 |
| 190 BackgroundSyncRegistration new_registration = sync_registration; |
| 191 BackgroundSyncRegistrations* registrations = |
| 192 &sw_to_registrations_map_[sw_registration_id]; |
| 193 new_registration.id = registrations->next_id++; |
| 194 |
| 195 AddRegistrationToMap(sw_registration_id, new_registration); |
| 196 |
| 197 StoreRegistrations( |
| 198 origin, sw_registration_id, |
| 199 base::Bind(&BackgroundSyncManager::RegisterDidStore, |
| 200 weak_ptr_factory_.GetWeakPtr(), sw_registration_id, |
| 201 new_registration, existing_registration, callback)); |
| 202 } |
| 203 |
| 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()) |
| 211 return false; |
| 212 |
| 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()) |
| 218 return false; |
| 219 |
| 220 if (existing_registration) |
| 221 *existing_registration = name_and_registration_iter->second; |
| 222 |
| 223 return true; |
| 224 } |
| 225 |
| 226 void BackgroundSyncManager::StoreRegistrations( |
| 227 const GURL& origin, |
| 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); |
| 235 |
| 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); |
| 246 } |
| 247 std::string serialized; |
| 248 bool success = registrations_proto.SerializeToString(&serialized); |
| 249 DCHECK(success); |
| 250 |
| 251 StoreDataInBackend(sw_registration_id, origin, kBackgroundSyncUserDataKey, |
| 252 serialized, callback); |
| 253 } |
| 254 |
| 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); |
| 266 } else { |
| 267 RemoveRegistrationFromMap(sw_registration_id, new_registration.name, |
| 268 nullptr); |
| 269 } |
| 270 base::MessageLoop::current()->PostTask( |
| 271 FROM_HERE, |
| 272 base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration())); |
| 273 return; |
| 274 } |
| 275 |
| 276 // TODO(jkarlin): Run the registration algorithm. |
| 277 base::MessageLoop::current()->PostTask( |
| 278 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration)); |
| 279 } |
| 280 |
| 281 void BackgroundSyncManager::RemoveRegistrationFromMap( |
| 282 int64 sw_registration_id, |
| 283 const std::string& sync_registration_name, |
| 284 BackgroundSyncRegistration* old_registration) { |
| 285 DCHECK( |
| 286 LookupRegistration(sw_registration_id, sync_registration_name, nullptr)); |
| 287 |
| 288 BackgroundSyncRegistrations* registrations = |
| 289 &sw_to_registrations_map_[sw_registration_id]; |
| 290 |
| 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; |
| 295 |
| 296 registrations->name_to_registration_map.erase(name_and_registration_iter); |
| 297 } |
| 298 |
| 299 void BackgroundSyncManager::AddRegistrationToMap( |
| 300 int64 sw_registration_id, |
| 301 const BackgroundSyncRegistration& sync_registration) { |
| 302 DCHECK_NE(BackgroundSyncRegistration::kInvalidRegistrationId, |
| 303 sw_registration_id); |
| 304 |
| 305 BackgroundSyncRegistrations* registrations = |
| 306 &sw_to_registrations_map_[sw_registration_id]; |
| 307 registrations->name_to_registration_map[sync_registration.name] = |
| 308 sync_registration; |
| 309 } |
| 310 |
| 311 void BackgroundSyncManager::StoreDataInBackend( |
| 312 int64 sw_registration_id, |
| 313 const GURL& origin, |
| 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); |
| 319 } |
| 320 |
| 321 void BackgroundSyncManager::GetDataFromBackend( |
| 322 const std::string& key, |
| 323 const ServiceWorkerStorage::GetUserDataForAllRegistrationsCallback& |
| 324 callback) { |
| 325 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 326 |
| 327 service_worker_context_->context()->storage()->GetUserDataForAllRegistrations( |
| 328 key, callback); |
| 329 } |
| 330 |
| 331 void BackgroundSyncManager::UnregisterImpl( |
| 332 const GURL& origin, |
| 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)); |
| 343 return; |
| 344 } |
| 345 |
| 346 BackgroundSyncRegistration old_sync_registration; |
| 347 RemoveRegistrationFromMap(sw_registration_id, sync_registration_name, |
| 348 &old_sync_registration); |
| 349 |
| 350 StoreRegistrations( |
| 351 origin, sw_registration_id, |
| 352 base::Bind(&BackgroundSyncManager::UnregisterDidStore, |
| 353 weak_ptr_factory_.GetWeakPtr(), sw_registration_id, |
| 354 old_sync_registration, callback)); |
| 355 } |
| 356 |
| 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)); |
| 367 return; |
| 368 } |
| 369 |
| 370 // TODO(jkarlin): Run the registration algorithm. |
| 371 base::MessageLoop::current()->PostTask(FROM_HERE, |
| 372 base::Bind(callback, ERROR_TYPE_OK)); |
| 373 } |
| 374 |
| 375 void BackgroundSyncManager::GetRegistrationImpl( |
| 376 const GURL& origin, |
| 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())); |
| 386 return; |
| 387 } |
| 388 |
| 389 base::MessageLoop::current()->PostTask( |
| 390 FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registration)); |
| 391 } |
| 392 |
| 393 void BackgroundSyncManager::PendingStatusAndRegistrationCallback( |
| 394 const StatusAndRegistrationCallback& callback, |
| 395 ErrorType error, |
| 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); |
| 400 if (manager) |
| 401 op_scheduler_.CompleteOperationAndRunNext(); |
| 402 } |
| 403 |
| 404 void BackgroundSyncManager::PendingStatusCallback( |
| 405 const StatusCallback& callback, |
| 406 ErrorType error) { |
| 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(); |
| 409 callback.Run(error); |
| 410 if (manager) |
| 411 op_scheduler_.CompleteOperationAndRunNext(); |
| 412 } |
| 413 |
| 414 } // namespace content |
OLD | NEW |