1 // Copyright 2013 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 "chrome/browser/sync/glue/sync_backend_host_impl.h" 6 7 #include "base/command_line.h" 8 #include "chrome/browser/chrome_notification_types.h" 9 #include "chrome/browser/invalidation/invalidation_service.h" 10 #include "chrome/browser/invalidation/invalidation_service_factory.h" 11 #include "chrome/browser/network_time/network_time_tracker.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/sync/glue/sync_backend_host_core.h" 14 #include "chrome/browser/sync/glue/sync_backend_registrar.h" 15 #include "chrome/browser/sync/glue/sync_frontend.h" 16 #include "chrome/browser/sync/sync_prefs.h" 17 #include "chrome/common/chrome_switches.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/notification_details.h" 20 #include "content/public/browser/notification_source.h" 21 #include "sync/internal_api/public/base_transaction.h" 22 #include "sync/internal_api/public/http_bridge.h" 23 #include "sync/internal_api/public/internal_components_factory.h" 24 #include "sync/internal_api/public/internal_components_factory_impl.h" 25 #include "sync/internal_api/public/network_resources.h" 26 #include "sync/internal_api/public/sync_manager.h" 27 #include "sync/internal_api/public/sync_manager_factory.h" 28 #include "sync/internal_api/public/util/experiments.h" 29 #include "sync/internal_api/public/util/sync_string_conversions.h" 30 #include "sync/notifier/object_id_invalidation_map.h" 31 32 // Helper macros to log with the syncer thread name; useful when there 33 // are multiple syncers involved. 34 35 #define SLOG(severity) LOG(severity) << name_ << ": " 36 37 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": " 38 39 using syncer::InternalComponentsFactory; 40 41 static const base::FilePath::CharType kSyncDataFolderName[] = 42 FILE_PATH_LITERAL("Sync Data"); 43 44 namespace browser_sync { 45 46 SyncBackendHostImpl::SyncBackendHostImpl( 47 const std::string& name, 48 Profile* profile, 49 const base::WeakPtr<SyncPrefs>& sync_prefs) 50 : frontend_loop_(base::MessageLoop::current()), 51 profile_(profile), 52 name_(name), 53 initialized_(false), 54 sync_prefs_(sync_prefs), 55 frontend_(NULL), 56 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE), 57 invalidator_( 58 invalidation::InvalidationServiceFactory::GetForProfile(profile)), 59 invalidation_handler_registered_(false), 60 weak_ptr_factory_(this) { 61 core_ = new SyncBackendHostCore( 62 name_, 63 profile_->GetPath().Append(kSyncDataFolderName), 64 sync_prefs_->HasSyncSetupCompleted(), 65 weak_ptr_factory_.GetWeakPtr()); 66 } 67 68 SyncBackendHostImpl::~SyncBackendHostImpl() { 69 DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor."; 70 DCHECK(!registrar_.get()); 71 } 72 73 void SyncBackendHostImpl::Initialize( 74 SyncFrontend* frontend, 75 scoped_ptr<base::Thread> sync_thread, 76 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, 77 const GURL& sync_service_url, 78 const syncer::SyncCredentials& credentials, 79 bool delete_sync_data_folder, 80 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory, 81 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler, 82 syncer::ReportUnrecoverableErrorFunction 83 report_unrecoverable_error_function, 84 syncer::NetworkResources* network_resources) { 85 registrar_.reset(new browser_sync::SyncBackendRegistrar(name_, 86 profile_, 87 sync_thread.Pass())); 88 CHECK(registrar_->sync_thread()); 89 90 frontend_ = frontend; 91 DCHECK(frontend); 92 93 syncer::ModelSafeRoutingInfo routing_info; 94 std::vector<syncer::ModelSafeWorker*> workers; 95 registrar_->GetModelSafeRoutingInfo(&routing_info); 96 registrar_->GetWorkers(&workers); 97 98 InternalComponentsFactory::Switches factory_switches = { 99 InternalComponentsFactory::ENCRYPTION_KEYSTORE, 100 InternalComponentsFactory::BACKOFF_NORMAL 101 }; 102 103 CommandLine* cl = CommandLine::ForCurrentProcess(); 104 if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) { 105 factory_switches.backoff_override = 106 InternalComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE; 107 } 108 if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) { 109 factory_switches.pre_commit_updates_policy = 110 InternalComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE; 111 } 112 113 scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions( 114 registrar_->sync_thread()->message_loop(), 115 registrar_.get(), 116 routing_info, 117 workers, 118 extensions_activity_monitor_.GetExtensionsActivity(), 119 event_handler, 120 sync_service_url, 121 network_resources->GetHttpPostProviderFactory( 122 make_scoped_refptr(profile_->GetRequestContext()), 123 NetworkTimeTracker::BuildNotifierUpdateCallback(), 124 core_->GetRequestContextCancelationSignal()), 125 credentials, 126 invalidator_->GetInvalidatorClientId(), 127 sync_manager_factory.Pass(), 128 delete_sync_data_folder, 129 sync_prefs_->GetEncryptionBootstrapToken(), 130 sync_prefs_->GetKeystoreEncryptionBootstrapToken(), 131 scoped_ptr<InternalComponentsFactory>( 132 new syncer::InternalComponentsFactoryImpl(factory_switches)).Pass(), 133 unrecoverable_error_handler.Pass(), 134 report_unrecoverable_error_function)); 135 InitCore(init_opts.Pass()); 136 } 137 138 void SyncBackendHostImpl::UpdateCredentials( 139 const syncer::SyncCredentials& credentials) { 140 DCHECK(registrar_->sync_thread()->IsRunning()); 141 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 142 base::Bind(&SyncBackendHostCore::DoUpdateCredentials, 143 core_.get(), 144 credentials)); 145 } 146 147 void SyncBackendHostImpl::StartSyncingWithServer() { 148 SDVLOG(1) << "SyncBackendHostImpl::StartSyncingWithServer called."; 149 150 syncer::ModelSafeRoutingInfo routing_info; 151 registrar_->GetModelSafeRoutingInfo(&routing_info); 152 153 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 154 base::Bind(&SyncBackendHostCore::DoStartSyncing, 155 core_.get(), routing_info)); 156 } 157 158 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase, 159 bool is_explicit) { 160 DCHECK(registrar_->sync_thread()->IsRunning()); 161 if (!IsNigoriEnabled()) { 162 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori" 163 " is disabled."; 164 return; 165 } 166 167 // We should never be called with an empty passphrase. 168 DCHECK(!passphrase.empty()); 169 170 // This should only be called by the frontend. 171 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 172 173 // SetEncryptionPassphrase should never be called if we are currently 174 // encrypted with an explicit passphrase. 175 DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE || 176 cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE); 177 178 // Post an encryption task on the syncer thread. 179 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 180 base::Bind(&SyncBackendHostCore::DoSetEncryptionPassphrase, 181 core_.get(), 182 passphrase, is_explicit)); 183 } 184 185 bool SyncBackendHostImpl::SetDecryptionPassphrase( 186 const std::string& passphrase) { 187 if (!IsNigoriEnabled()) { 188 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori" 189 " is disabled."; 190 return false; 191 } 192 193 // We should never be called with an empty passphrase. 194 DCHECK(!passphrase.empty()); 195 196 // This should only be called by the frontend. 197 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 198 199 // This should only be called when we have cached pending keys. 200 DCHECK(cached_pending_keys_.has_blob()); 201 202 // Check the passphrase that was provided against our local cache of the 203 // cryptographer's pending keys. If this was unsuccessful, the UI layer can 204 // immediately call OnPassphraseRequired without showing the user a spinner. 205 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase)) 206 return false; 207 208 // Post a decryption task on the syncer thread. 209 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 210 base::Bind(&SyncBackendHostCore::DoSetDecryptionPassphrase, 211 core_.get(), 212 passphrase)); 213 214 // Since we were able to decrypt the cached pending keys with the passphrase 215 // provided, we immediately alert the UI layer that the passphrase was 216 // accepted. This will avoid the situation where a user enters a passphrase, 217 // clicks OK, immediately reopens the advanced settings dialog, and gets an 218 // unnecessary prompt for a passphrase. 219 // Note: It is not guaranteed that the passphrase will be accepted by the 220 // syncer thread, since we could receive a new nigori node while the task is 221 // pending. This scenario is a valid race, and SetDecryptionPassphrase can 222 // trigger a new OnPassphraseRequired if it needs to. 223 NotifyPassphraseAccepted(); 224 return true; 225 } 226 227 void SyncBackendHostImpl::StopSyncingForShutdown() { 228 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 229 230 // Immediately stop sending messages to the frontend. 231 frontend_ = NULL; 232 233 // Stop listening for and forwarding locally-triggered sync refresh requests. 234 notification_registrar_.RemoveAll(); 235 236 DCHECK(registrar_->sync_thread()->IsRunning()); 237 238 registrar_->RequestWorkerStopOnUIThread(); 239 240 core_->ShutdownOnUIThread(); 241 } 242 243 scoped_ptr<base::Thread> SyncBackendHostImpl::Shutdown(ShutdownOption option) { 244 // StopSyncingForShutdown() (which nulls out |frontend_|) should be 245 // called first. 246 DCHECK(!frontend_); 247 DCHECK(registrar_->sync_thread()->IsRunning()); 248 249 bool sync_disabled = (option == DISABLE_AND_CLAIM_THREAD); 250 bool sync_thread_claimed = 251 (option == DISABLE_AND_CLAIM_THREAD || option == STOP_AND_CLAIM_THREAD); 252 253 if (invalidation_handler_registered_) { 254 if (sync_disabled) { 255 UnregisterInvalidationIds(); 256 } 257 invalidator_->UnregisterInvalidationHandler(this); 258 invalidator_ = NULL; 259 } 260 invalidation_handler_registered_ = false; 261 262 // Shut down and destroy sync manager. 263 registrar_->sync_thread()->message_loop()->PostTask( 264 FROM_HERE, 265 base::Bind(&SyncBackendHostCore::DoShutdown, 266 core_.get(), sync_disabled)); 267 core_ = NULL; 268 269 // Worker cleanup. 270 SyncBackendRegistrar* detached_registrar = registrar_.release(); 271 detached_registrar->sync_thread()->message_loop()->PostTask( 272 FROM_HERE, 273 base::Bind(&SyncBackendRegistrar::Shutdown, 274 base::Unretained(detached_registrar))); 275 276 if (sync_thread_claimed) 277 return detached_registrar->ReleaseSyncThread(); 278 else 279 return scoped_ptr<base::Thread>(); 280 } 281 282 void SyncBackendHostImpl::UnregisterInvalidationIds() { 283 if (invalidation_handler_registered_) { 284 invalidator_->UpdateRegisteredInvalidationIds( 285 this, 286 syncer::ObjectIdSet()); 287 } 288 } 289 290 void SyncBackendHostImpl::ConfigureDataTypes( 291 syncer::ConfigureReason reason, 292 const DataTypeConfigStateMap& config_state_map, 293 const base::Callback<void(syncer::ModelTypeSet, 294 syncer::ModelTypeSet)>& ready_task, 295 const base::Callback<void()>& retry_callback) { 296 // Only one configure is allowed at a time. This is guaranteed by our 297 // callers. The SyncBackendHostImpl requests one configure as the backend is 298 // initializing and waits for it to complete. After initialization, all 299 // configurations will pass through the DataTypeManager, which is careful to 300 // never send a new configure request until the current request succeeds. 301 302 // The SyncBackendRegistrar's routing info will be updated by adding the 303 // types_to_add to the list then removing types_to_remove. Any types which 304 // are not in either of those sets will remain untouched. 305 // 306 // Types which were not in the list previously are not fully downloaded, so we 307 // must ask the syncer to download them. Any newly supported datatypes will 308 // not have been in that routing info list, so they will be among the types 309 // downloaded if they are enabled. 310 // 311 // The SyncBackendRegistrar's state was initially derived from the types 312 // detected to have been downloaded in the database. Afterwards it is 313 // modified only by this function. We expect it to remain in sync with the 314 // backend because configuration requests are never aborted; they are retried 315 // until they succeed or the backend is shut down. 316 317 syncer::ModelTypeSet previous_types = registrar_->GetLastConfiguredTypes(); 318 319 syncer::ModelTypeSet disabled_types = 320 GetDataTypesInState(DISABLED, config_state_map); 321 syncer::ModelTypeSet fatal_types = 322 GetDataTypesInState(FATAL, config_state_map); 323 syncer::ModelTypeSet crypto_types = 324 GetDataTypesInState(CRYPTO, config_state_map); 325 disabled_types.PutAll(fatal_types); 326 disabled_types.PutAll(crypto_types); 327 syncer::ModelTypeSet active_types = 328 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map); 329 syncer::ModelTypeSet clean_first_types = 330 GetDataTypesInState(CONFIGURE_CLEAN, config_state_map); 331 syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes( 332 syncer::Union(active_types, clean_first_types), 333 disabled_types); 334 types_to_download.PutAll(clean_first_types); 335 types_to_download.RemoveAll(syncer::ProxyTypes()); 336 if (!types_to_download.Empty()) 337 types_to_download.Put(syncer::NIGORI); 338 339 // TODO(sync): crbug.com/137550. 340 // It's dangerous to configure types that have progress markers. Types with 341 // progress markers can trigger a MIGRATION_DONE response. We are not 342 // prepared to handle a migration during a configure, so we must ensure that 343 // all our types_to_download actually contain no data before we sync them. 344 // 345 // One common way to end up in this situation used to be types which 346 // downloaded some or all of their data but have not applied it yet. We avoid 347 // problems with those types by purging the data of any such partially synced 348 // types soon after we load the directory. 349 // 350 // Another possible scenario is that we have newly supported or newly enabled 351 // data types being downloaded here but the nigori type, which is always 352 // included in any GetUpdates request, requires migration. The server has 353 // code to detect this scenario based on the configure reason, the fact that 354 // the nigori type is the only requested type which requires migration, and 355 // that the requested types list includes at least one non-nigori type. It 356 // will not send a MIGRATION_DONE response in that case. We still need to be 357 // careful to not send progress markers for non-nigori types, though. If a 358 // non-nigori type in the request requires migration, a MIGRATION_DONE 359 // response will be sent. 360 361 syncer::ModelSafeRoutingInfo routing_info; 362 registrar_->GetModelSafeRoutingInfo(&routing_info); 363 364 syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes(); 365 syncer::ModelTypeSet types_to_purge = 366 syncer::Difference(previous_types, current_types); 367 syncer::ModelTypeSet inactive_types = 368 GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map); 369 types_to_purge.RemoveAll(inactive_types); 370 371 // If a type has already been disabled and unapplied or journaled, it will 372 // not be part of the |types_to_purge| set, and therefore does not need 373 // to be acted on again. 374 fatal_types.RetainAll(types_to_purge); 375 syncer::ModelTypeSet unapply_types = 376 syncer::Union(crypto_types, clean_first_types); 377 unapply_types.RetainAll(types_to_purge); 378 379 DCHECK(syncer::Intersection(current_types, fatal_types).Empty()); 380 DCHECK(syncer::Intersection(current_types, crypto_types).Empty()); 381 DCHECK(current_types.HasAll(types_to_download)); 382 383 SDVLOG(1) << "Types " 384 << syncer::ModelTypeSetToString(types_to_download) 385 << " added; calling DoConfigureSyncer"; 386 // Divide up the types into their corresponding actions (each is mutually 387 // exclusive): 388 // - Types which have just been added to the routing info (types_to_download): 389 // are downloaded. 390 // - Types which have encountered a fatal error (fatal_types) are deleted 391 // from the directory and journaled in the delete journal. 392 // - Types which have encountered a cryptographer error (crypto_types) are 393 // unapplied (local state is purged but sync state is not). 394 // - All other types not in the routing info (types just disabled) are deleted 395 // from the directory. 396 // - Everything else (enabled types and already disabled types) is not 397 // touched. 398 RequestConfigureSyncer(reason, 399 types_to_download, 400 types_to_purge, 401 fatal_types, 402 unapply_types, 403 inactive_types, 404 routing_info, 405 ready_task, 406 retry_callback); 407 } 408 409 void SyncBackendHostImpl::EnableEncryptEverything() { 410 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 411 base::Bind(&SyncBackendHostCore::DoEnableEncryptEverything, 412 core_.get())); 413 } 414 415 void SyncBackendHostImpl::ActivateDataType( 416 syncer::ModelType type, syncer::ModelSafeGroup group, 417 ChangeProcessor* change_processor) { 418 registrar_->ActivateDataType(type, group, change_processor, GetUserShare()); 419 } 420 421 void SyncBackendHostImpl::DeactivateDataType(syncer::ModelType type) { 422 registrar_->DeactivateDataType(type); 423 } 424 425 syncer::UserShare* SyncBackendHostImpl::GetUserShare() const { 426 return core_->sync_manager()->GetUserShare(); 427 } 428 429 SyncBackendHostImpl::Status SyncBackendHostImpl::GetDetailedStatus() { 430 DCHECK(initialized()); 431 return core_->sync_manager()->GetDetailedStatus(); 432 } 433 434 syncer::sessions::SyncSessionSnapshot 435 SyncBackendHostImpl::GetLastSessionSnapshot() const { 436 return last_snapshot_; 437 } 438 439 bool SyncBackendHostImpl::HasUnsyncedItems() const { 440 DCHECK(initialized()); 441 return core_->sync_manager()->HasUnsyncedItems(); 442 } 443 444 bool SyncBackendHostImpl::IsNigoriEnabled() const { 445 return registrar_.get() && registrar_->IsNigoriEnabled(); 446 } 447 448 syncer::PassphraseType SyncBackendHostImpl::GetPassphraseType() const { 449 return cached_passphrase_type_; 450 } 451 452 base::Time SyncBackendHostImpl::GetExplicitPassphraseTime() const { 453 return cached_explicit_passphrase_time_; 454 } 455 456 bool SyncBackendHostImpl::IsCryptographerReady( 457 const syncer::BaseTransaction* trans) const { 458 return initialized() && trans->GetCryptographer()->is_ready(); 459 } 460 461 void SyncBackendHostImpl::GetModelSafeRoutingInfo( 462 syncer::ModelSafeRoutingInfo* out) const { 463 if (initialized()) { 464 CHECK(registrar_.get()); 465 registrar_->GetModelSafeRoutingInfo(out); 466 } else { 467 NOTREACHED(); 468 } 469 } 470 471 SyncedDeviceTracker* SyncBackendHostImpl::GetSyncedDeviceTracker() const { 472 if (!initialized()) 473 return NULL; 474 return core_->synced_device_tracker(); 475 } 476 477 void SyncBackendHostImpl::InitCore(scoped_ptr<DoInitializeOptions> options) { 478 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 479 base::Bind(&SyncBackendHostCore::DoInitialize, 480 core_.get(), base::Passed(&options))); 481 } 482 483 void SyncBackendHostImpl::RequestConfigureSyncer( 484 syncer::ConfigureReason reason, 485 syncer::ModelTypeSet to_download, 486 syncer::ModelTypeSet to_purge, 487 syncer::ModelTypeSet to_journal, 488 syncer::ModelTypeSet to_unapply, 489 syncer::ModelTypeSet to_ignore, 490 const syncer::ModelSafeRoutingInfo& routing_info, 491 const base::Callback<void(syncer::ModelTypeSet, 492 syncer::ModelTypeSet)>& ready_task, 493 const base::Closure& retry_callback) { 494 DoConfigureSyncerTypes config_types; 495 config_types.to_download = to_download; 496 config_types.to_purge = to_purge; 497 config_types.to_journal = to_journal; 498 config_types.to_unapply = to_unapply; 499 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 500 base::Bind(&SyncBackendHostCore::DoConfigureSyncer, 501 core_.get(), 502 reason, 503 config_types, 504 routing_info, 505 ready_task, 506 retry_callback)); 507 } 508 509 void SyncBackendHostImpl::FinishConfigureDataTypesOnFrontendLoop( 510 const syncer::ModelTypeSet enabled_types, 511 const syncer::ModelTypeSet succeeded_configuration_types, 512 const syncer::ModelTypeSet failed_configuration_types, 513 const base::Callback<void(syncer::ModelTypeSet, 514 syncer::ModelTypeSet)>& ready_task) { 515 if (!frontend_) 516 return; 517 518 invalidator_->UpdateRegisteredInvalidationIds( 519 this, 520 ModelTypeSetToObjectIdSet(enabled_types)); 521 522 if (!ready_task.is_null()) 523 ready_task.Run(succeeded_configuration_types, failed_configuration_types); 524 } 525 526 void SyncBackendHostImpl::Observe( 527 int type, 528 const content::NotificationSource& source, 529 const content::NotificationDetails& details) { 530 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 531 DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL); 532 533 content::Details<const syncer::ModelTypeSet> state_details(details); 534 const syncer::ModelTypeSet& types = *(state_details.ptr()); 535 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, 536 base::Bind(&SyncBackendHostCore::DoRefreshTypes, core_.get(), types)); 537 } 538 539 void SyncBackendHostImpl::AddExperimentalTypes() { 540 CHECK(initialized()); 541 syncer::Experiments experiments; 542 if (core_->sync_manager()->ReceivedExperiment(&experiments)) 543 frontend_->OnExperimentsChanged(experiments); 544 } 545 546 void SyncBackendHostImpl::HandleControlTypesDownloadRetry() { 547 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 548 if (!frontend_) 549 return; 550 551 frontend_->OnSyncConfigureRetry(); 552 } 553 554 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop( 555 const syncer::WeakHandle<syncer::JsBackend> js_backend, 556 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener> 557 debug_info_listener) { 558 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 559 if (!frontend_) 560 return; 561 562 initialized_ = true; 563 564 invalidator_->RegisterInvalidationHandler(this); 565 invalidation_handler_registered_ = true; 566 567 // Fake a state change to initialize the SyncManager's cached invalidator 568 // state. 569 OnInvalidatorStateChange(invalidator_->GetInvalidatorState()); 570 571 // Start forwarding refresh requests to the SyncManager 572 notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL, 573 content::Source<Profile>(profile_)); 574 575 // Now that we've downloaded the control types, we can see if there are any 576 // experimental types to enable. This should be done before we inform 577 // the frontend to ensure they're visible in the customize screen. 578 AddExperimentalTypes(); 579 frontend_->OnBackendInitialized(js_backend, 580 debug_info_listener, 581 true); 582 } 583 584 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() { 585 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 586 if (!frontend_) 587 return; 588 589 frontend_->OnBackendInitialized( 590 syncer::WeakHandle<syncer::JsBackend>(), 591 syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(), 592 false); 593 } 594 595 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop( 596 const syncer::sessions::SyncSessionSnapshot& snapshot) { 597 if (!frontend_) 598 return; 599 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 600 601 last_snapshot_ = snapshot; 602 603 SDVLOG(1) << "Got snapshot " << snapshot.ToString(); 604 605 const syncer::ModelTypeSet to_migrate = 606 snapshot.model_neutral_state().types_needing_local_migration; 607 if (!to_migrate.Empty()) 608 frontend_->OnMigrationNeededForTypes(to_migrate); 609 610 // Process any changes to the datatypes we're syncing. 611 // TODO(sync): add support for removing types. 612 if (initialized()) 613 AddExperimentalTypes(); 614 615 if (initialized()) 616 frontend_->OnSyncCycleCompleted(); 617 } 618 619 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop( 620 const base::Closure& retry_callback) { 621 SDVLOG(1) << "Failed to complete configuration, informing of retry."; 622 retry_callback.Run(); 623 } 624 625 void SyncBackendHostImpl::PersistEncryptionBootstrapToken( 626 const std::string& token, 627 syncer::BootstrapTokenType token_type) { 628 CHECK(sync_prefs_.get()); 629 DCHECK(!token.empty()); 630 if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN) 631 sync_prefs_->SetEncryptionBootstrapToken(token); 632 else 633 sync_prefs_->SetKeystoreEncryptionBootstrapToken(token); 634 } 635 636 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop( 637 const syncer::SyncProtocolError& sync_error) { 638 if (!frontend_) 639 return; 640 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 641 frontend_->OnActionableError(sync_error); 642 } 643 644 void SyncBackendHostImpl::OnInvalidatorStateChange( 645 syncer::InvalidatorState state) { 646 registrar_->sync_thread()->message_loop()->PostTask( 647 FROM_HERE, 648 base::Bind(&SyncBackendHostCore::DoOnInvalidatorStateChange, 649 core_.get(), 650 state)); 651 } 652 653 void SyncBackendHostImpl::OnIncomingInvalidation( 654 const syncer::ObjectIdInvalidationMap& invalidation_map) { 655 // TODO(rlarocque): Acknowledge these invalidations only after the syncer has 656 // acted on them and saved the results to disk. 657 invalidation_map.AcknowledgeAll(); 658 registrar_->sync_thread()->message_loop()->PostTask( 659 FROM_HERE, 660 base::Bind(&SyncBackendHostCore::DoOnIncomingInvalidation, 661 core_.get(), 662 invalidation_map)); 663 } 664 665 bool SyncBackendHostImpl::CheckPassphraseAgainstCachedPendingKeys( 666 const std::string& passphrase) const { 667 DCHECK(cached_pending_keys_.has_blob()); 668 DCHECK(!passphrase.empty()); 669 syncer::Nigori nigori; 670 nigori.InitByDerivation("localhost", "dummy", passphrase); 671 std::string plaintext; 672 bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext); 673 DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys."; 674 return result; 675 } 676 677 void SyncBackendHostImpl::NotifyPassphraseRequired( 678 syncer::PassphraseRequiredReason reason, 679 sync_pb::EncryptedData pending_keys) { 680 if (!frontend_) 681 return; 682 683 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 684 685 // Update our cache of the cryptographer's pending keys. 686 cached_pending_keys_ = pending_keys; 687 688 frontend_->OnPassphraseRequired(reason, pending_keys); 689 } 690 691 void SyncBackendHostImpl::NotifyPassphraseAccepted() { 692 if (!frontend_) 693 return; 694 695 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 696 697 // Clear our cache of the cryptographer's pending keys. 698 cached_pending_keys_.clear_blob(); 699 frontend_->OnPassphraseAccepted(); 700 } 701 702 void SyncBackendHostImpl::NotifyEncryptedTypesChanged( 703 syncer::ModelTypeSet encrypted_types, 704 bool encrypt_everything) { 705 if (!frontend_) 706 return; 707 708 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 709 frontend_->OnEncryptedTypesChanged( 710 encrypted_types, encrypt_everything); 711 } 712 713 void SyncBackendHostImpl::NotifyEncryptionComplete() { 714 if (!frontend_) 715 return; 716 717 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 718 frontend_->OnEncryptionComplete(); 719 } 720 721 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop( 722 syncer::PassphraseType type, 723 base::Time explicit_passphrase_time) { 724 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 725 DVLOG(1) << "Passphrase type changed to " 726 << syncer::PassphraseTypeToString(type); 727 cached_passphrase_type_ = type; 728 cached_explicit_passphrase_time_ = explicit_passphrase_time; 729 } 730 731 void SyncBackendHostImpl::HandleStopSyncingPermanentlyOnFrontendLoop() { 732 if (!frontend_) 733 return; 734 frontend_->OnStopSyncingPermanently(); 735 } 736 737 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop( 738 syncer::ConnectionStatus status) { 739 if (!frontend_) 740 return; 741 742 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); 743 744 DVLOG(1) << "Connection status changed: " 745 << syncer::ConnectionStatusToString(status); 746 frontend_->OnConnectionStatusChange(status); 747 } 748 749 base::MessageLoop* SyncBackendHostImpl::GetSyncLoopForTesting() { 750 return registrar_->sync_thread()->message_loop(); 751 } 752 753 } // namespace browser_sync 754 755 #undef SDVLOG 756 757 #undef SLOG 758 759