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 |