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