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