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