• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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