| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/glue/sync_backend_host.h" | 5 #include "chrome/browser/sync/glue/sync_backend_host.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 #include <map> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/command_line.h" | |
| 12 #include "base/compiler_specific.h" | |
| 13 #include "base/file_util.h" | |
| 14 #include "base/files/file_path.h" | |
| 15 #include "base/location.h" | |
| 16 #include "base/metrics/histogram.h" | |
| 17 #include "base/strings/utf_string_conversions.h" | |
| 18 #include "base/threading/thread_restrictions.h" | |
| 19 #include "base/timer/timer.h" | |
| 20 #include "base/tracked_objects.h" | |
| 21 #include "build/build_config.h" | |
| 22 #include "chrome/browser/invalidation/invalidation_service.h" | |
| 23 #include "chrome/browser/invalidation/invalidation_service_factory.h" | |
| 24 #include "chrome/browser/chrome_notification_types.h" | |
| 25 #include "chrome/browser/network_time/network_time_tracker.h" | |
| 26 #include "chrome/browser/profiles/profile.h" | |
| 27 #include "chrome/browser/signin/token_service.h" | |
| 28 #include "chrome/browser/signin/token_service_factory.h" | |
| 29 #include "chrome/browser/sync/glue/change_processor.h" | |
| 30 #include "chrome/browser/sync/glue/chrome_encryptor.h" | |
| 31 #include "chrome/browser/sync/glue/device_info.h" | |
| 32 #include "chrome/browser/sync/glue/sync_backend_registrar.h" | |
| 33 #include "chrome/browser/sync/glue/synced_device_tracker.h" | |
| 34 #include "chrome/browser/sync/sync_prefs.h" | |
| 35 #include "chrome/common/chrome_switches.h" | |
| 36 #include "chrome/common/chrome_version_info.h" | |
| 37 #include "content/public/browser/browser_thread.h" | |
| 38 #include "content/public/browser/notification_details.h" | |
| 39 #include "content/public/browser/notification_service.h" | |
| 40 #include "content/public/browser/notification_source.h" | |
| 41 #include "content/public/common/content_client.h" | |
| 42 #include "google_apis/gaia/gaia_constants.h" | |
| 43 #include "jingle/notifier/base/notification_method.h" | |
| 44 #include "jingle/notifier/base/notifier_options.h" | |
| 45 #include "net/base/host_port_pair.h" | |
| 46 #include "net/url_request/url_request_context_getter.h" | |
| 47 #include "sync/internal_api/public/base/cancelation_signal.h" | |
| 48 #include "sync/internal_api/public/base_transaction.h" | |
| 49 #include "sync/internal_api/public/engine/model_safe_worker.h" | |
| 50 #include "sync/internal_api/public/http_bridge.h" | |
| 51 #include "sync/internal_api/public/internal_components_factory_impl.h" | |
| 52 #include "sync/internal_api/public/read_transaction.h" | |
| 53 #include "sync/internal_api/public/sync_manager_factory.h" | |
| 54 #include "sync/internal_api/public/util/experiments.h" | |
| 55 #include "sync/internal_api/public/util/sync_string_conversions.h" | |
| 56 #include "sync/protocol/encryption.pb.h" | |
| 57 #include "sync/protocol/sync.pb.h" | |
| 58 #include "sync/util/nigori.h" | |
| 59 | |
| 60 static const int kSaveChangesIntervalSeconds = 10; | |
| 61 static const base::FilePath::CharType kSyncDataFolderName[] = | |
| 62 FILE_PATH_LITERAL("Sync Data"); | |
| 63 | |
| 64 typedef TokenService::TokenAvailableDetails TokenAvailableDetails; | |
| 65 | |
| 66 typedef GoogleServiceAuthError AuthError; | |
| 67 | |
| 68 namespace browser_sync { | 7 namespace browser_sync { |
| 69 | 8 |
| 70 using content::BrowserThread; | 9 SyncBackendHost::SyncBackendHost() {} |
| 71 using syncer::InternalComponentsFactory; | |
| 72 using syncer::InternalComponentsFactoryImpl; | |
| 73 using syncer::sessions::SyncSessionSnapshot; | |
| 74 using syncer::SyncCredentials; | |
| 75 | 10 |
| 76 namespace { | 11 SyncBackendHost::~SyncBackendHost() {} |
| 77 | |
| 78 // Enums for UMAs. | |
| 79 enum SyncBackendInitState { | |
| 80 SETUP_COMPLETED_FOUND_RESTORED_TYPES = 0, | |
| 81 SETUP_COMPLETED_NO_RESTORED_TYPES, | |
| 82 FIRST_SETUP_NO_RESTORED_TYPES, | |
| 83 FIRST_SETUP_RESTORED_TYPES, | |
| 84 SYNC_BACKEND_INIT_STATE_COUNT | |
| 85 }; | |
| 86 | |
| 87 // Helper struct to handle currying params to | |
| 88 // SyncBackendHost::Core::DoConfigureSyncer. | |
| 89 struct DoConfigureSyncerTypes { | |
| 90 DoConfigureSyncerTypes() {} | |
| 91 ~DoConfigureSyncerTypes() {} | |
| 92 syncer::ModelTypeSet to_download; | |
| 93 syncer::ModelTypeSet to_purge; | |
| 94 syncer::ModelTypeSet to_journal; | |
| 95 syncer::ModelTypeSet to_unapply; | |
| 96 }; | |
| 97 | |
| 98 } // namespace | |
| 99 | |
| 100 // Helper macros to log with the syncer thread name; useful when there | |
| 101 // are multiple syncers involved. | |
| 102 | |
| 103 #define SLOG(severity) LOG(severity) << name_ << ": " | |
| 104 | |
| 105 #define SDVLOG(verbose_level) DVLOG(verbose_level) << name_ << ": " | |
| 106 | |
| 107 class SyncBackendHost::Core | |
| 108 : public base::RefCountedThreadSafe<SyncBackendHost::Core>, | |
| 109 public syncer::SyncEncryptionHandler::Observer, | |
| 110 public syncer::SyncManager::Observer { | |
| 111 public: | |
| 112 Core(const std::string& name, | |
| 113 const base::FilePath& sync_data_folder_path, | |
| 114 bool has_sync_setup_completed, | |
| 115 const base::WeakPtr<SyncBackendHost>& backend); | |
| 116 | |
| 117 // SyncManager::Observer implementation. The Core just acts like an air | |
| 118 // traffic controller here, forwarding incoming messages to appropriate | |
| 119 // landing threads. | |
| 120 virtual void OnSyncCycleCompleted( | |
| 121 const syncer::sessions::SyncSessionSnapshot& snapshot) OVERRIDE; | |
| 122 virtual void OnInitializationComplete( | |
| 123 const syncer::WeakHandle<syncer::JsBackend>& js_backend, | |
| 124 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>& | |
| 125 debug_info_listener, | |
| 126 bool success, | |
| 127 syncer::ModelTypeSet restored_types) OVERRIDE; | |
| 128 virtual void OnConnectionStatusChange( | |
| 129 syncer::ConnectionStatus status) OVERRIDE; | |
| 130 virtual void OnStopSyncingPermanently() OVERRIDE; | |
| 131 virtual void OnActionableError( | |
| 132 const syncer::SyncProtocolError& sync_error) OVERRIDE; | |
| 133 | |
| 134 // SyncEncryptionHandler::Observer implementation. | |
| 135 virtual void OnPassphraseRequired( | |
| 136 syncer::PassphraseRequiredReason reason, | |
| 137 const sync_pb::EncryptedData& pending_keys) OVERRIDE; | |
| 138 virtual void OnPassphraseAccepted() OVERRIDE; | |
| 139 virtual void OnBootstrapTokenUpdated( | |
| 140 const std::string& bootstrap_token, | |
| 141 syncer::BootstrapTokenType type) OVERRIDE; | |
| 142 virtual void OnEncryptedTypesChanged( | |
| 143 syncer::ModelTypeSet encrypted_types, | |
| 144 bool encrypt_everything) OVERRIDE; | |
| 145 virtual void OnEncryptionComplete() OVERRIDE; | |
| 146 virtual void OnCryptographerStateChanged( | |
| 147 syncer::Cryptographer* cryptographer) OVERRIDE; | |
| 148 virtual void OnPassphraseTypeChanged(syncer::PassphraseType type, | |
| 149 base::Time passphrase_time) OVERRIDE; | |
| 150 | |
| 151 // Forwards an invalidation state change to the sync manager. | |
| 152 void DoOnInvalidatorStateChange(syncer::InvalidatorState state); | |
| 153 | |
| 154 // Forwards an invalidation to the sync manager. | |
| 155 void DoOnIncomingInvalidation( | |
| 156 syncer::ObjectIdInvalidationMap invalidation_map); | |
| 157 | |
| 158 // Note: | |
| 159 // | |
| 160 // The Do* methods are the various entry points from our | |
| 161 // SyncBackendHost. They are all called on the sync thread to | |
| 162 // actually perform synchronous (and potentially blocking) syncapi | |
| 163 // operations. | |
| 164 // | |
| 165 // Called to perform initialization of the syncapi on behalf of | |
| 166 // SyncBackendHost::Initialize. | |
| 167 void DoInitialize(scoped_ptr<DoInitializeOptions> options); | |
| 168 | |
| 169 // Called to perform credential update on behalf of | |
| 170 // SyncBackendHost::UpdateCredentials. | |
| 171 void DoUpdateCredentials(const syncer::SyncCredentials& credentials); | |
| 172 | |
| 173 // Called to tell the syncapi to start syncing (generally after | |
| 174 // initialization and authentication). | |
| 175 void DoStartSyncing(const syncer::ModelSafeRoutingInfo& routing_info); | |
| 176 | |
| 177 // Called to set the passphrase for encryption. | |
| 178 void DoSetEncryptionPassphrase(const std::string& passphrase, | |
| 179 bool is_explicit); | |
| 180 | |
| 181 // Called to decrypt the pending keys. | |
| 182 void DoSetDecryptionPassphrase(const std::string& passphrase); | |
| 183 | |
| 184 // Called to turn on encryption of all sync data as well as | |
| 185 // reencrypt everything. | |
| 186 void DoEnableEncryptEverything(); | |
| 187 | |
| 188 // Ask the syncer to check for updates for the specified types. | |
| 189 void DoRefreshTypes(syncer::ModelTypeSet types); | |
| 190 | |
| 191 // Invoked if we failed to download the necessary control types at startup. | |
| 192 // Invokes SyncBackendHost::HandleControlTypesDownloadRetry. | |
| 193 void OnControlTypesDownloadRetry(); | |
| 194 | |
| 195 // Called to perform tasks which require the control data to be downloaded. | |
| 196 // This includes refreshing encryption, setting up the device info change | |
| 197 // processor, etc. | |
| 198 void DoInitialProcessControlTypes(); | |
| 199 | |
| 200 // Some parts of DoInitialProcessControlTypes() may be executed on a different | |
| 201 // thread. This function asynchronously continues the work started in | |
| 202 // DoInitialProcessControlTypes() once that other thread gets back to us. | |
| 203 void DoFinishInitialProcessControlTypes(); | |
| 204 | |
| 205 // The shutdown order is a bit complicated: | |
| 206 // 1) Call ShutdownOnUIThread() from |frontend_loop_| to request sync manager | |
| 207 // to stop as soon as possible. | |
| 208 // 2) Post DoShutdown() to sync loop to clean up backend state, save | |
| 209 // directory and destroy sync manager. | |
| 210 void ShutdownOnUIThread(); | |
| 211 void DoShutdown(bool sync_disabled); | |
| 212 void DoDestroySyncManager(); | |
| 213 | |
| 214 // Configuration methods that must execute on sync loop. | |
| 215 void DoConfigureSyncer( | |
| 216 syncer::ConfigureReason reason, | |
| 217 const DoConfigureSyncerTypes& config_types, | |
| 218 const syncer::ModelSafeRoutingInfo routing_info, | |
| 219 const base::Callback<void(syncer::ModelTypeSet, | |
| 220 syncer::ModelTypeSet)>& ready_task, | |
| 221 const base::Closure& retry_callback); | |
| 222 void DoFinishConfigureDataTypes( | |
| 223 syncer::ModelTypeSet types_to_config, | |
| 224 const base::Callback<void(syncer::ModelTypeSet, | |
| 225 syncer::ModelTypeSet)>& ready_task); | |
| 226 void DoRetryConfiguration( | |
| 227 const base::Closure& retry_callback); | |
| 228 | |
| 229 // Set the base request context to use when making HTTP calls. | |
| 230 // This method will add a reference to the context to persist it | |
| 231 // on the IO thread. Must be removed from IO thread. | |
| 232 | |
| 233 syncer::SyncManager* sync_manager() { return sync_manager_.get(); } | |
| 234 | |
| 235 SyncedDeviceTracker* synced_device_tracker() { | |
| 236 return synced_device_tracker_.get(); | |
| 237 } | |
| 238 | |
| 239 // Delete the sync data folder to cleanup backend data. Happens the first | |
| 240 // time sync is enabled for a user (to prevent accidentally reusing old | |
| 241 // sync databases), as well as shutdown when you're no longer syncing. | |
| 242 void DeleteSyncDataFolder(); | |
| 243 | |
| 244 // We expose this member because it's required in the construction of the | |
| 245 // HttpBridgeFactory. | |
| 246 syncer::CancelationSignal* GetRequestContextCancelationSignal() { | |
| 247 return &release_request_context_signal_; | |
| 248 } | |
| 249 | |
| 250 private: | |
| 251 friend class base::RefCountedThreadSafe<SyncBackendHost::Core>; | |
| 252 friend class SyncBackendHostForProfileSyncTest; | |
| 253 | |
| 254 virtual ~Core(); | |
| 255 | |
| 256 // Invoked when initialization of syncapi is complete and we can start | |
| 257 // our timer. | |
| 258 // This must be called from the thread on which SaveChanges is intended to | |
| 259 // be run on; the host's |registrar_->sync_thread()|. | |
| 260 void StartSavingChanges(); | |
| 261 | |
| 262 // Invoked periodically to tell the syncapi to persist its state | |
| 263 // by writing to disk. | |
| 264 // This is called from the thread we were created on (which is sync thread), | |
| 265 // using a repeating timer that is kicked off as soon as the SyncManager | |
| 266 // tells us it completed initialization. | |
| 267 void SaveChanges(); | |
| 268 | |
| 269 // Name used for debugging. | |
| 270 const std::string name_; | |
| 271 | |
| 272 // Path of the folder that stores the sync data files. | |
| 273 const base::FilePath sync_data_folder_path_; | |
| 274 | |
| 275 // Our parent SyncBackendHost. | |
| 276 syncer::WeakHandle<SyncBackendHost> host_; | |
| 277 | |
| 278 // The loop where all the sync backend operations happen. | |
| 279 // Non-NULL only between calls to DoInitialize() and ~Core(). | |
| 280 base::MessageLoop* sync_loop_; | |
| 281 | |
| 282 // Our parent's registrar (not owned). Non-NULL only between | |
| 283 // calls to DoInitialize() and DoShutdown(). | |
| 284 SyncBackendRegistrar* registrar_; | |
| 285 | |
| 286 // The timer used to periodically call SaveChanges. | |
| 287 scoped_ptr<base::RepeatingTimer<Core> > save_changes_timer_; | |
| 288 | |
| 289 // Our encryptor, which uses Chrome's encryption functions. | |
| 290 ChromeEncryptor encryptor_; | |
| 291 | |
| 292 // A special ChangeProcessor that tracks the DEVICE_INFO type for us. | |
| 293 scoped_ptr<SyncedDeviceTracker> synced_device_tracker_; | |
| 294 | |
| 295 // The top-level syncapi entry point. Lives on the sync thread. | |
| 296 scoped_ptr<syncer::SyncManager> sync_manager_; | |
| 297 | |
| 298 // Temporary holder of sync manager's initialization results. Set by | |
| 299 // OnInitializeComplete, and consumed when we pass it via OnBackendInitialized | |
| 300 // in the final state of HandleInitializationSuccessOnFrontendLoop. | |
| 301 syncer::WeakHandle<syncer::JsBackend> js_backend_; | |
| 302 syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_; | |
| 303 | |
| 304 // These signals allow us to send requests to shut down the HttpBridgeFactory | |
| 305 // and ServerConnectionManager without having to wait for those classes to | |
| 306 // finish initializing first. | |
| 307 // | |
| 308 // See comments in Core::ShutdownOnUIThread() for more details. | |
| 309 syncer::CancelationSignal release_request_context_signal_; | |
| 310 syncer::CancelationSignal stop_syncing_signal_; | |
| 311 | |
| 312 // Matches the value of SyncPref's HasSyncSetupCompleted() flag at init time. | |
| 313 // Should not be used for anything except for UMAs and logging. | |
| 314 const bool has_sync_setup_completed_; | |
| 315 | |
| 316 base::WeakPtrFactory<Core> weak_ptr_factory_; | |
| 317 | |
| 318 DISALLOW_COPY_AND_ASSIGN(Core); | |
| 319 }; | |
| 320 | |
| 321 SyncBackendHost::SyncBackendHost( | |
| 322 const std::string& name, | |
| 323 Profile* profile, | |
| 324 const base::WeakPtr<SyncPrefs>& sync_prefs) | |
| 325 : frontend_loop_(base::MessageLoop::current()), | |
| 326 profile_(profile), | |
| 327 name_(name), | |
| 328 initialized_(false), | |
| 329 sync_prefs_(sync_prefs), | |
| 330 frontend_(NULL), | |
| 331 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE), | |
| 332 invalidator_( | |
| 333 invalidation::InvalidationServiceFactory::GetForProfile(profile)), | |
| 334 invalidation_handler_registered_(false), | |
| 335 weak_ptr_factory_(this) { | |
| 336 core_ = new Core(name_, profile_->GetPath().Append(kSyncDataFolderName), | |
| 337 sync_prefs_->HasSyncSetupCompleted(), | |
| 338 weak_ptr_factory_.GetWeakPtr()); | |
| 339 } | |
| 340 | |
| 341 SyncBackendHost::SyncBackendHost(Profile* profile) | |
| 342 : frontend_loop_(base::MessageLoop::current()), | |
| 343 profile_(profile), | |
| 344 name_("Unknown"), | |
| 345 initialized_(false), | |
| 346 frontend_(NULL), | |
| 347 cached_passphrase_type_(syncer::IMPLICIT_PASSPHRASE), | |
| 348 invalidation_handler_registered_(false), | |
| 349 weak_ptr_factory_(this) { | |
| 350 } | |
| 351 | |
| 352 SyncBackendHost::~SyncBackendHost() { | |
| 353 DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor."; | |
| 354 DCHECK(!registrar_.get()); | |
| 355 } | |
| 356 | |
| 357 void SyncBackendHost::Initialize( | |
| 358 SyncFrontend* frontend, | |
| 359 scoped_ptr<base::Thread> sync_thread, | |
| 360 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, | |
| 361 const GURL& sync_service_url, | |
| 362 const SyncCredentials& credentials, | |
| 363 bool delete_sync_data_folder, | |
| 364 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory, | |
| 365 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler, | |
| 366 syncer::ReportUnrecoverableErrorFunction | |
| 367 report_unrecoverable_error_function) { | |
| 368 registrar_.reset(new SyncBackendRegistrar(name_, | |
| 369 profile_, | |
| 370 sync_thread.Pass())); | |
| 371 CHECK(registrar_->sync_thread()); | |
| 372 | |
| 373 frontend_ = frontend; | |
| 374 DCHECK(frontend); | |
| 375 | |
| 376 syncer::ModelSafeRoutingInfo routing_info; | |
| 377 std::vector<syncer::ModelSafeWorker*> workers; | |
| 378 registrar_->GetModelSafeRoutingInfo(&routing_info); | |
| 379 registrar_->GetWorkers(&workers); | |
| 380 | |
| 381 InternalComponentsFactory::Switches factory_switches = { | |
| 382 InternalComponentsFactory::ENCRYPTION_KEYSTORE, | |
| 383 InternalComponentsFactory::BACKOFF_NORMAL | |
| 384 }; | |
| 385 | |
| 386 CommandLine* cl = CommandLine::ForCurrentProcess(); | |
| 387 if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) { | |
| 388 factory_switches.backoff_override = | |
| 389 InternalComponentsFactoryImpl::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE; | |
| 390 } | |
| 391 if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) { | |
| 392 factory_switches.pre_commit_updates_policy = | |
| 393 InternalComponentsFactoryImpl::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE; | |
| 394 } | |
| 395 | |
| 396 scoped_ptr<DoInitializeOptions> init_opts(new DoInitializeOptions( | |
| 397 registrar_->sync_thread()->message_loop(), | |
| 398 registrar_.get(), | |
| 399 routing_info, | |
| 400 workers, | |
| 401 extensions_activity_monitor_.GetExtensionsActivity(), | |
| 402 event_handler, | |
| 403 sync_service_url, | |
| 404 scoped_ptr<syncer::HttpPostProviderFactory>( | |
| 405 new syncer::HttpBridgeFactory( | |
| 406 make_scoped_refptr(profile_->GetRequestContext()), | |
| 407 NetworkTimeTracker::BuildNotifierUpdateCallback(), | |
| 408 core_->GetRequestContextCancelationSignal())), | |
| 409 credentials, | |
| 410 invalidator_->GetInvalidatorClientId(), | |
| 411 sync_manager_factory.Pass(), | |
| 412 delete_sync_data_folder, | |
| 413 sync_prefs_->GetEncryptionBootstrapToken(), | |
| 414 sync_prefs_->GetKeystoreEncryptionBootstrapToken(), | |
| 415 scoped_ptr<InternalComponentsFactory>( | |
| 416 new InternalComponentsFactoryImpl(factory_switches)).Pass(), | |
| 417 unrecoverable_error_handler.Pass(), | |
| 418 report_unrecoverable_error_function)); | |
| 419 InitCore(init_opts.Pass()); | |
| 420 } | |
| 421 | |
| 422 void SyncBackendHost::UpdateCredentials(const SyncCredentials& credentials) { | |
| 423 DCHECK(registrar_->sync_thread()->IsRunning()); | |
| 424 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 425 base::Bind(&SyncBackendHost::Core::DoUpdateCredentials, | |
| 426 core_.get(), | |
| 427 credentials)); | |
| 428 } | |
| 429 | |
| 430 void SyncBackendHost::StartSyncingWithServer() { | |
| 431 SDVLOG(1) << "SyncBackendHost::StartSyncingWithServer called."; | |
| 432 | |
| 433 syncer::ModelSafeRoutingInfo routing_info; | |
| 434 registrar_->GetModelSafeRoutingInfo(&routing_info); | |
| 435 | |
| 436 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 437 base::Bind(&SyncBackendHost::Core::DoStartSyncing, | |
| 438 core_.get(), routing_info)); | |
| 439 } | |
| 440 | |
| 441 void SyncBackendHost::SetEncryptionPassphrase(const std::string& passphrase, | |
| 442 bool is_explicit) { | |
| 443 DCHECK(registrar_->sync_thread()->IsRunning()); | |
| 444 if (!IsNigoriEnabled()) { | |
| 445 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori" | |
| 446 " is disabled."; | |
| 447 return; | |
| 448 } | |
| 449 | |
| 450 // We should never be called with an empty passphrase. | |
| 451 DCHECK(!passphrase.empty()); | |
| 452 | |
| 453 // This should only be called by the frontend. | |
| 454 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 455 | |
| 456 // SetEncryptionPassphrase should never be called if we are currently | |
| 457 // encrypted with an explicit passphrase. | |
| 458 DCHECK(cached_passphrase_type_ == syncer::KEYSTORE_PASSPHRASE || | |
| 459 cached_passphrase_type_ == syncer::IMPLICIT_PASSPHRASE); | |
| 460 | |
| 461 // Post an encryption task on the syncer thread. | |
| 462 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 463 base::Bind(&SyncBackendHost::Core::DoSetEncryptionPassphrase, | |
| 464 core_.get(), | |
| 465 passphrase, is_explicit)); | |
| 466 } | |
| 467 | |
| 468 bool SyncBackendHost::SetDecryptionPassphrase(const std::string& passphrase) { | |
| 469 if (!IsNigoriEnabled()) { | |
| 470 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori" | |
| 471 " is disabled."; | |
| 472 return false; | |
| 473 } | |
| 474 | |
| 475 // We should never be called with an empty passphrase. | |
| 476 DCHECK(!passphrase.empty()); | |
| 477 | |
| 478 // This should only be called by the frontend. | |
| 479 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 480 | |
| 481 // This should only be called when we have cached pending keys. | |
| 482 DCHECK(cached_pending_keys_.has_blob()); | |
| 483 | |
| 484 // Check the passphrase that was provided against our local cache of the | |
| 485 // cryptographer's pending keys. If this was unsuccessful, the UI layer can | |
| 486 // immediately call OnPassphraseRequired without showing the user a spinner. | |
| 487 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase)) | |
| 488 return false; | |
| 489 | |
| 490 // Post a decryption task on the syncer thread. | |
| 491 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 492 base::Bind(&SyncBackendHost::Core::DoSetDecryptionPassphrase, | |
| 493 core_.get(), | |
| 494 passphrase)); | |
| 495 | |
| 496 // Since we were able to decrypt the cached pending keys with the passphrase | |
| 497 // provided, we immediately alert the UI layer that the passphrase was | |
| 498 // accepted. This will avoid the situation where a user enters a passphrase, | |
| 499 // clicks OK, immediately reopens the advanced settings dialog, and gets an | |
| 500 // unnecessary prompt for a passphrase. | |
| 501 // Note: It is not guaranteed that the passphrase will be accepted by the | |
| 502 // syncer thread, since we could receive a new nigori node while the task is | |
| 503 // pending. This scenario is a valid race, and SetDecryptionPassphrase can | |
| 504 // trigger a new OnPassphraseRequired if it needs to. | |
| 505 NotifyPassphraseAccepted(); | |
| 506 return true; | |
| 507 } | |
| 508 | |
| 509 void SyncBackendHost::StopSyncingForShutdown() { | |
| 510 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 511 | |
| 512 // Immediately stop sending messages to the frontend. | |
| 513 frontend_ = NULL; | |
| 514 | |
| 515 // Stop listening for and forwarding locally-triggered sync refresh requests. | |
| 516 notification_registrar_.RemoveAll(); | |
| 517 | |
| 518 DCHECK(registrar_->sync_thread()->IsRunning()); | |
| 519 | |
| 520 registrar_->RequestWorkerStopOnUIThread(); | |
| 521 | |
| 522 core_->ShutdownOnUIThread(); | |
| 523 } | |
| 524 | |
| 525 scoped_ptr<base::Thread> SyncBackendHost::Shutdown(ShutdownOption option) { | |
| 526 // StopSyncingForShutdown() (which nulls out |frontend_|) should be | |
| 527 // called first. | |
| 528 DCHECK(!frontend_); | |
| 529 DCHECK(registrar_->sync_thread()->IsRunning()); | |
| 530 | |
| 531 bool sync_disabled = (option == DISABLE_AND_CLAIM_THREAD); | |
| 532 bool sync_thread_claimed = | |
| 533 (option == DISABLE_AND_CLAIM_THREAD || option == STOP_AND_CLAIM_THREAD); | |
| 534 | |
| 535 if (invalidation_handler_registered_) { | |
| 536 if (sync_disabled) { | |
| 537 UnregisterInvalidationIds(); | |
| 538 } | |
| 539 invalidator_->UnregisterInvalidationHandler(this); | |
| 540 invalidator_ = NULL; | |
| 541 } | |
| 542 invalidation_handler_registered_ = false; | |
| 543 | |
| 544 // Shut down and destroy sync manager. | |
| 545 registrar_->sync_thread()->message_loop()->PostTask( | |
| 546 FROM_HERE, | |
| 547 base::Bind(&SyncBackendHost::Core::DoShutdown, | |
| 548 core_.get(), sync_disabled)); | |
| 549 core_ = NULL; | |
| 550 | |
| 551 // Worker cleanup. | |
| 552 SyncBackendRegistrar* detached_registrar = registrar_.release(); | |
| 553 detached_registrar->sync_thread()->message_loop()->PostTask( | |
| 554 FROM_HERE, | |
| 555 base::Bind(&SyncBackendRegistrar::Shutdown, | |
| 556 base::Unretained(detached_registrar))); | |
| 557 | |
| 558 if (sync_thread_claimed) | |
| 559 return detached_registrar->ReleaseSyncThread(); | |
| 560 else | |
| 561 return scoped_ptr<base::Thread>(); | |
| 562 } | |
| 563 | |
| 564 void SyncBackendHost::UnregisterInvalidationIds() { | |
| 565 if (invalidation_handler_registered_) { | |
| 566 invalidator_->UpdateRegisteredInvalidationIds( | |
| 567 this, | |
| 568 syncer::ObjectIdSet()); | |
| 569 } | |
| 570 } | |
| 571 | |
| 572 void SyncBackendHost::ConfigureDataTypes( | |
| 573 syncer::ConfigureReason reason, | |
| 574 const DataTypeConfigStateMap& config_state_map, | |
| 575 const base::Callback<void(syncer::ModelTypeSet, | |
| 576 syncer::ModelTypeSet)>& ready_task, | |
| 577 const base::Callback<void()>& retry_callback) { | |
| 578 // Only one configure is allowed at a time. This is guaranteed by our | |
| 579 // callers. The SyncBackendHost requests one configure as the backend is | |
| 580 // initializing and waits for it to complete. After initialization, all | |
| 581 // configurations will pass through the DataTypeManager, which is careful to | |
| 582 // never send a new configure request until the current request succeeds. | |
| 583 | |
| 584 // The SyncBackendRegistrar's routing info will be updated by adding the | |
| 585 // types_to_add to the list then removing types_to_remove. Any types which | |
| 586 // are not in either of those sets will remain untouched. | |
| 587 // | |
| 588 // Types which were not in the list previously are not fully downloaded, so we | |
| 589 // must ask the syncer to download them. Any newly supported datatypes will | |
| 590 // not have been in that routing info list, so they will be among the types | |
| 591 // downloaded if they are enabled. | |
| 592 // | |
| 593 // The SyncBackendRegistrar's state was initially derived from the types | |
| 594 // detected to have been downloaded in the database. Afterwards it is | |
| 595 // modified only by this function. We expect it to remain in sync with the | |
| 596 // backend because configuration requests are never aborted; they are retried | |
| 597 // until they succeed or the backend is shut down. | |
| 598 | |
| 599 syncer::ModelTypeSet previous_types = registrar_->GetLastConfiguredTypes(); | |
| 600 | |
| 601 syncer::ModelTypeSet disabled_types = | |
| 602 GetDataTypesInState(DISABLED, config_state_map); | |
| 603 syncer::ModelTypeSet fatal_types = | |
| 604 GetDataTypesInState(FATAL, config_state_map); | |
| 605 syncer::ModelTypeSet crypto_types = | |
| 606 GetDataTypesInState(CRYPTO, config_state_map); | |
| 607 disabled_types.PutAll(fatal_types); | |
| 608 disabled_types.PutAll(crypto_types); | |
| 609 syncer::ModelTypeSet active_types = | |
| 610 GetDataTypesInState(CONFIGURE_ACTIVE, config_state_map); | |
| 611 syncer::ModelTypeSet clean_first_types = | |
| 612 GetDataTypesInState(CONFIGURE_CLEAN, config_state_map); | |
| 613 syncer::ModelTypeSet types_to_download = registrar_->ConfigureDataTypes( | |
| 614 syncer::Union(active_types, clean_first_types), | |
| 615 disabled_types); | |
| 616 types_to_download.PutAll(clean_first_types); | |
| 617 types_to_download.RemoveAll(syncer::ProxyTypes()); | |
| 618 if (!types_to_download.Empty()) | |
| 619 types_to_download.Put(syncer::NIGORI); | |
| 620 | |
| 621 // TODO(sync): crbug.com/137550. | |
| 622 // It's dangerous to configure types that have progress markers. Types with | |
| 623 // progress markers can trigger a MIGRATION_DONE response. We are not | |
| 624 // prepared to handle a migration during a configure, so we must ensure that | |
| 625 // all our types_to_download actually contain no data before we sync them. | |
| 626 // | |
| 627 // One common way to end up in this situation used to be types which | |
| 628 // downloaded some or all of their data but have not applied it yet. We avoid | |
| 629 // problems with those types by purging the data of any such partially synced | |
| 630 // types soon after we load the directory. | |
| 631 // | |
| 632 // Another possible scenario is that we have newly supported or newly enabled | |
| 633 // data types being downloaded here but the nigori type, which is always | |
| 634 // included in any GetUpdates request, requires migration. The server has | |
| 635 // code to detect this scenario based on the configure reason, the fact that | |
| 636 // the nigori type is the only requested type which requires migration, and | |
| 637 // that the requested types list includes at least one non-nigori type. It | |
| 638 // will not send a MIGRATION_DONE response in that case. We still need to be | |
| 639 // careful to not send progress markers for non-nigori types, though. If a | |
| 640 // non-nigori type in the request requires migration, a MIGRATION_DONE | |
| 641 // response will be sent. | |
| 642 | |
| 643 syncer::ModelSafeRoutingInfo routing_info; | |
| 644 registrar_->GetModelSafeRoutingInfo(&routing_info); | |
| 645 | |
| 646 syncer::ModelTypeSet current_types = registrar_->GetLastConfiguredTypes(); | |
| 647 syncer::ModelTypeSet types_to_purge = | |
| 648 syncer::Difference(previous_types, current_types); | |
| 649 syncer::ModelTypeSet inactive_types = | |
| 650 GetDataTypesInState(CONFIGURE_INACTIVE, config_state_map); | |
| 651 types_to_purge.RemoveAll(inactive_types); | |
| 652 | |
| 653 // If a type has already been disabled and unapplied or journaled, it will | |
| 654 // not be part of the |types_to_purge| set, and therefore does not need | |
| 655 // to be acted on again. | |
| 656 fatal_types.RetainAll(types_to_purge); | |
| 657 syncer::ModelTypeSet unapply_types = | |
| 658 syncer::Union(crypto_types, clean_first_types); | |
| 659 unapply_types.RetainAll(types_to_purge); | |
| 660 | |
| 661 DCHECK(syncer::Intersection(current_types, fatal_types).Empty()); | |
| 662 DCHECK(syncer::Intersection(current_types, crypto_types).Empty()); | |
| 663 DCHECK(current_types.HasAll(types_to_download)); | |
| 664 | |
| 665 SDVLOG(1) << "Types " | |
| 666 << syncer::ModelTypeSetToString(types_to_download) | |
| 667 << " added; calling DoConfigureSyncer"; | |
| 668 // Divide up the types into their corresponding actions (each is mutually | |
| 669 // exclusive): | |
| 670 // - Types which have just been added to the routing info (types_to_download): | |
| 671 // are downloaded. | |
| 672 // - Types which have encountered a fatal error (fatal_types) are deleted | |
| 673 // from the directory and journaled in the delete journal. | |
| 674 // - Types which have encountered a cryptographer error (crypto_types) are | |
| 675 // unapplied (local state is purged but sync state is not). | |
| 676 // - All other types not in the routing info (types just disabled) are deleted | |
| 677 // from the directory. | |
| 678 // - Everything else (enabled types and already disabled types) is not | |
| 679 // touched. | |
| 680 RequestConfigureSyncer(reason, | |
| 681 types_to_download, | |
| 682 types_to_purge, | |
| 683 fatal_types, | |
| 684 unapply_types, | |
| 685 inactive_types, | |
| 686 routing_info, | |
| 687 ready_task, | |
| 688 retry_callback); | |
| 689 } | |
| 690 | |
| 691 void SyncBackendHost::EnableEncryptEverything() { | |
| 692 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 693 base::Bind(&SyncBackendHost::Core::DoEnableEncryptEverything, | |
| 694 core_.get())); | |
| 695 } | |
| 696 | |
| 697 void SyncBackendHost::ActivateDataType( | |
| 698 syncer::ModelType type, syncer::ModelSafeGroup group, | |
| 699 ChangeProcessor* change_processor) { | |
| 700 registrar_->ActivateDataType(type, group, change_processor, GetUserShare()); | |
| 701 } | |
| 702 | |
| 703 void SyncBackendHost::DeactivateDataType(syncer::ModelType type) { | |
| 704 registrar_->DeactivateDataType(type); | |
| 705 } | |
| 706 | |
| 707 syncer::UserShare* SyncBackendHost::GetUserShare() const { | |
| 708 return core_->sync_manager()->GetUserShare(); | |
| 709 } | |
| 710 | |
| 711 SyncBackendHost::Status SyncBackendHost::GetDetailedStatus() { | |
| 712 DCHECK(initialized()); | |
| 713 return core_->sync_manager()->GetDetailedStatus(); | |
| 714 } | |
| 715 | |
| 716 SyncSessionSnapshot SyncBackendHost::GetLastSessionSnapshot() const { | |
| 717 return last_snapshot_; | |
| 718 } | |
| 719 | |
| 720 bool SyncBackendHost::HasUnsyncedItems() const { | |
| 721 DCHECK(initialized()); | |
| 722 return core_->sync_manager()->HasUnsyncedItems(); | |
| 723 } | |
| 724 | |
| 725 bool SyncBackendHost::IsNigoriEnabled() const { | |
| 726 return registrar_.get() && registrar_->IsNigoriEnabled(); | |
| 727 } | |
| 728 | |
| 729 syncer::PassphraseType SyncBackendHost::GetPassphraseType() const { | |
| 730 return cached_passphrase_type_; | |
| 731 } | |
| 732 | |
| 733 base::Time SyncBackendHost::GetExplicitPassphraseTime() const { | |
| 734 return cached_explicit_passphrase_time_; | |
| 735 } | |
| 736 | |
| 737 bool SyncBackendHost::IsCryptographerReady( | |
| 738 const syncer::BaseTransaction* trans) const { | |
| 739 return initialized() && trans->GetCryptographer()->is_ready(); | |
| 740 } | |
| 741 | |
| 742 void SyncBackendHost::GetModelSafeRoutingInfo( | |
| 743 syncer::ModelSafeRoutingInfo* out) const { | |
| 744 if (initialized()) { | |
| 745 CHECK(registrar_.get()); | |
| 746 registrar_->GetModelSafeRoutingInfo(out); | |
| 747 } else { | |
| 748 NOTREACHED(); | |
| 749 } | |
| 750 } | |
| 751 | |
| 752 SyncedDeviceTracker* SyncBackendHost::GetSyncedDeviceTracker() const { | |
| 753 if (!initialized()) | |
| 754 return NULL; | |
| 755 return core_->synced_device_tracker(); | |
| 756 } | |
| 757 | |
| 758 void SyncBackendHost::InitCore(scoped_ptr<DoInitializeOptions> options) { | |
| 759 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 760 base::Bind(&SyncBackendHost::Core::DoInitialize, | |
| 761 core_.get(), base::Passed(&options))); | |
| 762 } | |
| 763 | |
| 764 void SyncBackendHost::RequestConfigureSyncer( | |
| 765 syncer::ConfigureReason reason, | |
| 766 syncer::ModelTypeSet to_download, | |
| 767 syncer::ModelTypeSet to_purge, | |
| 768 syncer::ModelTypeSet to_journal, | |
| 769 syncer::ModelTypeSet to_unapply, | |
| 770 syncer::ModelTypeSet to_ignore, | |
| 771 const syncer::ModelSafeRoutingInfo& routing_info, | |
| 772 const base::Callback<void(syncer::ModelTypeSet, | |
| 773 syncer::ModelTypeSet)>& ready_task, | |
| 774 const base::Closure& retry_callback) { | |
| 775 DoConfigureSyncerTypes config_types; | |
| 776 config_types.to_download = to_download; | |
| 777 config_types.to_purge = to_purge; | |
| 778 config_types.to_journal = to_journal; | |
| 779 config_types.to_unapply = to_unapply; | |
| 780 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 781 base::Bind(&SyncBackendHost::Core::DoConfigureSyncer, | |
| 782 core_.get(), | |
| 783 reason, | |
| 784 config_types, | |
| 785 routing_info, | |
| 786 ready_task, | |
| 787 retry_callback)); | |
| 788 } | |
| 789 | |
| 790 void SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop( | |
| 791 const syncer::ModelTypeSet enabled_types, | |
| 792 const syncer::ModelTypeSet succeeded_configuration_types, | |
| 793 const syncer::ModelTypeSet failed_configuration_types, | |
| 794 const base::Callback<void(syncer::ModelTypeSet, | |
| 795 syncer::ModelTypeSet)>& ready_task) { | |
| 796 if (!frontend_) | |
| 797 return; | |
| 798 | |
| 799 invalidator_->UpdateRegisteredInvalidationIds( | |
| 800 this, | |
| 801 ModelTypeSetToObjectIdSet(enabled_types)); | |
| 802 | |
| 803 if (!ready_task.is_null()) | |
| 804 ready_task.Run(succeeded_configuration_types, failed_configuration_types); | |
| 805 } | |
| 806 | |
| 807 void SyncBackendHost::Observe( | |
| 808 int type, | |
| 809 const content::NotificationSource& source, | |
| 810 const content::NotificationDetails& details) { | |
| 811 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 812 DCHECK_EQ(type, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL); | |
| 813 | |
| 814 content::Details<const syncer::ModelTypeSet> state_details(details); | |
| 815 const syncer::ModelTypeSet& types = *(state_details.ptr()); | |
| 816 registrar_->sync_thread()->message_loop()->PostTask(FROM_HERE, | |
| 817 base::Bind(&SyncBackendHost::Core::DoRefreshTypes, core_.get(), types)); | |
| 818 } | |
| 819 | |
| 820 SyncBackendHost::DoInitializeOptions::DoInitializeOptions( | |
| 821 base::MessageLoop* sync_loop, | |
| 822 SyncBackendRegistrar* registrar, | |
| 823 const syncer::ModelSafeRoutingInfo& routing_info, | |
| 824 const std::vector<syncer::ModelSafeWorker*>& workers, | |
| 825 const scoped_refptr<syncer::ExtensionsActivity>& extensions_activity, | |
| 826 const syncer::WeakHandle<syncer::JsEventHandler>& event_handler, | |
| 827 const GURL& service_url, | |
| 828 scoped_ptr<syncer::HttpPostProviderFactory> http_bridge_factory, | |
| 829 const syncer::SyncCredentials& credentials, | |
| 830 const std::string& invalidator_client_id, | |
| 831 scoped_ptr<syncer::SyncManagerFactory> sync_manager_factory, | |
| 832 bool delete_sync_data_folder, | |
| 833 const std::string& restored_key_for_bootstrapping, | |
| 834 const std::string& restored_keystore_key_for_bootstrapping, | |
| 835 scoped_ptr<InternalComponentsFactory> internal_components_factory, | |
| 836 scoped_ptr<syncer::UnrecoverableErrorHandler> unrecoverable_error_handler, | |
| 837 syncer::ReportUnrecoverableErrorFunction | |
| 838 report_unrecoverable_error_function) | |
| 839 : sync_loop(sync_loop), | |
| 840 registrar(registrar), | |
| 841 routing_info(routing_info), | |
| 842 workers(workers), | |
| 843 extensions_activity(extensions_activity), | |
| 844 event_handler(event_handler), | |
| 845 service_url(service_url), | |
| 846 http_bridge_factory(http_bridge_factory.Pass()), | |
| 847 credentials(credentials), | |
| 848 invalidator_client_id(invalidator_client_id), | |
| 849 sync_manager_factory(sync_manager_factory.Pass()), | |
| 850 delete_sync_data_folder(delete_sync_data_folder), | |
| 851 restored_key_for_bootstrapping(restored_key_for_bootstrapping), | |
| 852 restored_keystore_key_for_bootstrapping( | |
| 853 restored_keystore_key_for_bootstrapping), | |
| 854 internal_components_factory(internal_components_factory.Pass()), | |
| 855 unrecoverable_error_handler(unrecoverable_error_handler.Pass()), | |
| 856 report_unrecoverable_error_function( | |
| 857 report_unrecoverable_error_function) { | |
| 858 } | |
| 859 | |
| 860 SyncBackendHost::DoInitializeOptions::~DoInitializeOptions() {} | |
| 861 | |
| 862 SyncBackendHost::Core::Core(const std::string& name, | |
| 863 const base::FilePath& sync_data_folder_path, | |
| 864 bool has_sync_setup_completed, | |
| 865 const base::WeakPtr<SyncBackendHost>& backend) | |
| 866 : name_(name), | |
| 867 sync_data_folder_path_(sync_data_folder_path), | |
| 868 host_(backend), | |
| 869 sync_loop_(NULL), | |
| 870 registrar_(NULL), | |
| 871 has_sync_setup_completed_(has_sync_setup_completed), | |
| 872 weak_ptr_factory_(this) { | |
| 873 DCHECK(backend.get()); | |
| 874 } | |
| 875 | |
| 876 SyncBackendHost::Core::~Core() { | |
| 877 DCHECK(!sync_manager_.get()); | |
| 878 } | |
| 879 | |
| 880 void SyncBackendHost::Core::OnSyncCycleCompleted( | |
| 881 const SyncSessionSnapshot& snapshot) { | |
| 882 if (!sync_loop_) | |
| 883 return; | |
| 884 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 885 | |
| 886 host_.Call( | |
| 887 FROM_HERE, | |
| 888 &SyncBackendHost::HandleSyncCycleCompletedOnFrontendLoop, | |
| 889 snapshot); | |
| 890 } | |
| 891 | |
| 892 void SyncBackendHost::Core::DoRefreshTypes(syncer::ModelTypeSet types) { | |
| 893 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 894 sync_manager_->RefreshTypes(types); | |
| 895 } | |
| 896 | |
| 897 void SyncBackendHost::Core::OnControlTypesDownloadRetry() { | |
| 898 host_.Call(FROM_HERE, | |
| 899 &SyncBackendHost::HandleControlTypesDownloadRetry); | |
| 900 } | |
| 901 | |
| 902 void SyncBackendHost::Core::OnInitializationComplete( | |
| 903 const syncer::WeakHandle<syncer::JsBackend>& js_backend, | |
| 904 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>& | |
| 905 debug_info_listener, | |
| 906 bool success, | |
| 907 const syncer::ModelTypeSet restored_types) { | |
| 908 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 909 | |
| 910 if (!success) { | |
| 911 DoDestroySyncManager(); | |
| 912 host_.Call(FROM_HERE, | |
| 913 &SyncBackendHost::HandleInitializationFailureOnFrontendLoop); | |
| 914 return; | |
| 915 } | |
| 916 | |
| 917 // Register for encryption related changes now. We have to do this before | |
| 918 // the initializing downloading control types or initializing the encryption | |
| 919 // handler in order to receive notifications triggered during encryption | |
| 920 // startup. | |
| 921 sync_manager_->GetEncryptionHandler()->AddObserver(this); | |
| 922 | |
| 923 // Sync manager initialization is complete, so we can schedule recurring | |
| 924 // SaveChanges. | |
| 925 sync_loop_->PostTask(FROM_HERE, | |
| 926 base::Bind(&Core::StartSavingChanges, | |
| 927 weak_ptr_factory_.GetWeakPtr())); | |
| 928 | |
| 929 // Hang on to these for a while longer. We're not ready to hand them back to | |
| 930 // the UI thread yet. | |
| 931 js_backend_ = js_backend; | |
| 932 debug_info_listener_ = debug_info_listener; | |
| 933 | |
| 934 // Track whether or not sync DB and preferences were in sync. | |
| 935 SyncBackendInitState backend_init_state; | |
| 936 if (has_sync_setup_completed_ && !restored_types.Empty()) { | |
| 937 backend_init_state = SETUP_COMPLETED_FOUND_RESTORED_TYPES; | |
| 938 } else if (has_sync_setup_completed_ && restored_types.Empty()) { | |
| 939 backend_init_state = SETUP_COMPLETED_NO_RESTORED_TYPES; | |
| 940 } else if (!has_sync_setup_completed_ && restored_types.Empty()) { | |
| 941 backend_init_state = FIRST_SETUP_NO_RESTORED_TYPES; | |
| 942 } else { // (!has_sync_setup_completed_ && !restored_types.Empty()) | |
| 943 backend_init_state = FIRST_SETUP_RESTORED_TYPES; | |
| 944 } | |
| 945 | |
| 946 UMA_HISTOGRAM_ENUMERATION("Sync.BackendInitializeRestoreState", | |
| 947 backend_init_state, | |
| 948 SYNC_BACKEND_INIT_STATE_COUNT); | |
| 949 | |
| 950 // Before proceeding any further, we need to download the control types and | |
| 951 // purge any partial data (ie. data downloaded for a type that was on its way | |
| 952 // to being initially synced, but didn't quite make it.). The following | |
| 953 // configure cycle will take care of this. It depends on the registrar state | |
| 954 // which we initialize below to ensure that we don't perform any downloads if | |
| 955 // all control types have already completed their initial sync. | |
| 956 registrar_->SetInitialTypes(restored_types); | |
| 957 | |
| 958 syncer::ConfigureReason reason = | |
| 959 restored_types.Empty() ? | |
| 960 syncer::CONFIGURE_REASON_NEW_CLIENT : | |
| 961 syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE; | |
| 962 | |
| 963 syncer::ModelTypeSet new_control_types = registrar_->ConfigureDataTypes( | |
| 964 syncer::ControlTypes(), syncer::ModelTypeSet()); | |
| 965 syncer::ModelSafeRoutingInfo routing_info; | |
| 966 registrar_->GetModelSafeRoutingInfo(&routing_info); | |
| 967 SDVLOG(1) << "Control Types " | |
| 968 << syncer::ModelTypeSetToString(new_control_types) | |
| 969 << " added; calling ConfigureSyncer"; | |
| 970 | |
| 971 syncer::ModelTypeSet types_to_purge = | |
| 972 syncer::Difference(syncer::ModelTypeSet::All(), | |
| 973 GetRoutingInfoTypes(routing_info)); | |
| 974 | |
| 975 sync_manager_->ConfigureSyncer( | |
| 976 reason, | |
| 977 new_control_types, | |
| 978 types_to_purge, | |
| 979 syncer::ModelTypeSet(), | |
| 980 syncer::ModelTypeSet(), | |
| 981 routing_info, | |
| 982 base::Bind(&SyncBackendHost::Core::DoInitialProcessControlTypes, | |
| 983 weak_ptr_factory_.GetWeakPtr()), | |
| 984 base::Bind(&SyncBackendHost::Core::OnControlTypesDownloadRetry, | |
| 985 weak_ptr_factory_.GetWeakPtr())); | |
| 986 } | |
| 987 | |
| 988 void SyncBackendHost::Core::OnConnectionStatusChange( | |
| 989 syncer::ConnectionStatus status) { | |
| 990 if (!sync_loop_) | |
| 991 return; | |
| 992 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 993 host_.Call( | |
| 994 FROM_HERE, | |
| 995 &SyncBackendHost::HandleConnectionStatusChangeOnFrontendLoop, status); | |
| 996 } | |
| 997 | |
| 998 void SyncBackendHost::Core::OnPassphraseRequired( | |
| 999 syncer::PassphraseRequiredReason reason, | |
| 1000 const sync_pb::EncryptedData& pending_keys) { | |
| 1001 if (!sync_loop_) | |
| 1002 return; | |
| 1003 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1004 host_.Call( | |
| 1005 FROM_HERE, | |
| 1006 &SyncBackendHost::NotifyPassphraseRequired, reason, pending_keys); | |
| 1007 } | |
| 1008 | |
| 1009 void SyncBackendHost::Core::OnPassphraseAccepted() { | |
| 1010 if (!sync_loop_) | |
| 1011 return; | |
| 1012 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1013 host_.Call( | |
| 1014 FROM_HERE, | |
| 1015 &SyncBackendHost::NotifyPassphraseAccepted); | |
| 1016 } | |
| 1017 | |
| 1018 void SyncBackendHost::Core::OnBootstrapTokenUpdated( | |
| 1019 const std::string& bootstrap_token, | |
| 1020 syncer::BootstrapTokenType type) { | |
| 1021 if (!sync_loop_) | |
| 1022 return; | |
| 1023 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1024 host_.Call(FROM_HERE, | |
| 1025 &SyncBackendHost::PersistEncryptionBootstrapToken, | |
| 1026 bootstrap_token, | |
| 1027 type); | |
| 1028 } | |
| 1029 | |
| 1030 void SyncBackendHost::Core::OnStopSyncingPermanently() { | |
| 1031 if (!sync_loop_) | |
| 1032 return; | |
| 1033 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1034 host_.Call( | |
| 1035 FROM_HERE, | |
| 1036 &SyncBackendHost::HandleStopSyncingPermanentlyOnFrontendLoop); | |
| 1037 } | |
| 1038 | |
| 1039 void SyncBackendHost::Core::OnEncryptedTypesChanged( | |
| 1040 syncer::ModelTypeSet encrypted_types, | |
| 1041 bool encrypt_everything) { | |
| 1042 if (!sync_loop_) | |
| 1043 return; | |
| 1044 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1045 // NOTE: We're in a transaction. | |
| 1046 host_.Call( | |
| 1047 FROM_HERE, | |
| 1048 &SyncBackendHost::NotifyEncryptedTypesChanged, | |
| 1049 encrypted_types, encrypt_everything); | |
| 1050 } | |
| 1051 | |
| 1052 void SyncBackendHost::Core::OnEncryptionComplete() { | |
| 1053 if (!sync_loop_) | |
| 1054 return; | |
| 1055 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1056 // NOTE: We're in a transaction. | |
| 1057 host_.Call( | |
| 1058 FROM_HERE, | |
| 1059 &SyncBackendHost::NotifyEncryptionComplete); | |
| 1060 } | |
| 1061 | |
| 1062 void SyncBackendHost::Core::OnCryptographerStateChanged( | |
| 1063 syncer::Cryptographer* cryptographer) { | |
| 1064 // Do nothing. | |
| 1065 } | |
| 1066 | |
| 1067 void SyncBackendHost::Core::OnPassphraseTypeChanged( | |
| 1068 syncer::PassphraseType type, base::Time passphrase_time) { | |
| 1069 host_.Call( | |
| 1070 FROM_HERE, | |
| 1071 &SyncBackendHost::HandlePassphraseTypeChangedOnFrontendLoop, | |
| 1072 type, passphrase_time); | |
| 1073 } | |
| 1074 | |
| 1075 void SyncBackendHost::Core::OnActionableError( | |
| 1076 const syncer::SyncProtocolError& sync_error) { | |
| 1077 if (!sync_loop_) | |
| 1078 return; | |
| 1079 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1080 host_.Call( | |
| 1081 FROM_HERE, | |
| 1082 &SyncBackendHost::HandleActionableErrorEventOnFrontendLoop, | |
| 1083 sync_error); | |
| 1084 } | |
| 1085 | |
| 1086 void SyncBackendHost::Core::DoOnInvalidatorStateChange( | |
| 1087 syncer::InvalidatorState state) { | |
| 1088 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1089 sync_manager_->OnInvalidatorStateChange(state); | |
| 1090 } | |
| 1091 | |
| 1092 void SyncBackendHost::Core::DoOnIncomingInvalidation( | |
| 1093 syncer::ObjectIdInvalidationMap invalidation_map) { | |
| 1094 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1095 sync_manager_->OnIncomingInvalidation(invalidation_map); | |
| 1096 } | |
| 1097 | |
| 1098 void SyncBackendHost::Core::DoInitialize( | |
| 1099 scoped_ptr<DoInitializeOptions> options) { | |
| 1100 DCHECK(!sync_loop_); | |
| 1101 sync_loop_ = options->sync_loop; | |
| 1102 DCHECK(sync_loop_); | |
| 1103 | |
| 1104 // Finish initializing the HttpBridgeFactory. We do this here because | |
| 1105 // building the user agent may block on some platforms. | |
| 1106 chrome::VersionInfo version_info; | |
| 1107 options->http_bridge_factory->Init( | |
| 1108 DeviceInfo::MakeUserAgentForSyncApi(version_info)); | |
| 1109 | |
| 1110 // Blow away the partial or corrupt sync data folder before doing any more | |
| 1111 // initialization, if necessary. | |
| 1112 if (options->delete_sync_data_folder) { | |
| 1113 DeleteSyncDataFolder(); | |
| 1114 } | |
| 1115 | |
| 1116 // Make sure that the directory exists before initializing the backend. | |
| 1117 // If it already exists, this will do no harm. | |
| 1118 if (!file_util::CreateDirectory(sync_data_folder_path_)) { | |
| 1119 DLOG(FATAL) << "Sync Data directory creation failed."; | |
| 1120 } | |
| 1121 | |
| 1122 DCHECK(!registrar_); | |
| 1123 registrar_ = options->registrar; | |
| 1124 DCHECK(registrar_); | |
| 1125 | |
| 1126 sync_manager_ = options->sync_manager_factory->CreateSyncManager(name_); | |
| 1127 sync_manager_->AddObserver(this); | |
| 1128 sync_manager_->Init(sync_data_folder_path_, | |
| 1129 options->event_handler, | |
| 1130 options->service_url.host() + options->service_url.path(), | |
| 1131 options->service_url.EffectiveIntPort(), | |
| 1132 options->service_url.SchemeIsSecure(), | |
| 1133 options->http_bridge_factory.Pass(), | |
| 1134 options->workers, | |
| 1135 options->extensions_activity, | |
| 1136 options->registrar /* as SyncManager::ChangeDelegate */, | |
| 1137 options->credentials, | |
| 1138 options->invalidator_client_id, | |
| 1139 options->restored_key_for_bootstrapping, | |
| 1140 options->restored_keystore_key_for_bootstrapping, | |
| 1141 options->internal_components_factory.get(), | |
| 1142 &encryptor_, | |
| 1143 options->unrecoverable_error_handler.Pass(), | |
| 1144 options->report_unrecoverable_error_function, | |
| 1145 &stop_syncing_signal_); | |
| 1146 | |
| 1147 // |sync_manager_| may end up being NULL here in tests (in | |
| 1148 // synchronous initialization mode). | |
| 1149 // | |
| 1150 // TODO(akalin): Fix this behavior (see http://crbug.com/140354). | |
| 1151 if (sync_manager_) { | |
| 1152 // Now check the command line to see if we need to simulate an | |
| 1153 // unrecoverable error for testing purpose. Note the error is thrown | |
| 1154 // only if the initialization succeeded. Also it makes sense to use this | |
| 1155 // flag only when restarting the browser with an account already setup. If | |
| 1156 // you use this before setting up the setup would not succeed as an error | |
| 1157 // would be encountered. | |
| 1158 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
| 1159 switches::kSyncThrowUnrecoverableError)) { | |
| 1160 sync_manager_->ThrowUnrecoverableError(); | |
| 1161 } | |
| 1162 } | |
| 1163 } | |
| 1164 | |
| 1165 void SyncBackendHost::Core::DoUpdateCredentials( | |
| 1166 const SyncCredentials& credentials) { | |
| 1167 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1168 // UpdateCredentials can be called during backend initialization, possibly | |
| 1169 // when backend initialization has failed but hasn't notified the UI thread | |
| 1170 // yet. In that case, the sync manager may have been destroyed on the sync | |
| 1171 // thread before this task was executed, so we do nothing. | |
| 1172 if (sync_manager_) { | |
| 1173 sync_manager_->UpdateCredentials(credentials); | |
| 1174 } | |
| 1175 } | |
| 1176 | |
| 1177 void SyncBackendHost::Core::DoStartSyncing( | |
| 1178 const syncer::ModelSafeRoutingInfo& routing_info) { | |
| 1179 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1180 sync_manager_->StartSyncingNormally(routing_info); | |
| 1181 } | |
| 1182 | |
| 1183 void SyncBackendHost::Core::DoSetEncryptionPassphrase( | |
| 1184 const std::string& passphrase, | |
| 1185 bool is_explicit) { | |
| 1186 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1187 sync_manager_->GetEncryptionHandler()->SetEncryptionPassphrase( | |
| 1188 passphrase, is_explicit); | |
| 1189 } | |
| 1190 | |
| 1191 void SyncBackendHost::Core::DoInitialProcessControlTypes() { | |
| 1192 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1193 | |
| 1194 DVLOG(1) << "Initilalizing Control Types"; | |
| 1195 | |
| 1196 // Initialize encryption. | |
| 1197 sync_manager_->GetEncryptionHandler()->Init(); | |
| 1198 | |
| 1199 // Note: experiments are currently handled via SBH::AddExperimentalTypes, | |
| 1200 // which is called at the end of every sync cycle. | |
| 1201 // TODO(zea): eventually add an experiment handler and initialize it here. | |
| 1202 | |
| 1203 if (!sync_manager_->GetUserShare()) { // NULL in some tests. | |
| 1204 DVLOG(1) << "Skipping initialization of DeviceInfo"; | |
| 1205 host_.Call( | |
| 1206 FROM_HERE, | |
| 1207 &SyncBackendHost::HandleInitializationFailureOnFrontendLoop); | |
| 1208 return; | |
| 1209 } | |
| 1210 | |
| 1211 if (!sync_manager_->InitialSyncEndedTypes().HasAll(syncer::ControlTypes())) { | |
| 1212 LOG(ERROR) << "Failed to download control types"; | |
| 1213 host_.Call( | |
| 1214 FROM_HERE, | |
| 1215 &SyncBackendHost::HandleInitializationFailureOnFrontendLoop); | |
| 1216 return; | |
| 1217 } | |
| 1218 | |
| 1219 // Initialize device info. This is asynchronous on some platforms, so we | |
| 1220 // provide a callback for when it finishes. | |
| 1221 synced_device_tracker_.reset( | |
| 1222 new SyncedDeviceTracker(sync_manager_->GetUserShare(), | |
| 1223 sync_manager_->cache_guid())); | |
| 1224 synced_device_tracker_->InitLocalDeviceInfo( | |
| 1225 base::Bind(&SyncBackendHost::Core::DoFinishInitialProcessControlTypes, | |
| 1226 weak_ptr_factory_.GetWeakPtr())); | |
| 1227 } | |
| 1228 | |
| 1229 void SyncBackendHost::Core::DoFinishInitialProcessControlTypes() { | |
| 1230 registrar_->ActivateDataType(syncer::DEVICE_INFO, | |
| 1231 syncer::GROUP_PASSIVE, | |
| 1232 synced_device_tracker_.get(), | |
| 1233 sync_manager_->GetUserShare()); | |
| 1234 | |
| 1235 host_.Call( | |
| 1236 FROM_HERE, | |
| 1237 &SyncBackendHost::HandleInitializationSuccessOnFrontendLoop, | |
| 1238 js_backend_, | |
| 1239 debug_info_listener_); | |
| 1240 | |
| 1241 js_backend_.Reset(); | |
| 1242 debug_info_listener_.Reset(); | |
| 1243 } | |
| 1244 | |
| 1245 void SyncBackendHost::Core::DoSetDecryptionPassphrase( | |
| 1246 const std::string& passphrase) { | |
| 1247 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1248 sync_manager_->GetEncryptionHandler()->SetDecryptionPassphrase( | |
| 1249 passphrase); | |
| 1250 } | |
| 1251 | |
| 1252 void SyncBackendHost::Core::DoEnableEncryptEverything() { | |
| 1253 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1254 sync_manager_->GetEncryptionHandler()->EnableEncryptEverything(); | |
| 1255 } | |
| 1256 | |
| 1257 void SyncBackendHost::Core::ShutdownOnUIThread() { | |
| 1258 // This will cut short any blocking network tasks, cut short any in-progress | |
| 1259 // sync cycles, and prevent the creation of new blocking network tasks and new | |
| 1260 // sync cycles. If there was an in-progress network request, it would have | |
| 1261 // had a reference to the RequestContextGetter. This reference will be | |
| 1262 // dropped by the time this function returns. | |
| 1263 // | |
| 1264 // It is safe to call this even if Sync's backend classes have not been | |
| 1265 // initialized yet. Those classes will receive the message when the sync | |
| 1266 // thread finally getes around to constructing them. | |
| 1267 stop_syncing_signal_.Signal(); | |
| 1268 | |
| 1269 // This will drop the HttpBridgeFactory's reference to the | |
| 1270 // RequestContextGetter. Once this has been called, the HttpBridgeFactory can | |
| 1271 // no longer be used to create new HttpBridge instances. We can get away with | |
| 1272 // this because the stop_syncing_signal_ has already been signalled, which | |
| 1273 // guarantees that the ServerConnectionManager will no longer attempt to | |
| 1274 // create new connections. | |
| 1275 release_request_context_signal_.Signal(); | |
| 1276 } | |
| 1277 | |
| 1278 void SyncBackendHost::Core::DoShutdown(bool sync_disabled) { | |
| 1279 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1280 | |
| 1281 // It's safe to do this even if the type was never activated. | |
| 1282 registrar_->DeactivateDataType(syncer::DEVICE_INFO); | |
| 1283 synced_device_tracker_.reset(); | |
| 1284 | |
| 1285 DoDestroySyncManager(); | |
| 1286 | |
| 1287 registrar_ = NULL; | |
| 1288 | |
| 1289 if (sync_disabled) | |
| 1290 DeleteSyncDataFolder(); | |
| 1291 | |
| 1292 host_.Reset(); | |
| 1293 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 1294 } | |
| 1295 | |
| 1296 void SyncBackendHost::Core::DoDestroySyncManager() { | |
| 1297 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1298 if (sync_manager_) { | |
| 1299 save_changes_timer_.reset(); | |
| 1300 sync_manager_->RemoveObserver(this); | |
| 1301 sync_manager_->ShutdownOnSyncThread(); | |
| 1302 sync_manager_.reset(); | |
| 1303 } | |
| 1304 } | |
| 1305 | |
| 1306 void SyncBackendHost::Core::DoConfigureSyncer( | |
| 1307 syncer::ConfigureReason reason, | |
| 1308 const DoConfigureSyncerTypes& config_types, | |
| 1309 const syncer::ModelSafeRoutingInfo routing_info, | |
| 1310 const base::Callback<void(syncer::ModelTypeSet, | |
| 1311 syncer::ModelTypeSet)>& ready_task, | |
| 1312 const base::Closure& retry_callback) { | |
| 1313 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1314 sync_manager_->ConfigureSyncer( | |
| 1315 reason, | |
| 1316 config_types.to_download, | |
| 1317 config_types.to_purge, | |
| 1318 config_types.to_journal, | |
| 1319 config_types.to_unapply, | |
| 1320 routing_info, | |
| 1321 base::Bind(&SyncBackendHost::Core::DoFinishConfigureDataTypes, | |
| 1322 weak_ptr_factory_.GetWeakPtr(), | |
| 1323 config_types.to_download, | |
| 1324 ready_task), | |
| 1325 base::Bind(&SyncBackendHost::Core::DoRetryConfiguration, | |
| 1326 weak_ptr_factory_.GetWeakPtr(), | |
| 1327 retry_callback)); | |
| 1328 } | |
| 1329 | |
| 1330 void SyncBackendHost::Core::DoFinishConfigureDataTypes( | |
| 1331 syncer::ModelTypeSet types_to_config, | |
| 1332 const base::Callback<void(syncer::ModelTypeSet, | |
| 1333 syncer::ModelTypeSet)>& ready_task) { | |
| 1334 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1335 | |
| 1336 // Update the enabled types for the bridge and sync manager. | |
| 1337 syncer::ModelSafeRoutingInfo routing_info; | |
| 1338 registrar_->GetModelSafeRoutingInfo(&routing_info); | |
| 1339 syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info); | |
| 1340 enabled_types.RemoveAll(syncer::ProxyTypes()); | |
| 1341 | |
| 1342 const syncer::ModelTypeSet failed_configuration_types = | |
| 1343 Difference(types_to_config, sync_manager_->InitialSyncEndedTypes()); | |
| 1344 const syncer::ModelTypeSet succeeded_configuration_types = | |
| 1345 Difference(types_to_config, failed_configuration_types); | |
| 1346 host_.Call(FROM_HERE, | |
| 1347 &SyncBackendHost::FinishConfigureDataTypesOnFrontendLoop, | |
| 1348 enabled_types, | |
| 1349 succeeded_configuration_types, | |
| 1350 failed_configuration_types, | |
| 1351 ready_task); | |
| 1352 } | |
| 1353 | |
| 1354 void SyncBackendHost::Core::DoRetryConfiguration( | |
| 1355 const base::Closure& retry_callback) { | |
| 1356 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1357 host_.Call(FROM_HERE, | |
| 1358 &SyncBackendHost::RetryConfigurationOnFrontendLoop, | |
| 1359 retry_callback); | |
| 1360 } | |
| 1361 | |
| 1362 void SyncBackendHost::Core::DeleteSyncDataFolder() { | |
| 1363 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1364 if (base::DirectoryExists(sync_data_folder_path_)) { | |
| 1365 if (!base::DeleteFile(sync_data_folder_path_, true)) | |
| 1366 SLOG(DFATAL) << "Could not delete the Sync Data folder."; | |
| 1367 } | |
| 1368 } | |
| 1369 | |
| 1370 void SyncBackendHost::Core::StartSavingChanges() { | |
| 1371 // We may already be shut down. | |
| 1372 if (!sync_loop_) | |
| 1373 return; | |
| 1374 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1375 DCHECK(!save_changes_timer_.get()); | |
| 1376 save_changes_timer_.reset(new base::RepeatingTimer<Core>()); | |
| 1377 save_changes_timer_->Start(FROM_HERE, | |
| 1378 base::TimeDelta::FromSeconds(kSaveChangesIntervalSeconds), | |
| 1379 this, &Core::SaveChanges); | |
| 1380 } | |
| 1381 | |
| 1382 void SyncBackendHost::Core::SaveChanges() { | |
| 1383 DCHECK_EQ(base::MessageLoop::current(), sync_loop_); | |
| 1384 sync_manager_->SaveChanges(); | |
| 1385 } | |
| 1386 | |
| 1387 void SyncBackendHost::AddExperimentalTypes() { | |
| 1388 CHECK(initialized()); | |
| 1389 syncer::Experiments experiments; | |
| 1390 if (core_->sync_manager()->ReceivedExperiment(&experiments)) | |
| 1391 frontend_->OnExperimentsChanged(experiments); | |
| 1392 } | |
| 1393 | |
| 1394 void SyncBackendHost::HandleControlTypesDownloadRetry() { | |
| 1395 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1396 if (!frontend_) | |
| 1397 return; | |
| 1398 | |
| 1399 frontend_->OnSyncConfigureRetry(); | |
| 1400 } | |
| 1401 | |
| 1402 void SyncBackendHost::HandleInitializationSuccessOnFrontendLoop( | |
| 1403 const syncer::WeakHandle<syncer::JsBackend> js_backend, | |
| 1404 const syncer::WeakHandle<syncer::DataTypeDebugInfoListener> | |
| 1405 debug_info_listener) { | |
| 1406 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1407 if (!frontend_) | |
| 1408 return; | |
| 1409 | |
| 1410 initialized_ = true; | |
| 1411 | |
| 1412 invalidator_->RegisterInvalidationHandler(this); | |
| 1413 invalidation_handler_registered_ = true; | |
| 1414 | |
| 1415 // Fake a state change to initialize the SyncManager's cached invalidator | |
| 1416 // state. | |
| 1417 OnInvalidatorStateChange(invalidator_->GetInvalidatorState()); | |
| 1418 | |
| 1419 // Start forwarding refresh requests to the SyncManager | |
| 1420 notification_registrar_.Add(this, chrome::NOTIFICATION_SYNC_REFRESH_LOCAL, | |
| 1421 content::Source<Profile>(profile_)); | |
| 1422 | |
| 1423 // Now that we've downloaded the control types, we can see if there are any | |
| 1424 // experimental types to enable. This should be done before we inform | |
| 1425 // the frontend to ensure they're visible in the customize screen. | |
| 1426 AddExperimentalTypes(); | |
| 1427 frontend_->OnBackendInitialized(js_backend, | |
| 1428 debug_info_listener, | |
| 1429 true); | |
| 1430 } | |
| 1431 | |
| 1432 void SyncBackendHost::HandleInitializationFailureOnFrontendLoop() { | |
| 1433 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1434 if (!frontend_) | |
| 1435 return; | |
| 1436 | |
| 1437 frontend_->OnBackendInitialized( | |
| 1438 syncer::WeakHandle<syncer::JsBackend>(), | |
| 1439 syncer::WeakHandle<syncer::DataTypeDebugInfoListener>(), | |
| 1440 false); | |
| 1441 } | |
| 1442 | |
| 1443 void SyncBackendHost::HandleSyncCycleCompletedOnFrontendLoop( | |
| 1444 const SyncSessionSnapshot& snapshot) { | |
| 1445 if (!frontend_) | |
| 1446 return; | |
| 1447 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1448 | |
| 1449 last_snapshot_ = snapshot; | |
| 1450 | |
| 1451 SDVLOG(1) << "Got snapshot " << snapshot.ToString(); | |
| 1452 | |
| 1453 const syncer::ModelTypeSet to_migrate = | |
| 1454 snapshot.model_neutral_state().types_needing_local_migration; | |
| 1455 if (!to_migrate.Empty()) | |
| 1456 frontend_->OnMigrationNeededForTypes(to_migrate); | |
| 1457 | |
| 1458 // Process any changes to the datatypes we're syncing. | |
| 1459 // TODO(sync): add support for removing types. | |
| 1460 if (initialized()) | |
| 1461 AddExperimentalTypes(); | |
| 1462 | |
| 1463 if (initialized()) | |
| 1464 frontend_->OnSyncCycleCompleted(); | |
| 1465 } | |
| 1466 | |
| 1467 void SyncBackendHost::RetryConfigurationOnFrontendLoop( | |
| 1468 const base::Closure& retry_callback) { | |
| 1469 SDVLOG(1) << "Failed to complete configuration, informing of retry."; | |
| 1470 retry_callback.Run(); | |
| 1471 } | |
| 1472 | |
| 1473 void SyncBackendHost::PersistEncryptionBootstrapToken( | |
| 1474 const std::string& token, | |
| 1475 syncer::BootstrapTokenType token_type) { | |
| 1476 CHECK(sync_prefs_.get()); | |
| 1477 DCHECK(!token.empty()); | |
| 1478 if (token_type == syncer::PASSPHRASE_BOOTSTRAP_TOKEN) | |
| 1479 sync_prefs_->SetEncryptionBootstrapToken(token); | |
| 1480 else | |
| 1481 sync_prefs_->SetKeystoreEncryptionBootstrapToken(token); | |
| 1482 } | |
| 1483 | |
| 1484 void SyncBackendHost::HandleActionableErrorEventOnFrontendLoop( | |
| 1485 const syncer::SyncProtocolError& sync_error) { | |
| 1486 if (!frontend_) | |
| 1487 return; | |
| 1488 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1489 frontend_->OnActionableError(sync_error); | |
| 1490 } | |
| 1491 | |
| 1492 void SyncBackendHost::OnInvalidatorStateChange(syncer::InvalidatorState state) { | |
| 1493 registrar_->sync_thread()->message_loop()->PostTask( | |
| 1494 FROM_HERE, | |
| 1495 base::Bind(&SyncBackendHost::Core::DoOnInvalidatorStateChange, | |
| 1496 core_.get(), | |
| 1497 state)); | |
| 1498 } | |
| 1499 | |
| 1500 void SyncBackendHost::OnIncomingInvalidation( | |
| 1501 const syncer::ObjectIdInvalidationMap& invalidation_map) { | |
| 1502 // TODO(rlarocque): Acknowledge these invalidations only after the syncer has | |
| 1503 // acted on them and saved the results to disk. | |
| 1504 syncer::ObjectIdSet ids = invalidation_map.GetObjectIds(); | |
| 1505 for (syncer::ObjectIdSet::const_iterator it = ids.begin(); | |
| 1506 it != ids.end(); ++it) { | |
| 1507 const syncer::AckHandle& handle = | |
| 1508 invalidation_map.ForObject(*it).back().ack_handle(); | |
| 1509 invalidator_->AcknowledgeInvalidation(*it, handle); | |
| 1510 } | |
| 1511 | |
| 1512 registrar_->sync_thread()->message_loop()->PostTask( | |
| 1513 FROM_HERE, | |
| 1514 base::Bind(&SyncBackendHost::Core::DoOnIncomingInvalidation, | |
| 1515 core_.get(), | |
| 1516 invalidation_map)); | |
| 1517 } | |
| 1518 | |
| 1519 bool SyncBackendHost::CheckPassphraseAgainstCachedPendingKeys( | |
| 1520 const std::string& passphrase) const { | |
| 1521 DCHECK(cached_pending_keys_.has_blob()); | |
| 1522 DCHECK(!passphrase.empty()); | |
| 1523 syncer::Nigori nigori; | |
| 1524 nigori.InitByDerivation("localhost", "dummy", passphrase); | |
| 1525 std::string plaintext; | |
| 1526 bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext); | |
| 1527 DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys."; | |
| 1528 return result; | |
| 1529 } | |
| 1530 | |
| 1531 void SyncBackendHost::NotifyPassphraseRequired( | |
| 1532 syncer::PassphraseRequiredReason reason, | |
| 1533 sync_pb::EncryptedData pending_keys) { | |
| 1534 if (!frontend_) | |
| 1535 return; | |
| 1536 | |
| 1537 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1538 | |
| 1539 // Update our cache of the cryptographer's pending keys. | |
| 1540 cached_pending_keys_ = pending_keys; | |
| 1541 | |
| 1542 frontend_->OnPassphraseRequired(reason, pending_keys); | |
| 1543 } | |
| 1544 | |
| 1545 void SyncBackendHost::NotifyPassphraseAccepted() { | |
| 1546 if (!frontend_) | |
| 1547 return; | |
| 1548 | |
| 1549 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1550 | |
| 1551 // Clear our cache of the cryptographer's pending keys. | |
| 1552 cached_pending_keys_.clear_blob(); | |
| 1553 frontend_->OnPassphraseAccepted(); | |
| 1554 } | |
| 1555 | |
| 1556 void SyncBackendHost::NotifyEncryptedTypesChanged( | |
| 1557 syncer::ModelTypeSet encrypted_types, | |
| 1558 bool encrypt_everything) { | |
| 1559 if (!frontend_) | |
| 1560 return; | |
| 1561 | |
| 1562 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1563 frontend_->OnEncryptedTypesChanged( | |
| 1564 encrypted_types, encrypt_everything); | |
| 1565 } | |
| 1566 | |
| 1567 void SyncBackendHost::NotifyEncryptionComplete() { | |
| 1568 if (!frontend_) | |
| 1569 return; | |
| 1570 | |
| 1571 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1572 frontend_->OnEncryptionComplete(); | |
| 1573 } | |
| 1574 | |
| 1575 void SyncBackendHost::HandlePassphraseTypeChangedOnFrontendLoop( | |
| 1576 syncer::PassphraseType type, | |
| 1577 base::Time explicit_passphrase_time) { | |
| 1578 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1579 DVLOG(1) << "Passphrase type changed to " | |
| 1580 << syncer::PassphraseTypeToString(type); | |
| 1581 cached_passphrase_type_ = type; | |
| 1582 cached_explicit_passphrase_time_ = explicit_passphrase_time; | |
| 1583 } | |
| 1584 | |
| 1585 void SyncBackendHost::HandleStopSyncingPermanentlyOnFrontendLoop() { | |
| 1586 if (!frontend_) | |
| 1587 return; | |
| 1588 frontend_->OnStopSyncingPermanently(); | |
| 1589 } | |
| 1590 | |
| 1591 void SyncBackendHost::HandleConnectionStatusChangeOnFrontendLoop( | |
| 1592 syncer::ConnectionStatus status) { | |
| 1593 if (!frontend_) | |
| 1594 return; | |
| 1595 | |
| 1596 DCHECK_EQ(base::MessageLoop::current(), frontend_loop_); | |
| 1597 | |
| 1598 DVLOG(1) << "Connection status changed: " | |
| 1599 << syncer::ConnectionStatusToString(status); | |
| 1600 frontend_->OnConnectionStatusChange(status); | |
| 1601 } | |
| 1602 | |
| 1603 base::MessageLoop* SyncBackendHost::GetSyncLoopForTesting() { | |
| 1604 return registrar_->sync_thread()->message_loop(); | |
| 1605 } | |
| 1606 | |
| 1607 #undef SDVLOG | |
| 1608 | |
| 1609 #undef SLOG | |
| 1610 | 12 |
| 1611 } // namespace browser_sync | 13 } // namespace browser_sync |
| OLD | NEW |