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