• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "sync/internal_api/sync_manager_impl.h"
6 
7 #include <string>
8 
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/json/json_writer.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/metrics/histogram.h"
16 #include "base/observer_list.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/values.h"
19 #include "sync/engine/sync_scheduler.h"
20 #include "sync/engine/syncer_types.h"
21 #include "sync/internal_api/change_reorder_buffer.h"
22 #include "sync/internal_api/public/base/cancelation_signal.h"
23 #include "sync/internal_api/public/base/model_type.h"
24 #include "sync/internal_api/public/base_node.h"
25 #include "sync/internal_api/public/configure_reason.h"
26 #include "sync/internal_api/public/engine/polling_constants.h"
27 #include "sync/internal_api/public/http_post_provider_factory.h"
28 #include "sync/internal_api/public/internal_components_factory.h"
29 #include "sync/internal_api/public/read_node.h"
30 #include "sync/internal_api/public/read_transaction.h"
31 #include "sync/internal_api/public/sync_core_proxy.h"
32 #include "sync/internal_api/public/user_share.h"
33 #include "sync/internal_api/public/util/experiments.h"
34 #include "sync/internal_api/public/write_node.h"
35 #include "sync/internal_api/public/write_transaction.h"
36 #include "sync/internal_api/sync_core.h"
37 #include "sync/internal_api/sync_core_proxy_impl.h"
38 #include "sync/internal_api/syncapi_internal.h"
39 #include "sync/internal_api/syncapi_server_connection_manager.h"
40 #include "sync/notifier/invalidation_util.h"
41 #include "sync/notifier/invalidator.h"
42 #include "sync/notifier/object_id_invalidation_map.h"
43 #include "sync/protocol/proto_value_conversions.h"
44 #include "sync/protocol/sync.pb.h"
45 #include "sync/sessions/directory_type_debug_info_emitter.h"
46 #include "sync/syncable/directory.h"
47 #include "sync/syncable/entry.h"
48 #include "sync/syncable/in_memory_directory_backing_store.h"
49 #include "sync/syncable/on_disk_directory_backing_store.h"
50 
51 using base::TimeDelta;
52 using sync_pb::GetUpdatesCallerInfo;
53 
54 namespace syncer {
55 
56 using sessions::SyncSessionContext;
57 using syncable::ImmutableWriteTransactionInfo;
58 using syncable::SPECIFICS;
59 using syncable::UNIQUE_POSITION;
60 
61 namespace {
62 
63 // Delays for syncer nudges.
64 static const int kDefaultNudgeDelayMilliseconds = 200;
65 static const int kPreferencesNudgeDelayMilliseconds = 2000;
66 static const int kSyncRefreshDelayMsec = 500;
67 static const int kSyncSchedulerDelayMsec = 250;
68 
GetSourceFromReason(ConfigureReason reason)69 GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason(
70     ConfigureReason reason) {
71   switch (reason) {
72     case CONFIGURE_REASON_RECONFIGURATION:
73       return GetUpdatesCallerInfo::RECONFIGURATION;
74     case CONFIGURE_REASON_MIGRATION:
75       return GetUpdatesCallerInfo::MIGRATION;
76     case CONFIGURE_REASON_NEW_CLIENT:
77       return GetUpdatesCallerInfo::NEW_CLIENT;
78     case CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE:
79     case CONFIGURE_REASON_CRYPTO:
80       return GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE;
81     default:
82       NOTREACHED();
83   }
84   return GetUpdatesCallerInfo::UNKNOWN;
85 }
86 
87 }  // namespace
88 
89 // A class to calculate nudge delays for types.
90 class NudgeStrategy {
91  public:
GetNudgeDelayTimeDelta(const ModelType & model_type,SyncManagerImpl * core)92   static TimeDelta GetNudgeDelayTimeDelta(const ModelType& model_type,
93                                           SyncManagerImpl* core) {
94     NudgeDelayStrategy delay_type = GetNudgeDelayStrategy(model_type);
95     return GetNudgeDelayTimeDeltaFromType(delay_type,
96                                           model_type,
97                                           core);
98   }
99 
100  private:
101   // Possible types of nudge delay for datatypes.
102   // Note: These are just hints. If a sync happens then all dirty entries
103   // would be committed as part of the sync.
104   enum NudgeDelayStrategy {
105     // Sync right away.
106     IMMEDIATE,
107 
108     // Sync this change while syncing another change.
109     ACCOMPANY_ONLY,
110 
111     // The datatype does not use one of the predefined wait times but defines
112     // its own wait time logic for nudge.
113     CUSTOM,
114   };
115 
GetNudgeDelayStrategy(const ModelType & type)116   static NudgeDelayStrategy GetNudgeDelayStrategy(const ModelType& type) {
117     switch (type) {
118      case AUTOFILL:
119        return ACCOMPANY_ONLY;
120      case PREFERENCES:
121      case SESSIONS:
122      case FAVICON_IMAGES:
123      case FAVICON_TRACKING:
124        return CUSTOM;
125      default:
126        return IMMEDIATE;
127     }
128   }
129 
GetNudgeDelayTimeDeltaFromType(const NudgeDelayStrategy & delay_type,const ModelType & model_type,const SyncManagerImpl * core)130   static TimeDelta GetNudgeDelayTimeDeltaFromType(
131       const NudgeDelayStrategy& delay_type, const ModelType& model_type,
132       const SyncManagerImpl* core) {
133     CHECK(core);
134     TimeDelta delay = TimeDelta::FromMilliseconds(
135        kDefaultNudgeDelayMilliseconds);
136     switch (delay_type) {
137      case IMMEDIATE:
138        delay = TimeDelta::FromMilliseconds(
139            kDefaultNudgeDelayMilliseconds);
140        break;
141      case ACCOMPANY_ONLY:
142        delay = TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds);
143        break;
144      case CUSTOM:
145        switch (model_type) {
146          case PREFERENCES:
147            delay = TimeDelta::FromMilliseconds(
148                kPreferencesNudgeDelayMilliseconds);
149            break;
150          case SESSIONS:
151          case FAVICON_IMAGES:
152          case FAVICON_TRACKING:
153            delay = core->scheduler()->GetSessionsCommitDelay();
154            break;
155          default:
156            NOTREACHED();
157        }
158        break;
159      default:
160        NOTREACHED();
161     }
162     return delay;
163   }
164 };
165 
SyncManagerImpl(const std::string & name)166 SyncManagerImpl::SyncManagerImpl(const std::string& name)
167     : name_(name),
168       change_delegate_(NULL),
169       initialized_(false),
170       observing_network_connectivity_changes_(false),
171       invalidator_state_(DEFAULT_INVALIDATION_ERROR),
172       report_unrecoverable_error_function_(NULL),
173       weak_ptr_factory_(this) {
174   // Pre-fill |notification_info_map_|.
175   for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
176     notification_info_map_.insert(
177         std::make_pair(ModelTypeFromInt(i), NotificationInfo()));
178   }
179 }
180 
~SyncManagerImpl()181 SyncManagerImpl::~SyncManagerImpl() {
182   DCHECK(thread_checker_.CalledOnValidThread());
183   CHECK(!initialized_);
184 }
185 
NotificationInfo()186 SyncManagerImpl::NotificationInfo::NotificationInfo() : total_count(0) {}
~NotificationInfo()187 SyncManagerImpl::NotificationInfo::~NotificationInfo() {}
188 
ToValue() const189 base::DictionaryValue* SyncManagerImpl::NotificationInfo::ToValue() const {
190   base::DictionaryValue* value = new base::DictionaryValue();
191   value->SetInteger("totalCount", total_count);
192   value->SetString("payload", payload);
193   return value;
194 }
195 
VisiblePositionsDiffer(const syncable::EntryKernelMutation & mutation) const196 bool SyncManagerImpl::VisiblePositionsDiffer(
197     const syncable::EntryKernelMutation& mutation) const {
198   const syncable::EntryKernel& a = mutation.original;
199   const syncable::EntryKernel& b = mutation.mutated;
200   if (!b.ShouldMaintainPosition())
201     return false;
202   if (!a.ref(UNIQUE_POSITION).Equals(b.ref(UNIQUE_POSITION)))
203     return true;
204   if (a.ref(syncable::PARENT_ID) != b.ref(syncable::PARENT_ID))
205     return true;
206   return false;
207 }
208 
VisiblePropertiesDiffer(const syncable::EntryKernelMutation & mutation,Cryptographer * cryptographer) const209 bool SyncManagerImpl::VisiblePropertiesDiffer(
210     const syncable::EntryKernelMutation& mutation,
211     Cryptographer* cryptographer) const {
212   const syncable::EntryKernel& a = mutation.original;
213   const syncable::EntryKernel& b = mutation.mutated;
214   const sync_pb::EntitySpecifics& a_specifics = a.ref(SPECIFICS);
215   const sync_pb::EntitySpecifics& b_specifics = b.ref(SPECIFICS);
216   DCHECK_EQ(GetModelTypeFromSpecifics(a_specifics),
217             GetModelTypeFromSpecifics(b_specifics));
218   ModelType model_type = GetModelTypeFromSpecifics(b_specifics);
219   // Suppress updates to items that aren't tracked by any browser model.
220   if (model_type < FIRST_REAL_MODEL_TYPE ||
221       !a.ref(syncable::UNIQUE_SERVER_TAG).empty()) {
222     return false;
223   }
224   if (a.ref(syncable::IS_DIR) != b.ref(syncable::IS_DIR))
225     return true;
226   if (!AreSpecificsEqual(cryptographer,
227                          a.ref(syncable::SPECIFICS),
228                          b.ref(syncable::SPECIFICS))) {
229     return true;
230   }
231   // We only care if the name has changed if neither specifics is encrypted
232   // (encrypted nodes blow away the NON_UNIQUE_NAME).
233   if (!a_specifics.has_encrypted() && !b_specifics.has_encrypted() &&
234       a.ref(syncable::NON_UNIQUE_NAME) != b.ref(syncable::NON_UNIQUE_NAME))
235     return true;
236   if (VisiblePositionsDiffer(mutation))
237     return true;
238   return false;
239 }
240 
InitialSyncEndedTypes()241 ModelTypeSet SyncManagerImpl::InitialSyncEndedTypes() {
242   return directory()->InitialSyncEndedTypes();
243 }
244 
GetTypesWithEmptyProgressMarkerToken(ModelTypeSet types)245 ModelTypeSet SyncManagerImpl::GetTypesWithEmptyProgressMarkerToken(
246     ModelTypeSet types) {
247   ModelTypeSet result;
248   for (ModelTypeSet::Iterator i = types.First(); i.Good(); i.Inc()) {
249     sync_pb::DataTypeProgressMarker marker;
250     directory()->GetDownloadProgress(i.Get(), &marker);
251 
252     if (marker.token().empty())
253       result.Put(i.Get());
254   }
255   return result;
256 }
257 
ConfigureSyncer(ConfigureReason reason,ModelTypeSet to_download,ModelTypeSet to_purge,ModelTypeSet to_journal,ModelTypeSet to_unapply,const ModelSafeRoutingInfo & new_routing_info,const base::Closure & ready_task,const base::Closure & retry_task)258 void SyncManagerImpl::ConfigureSyncer(
259     ConfigureReason reason,
260     ModelTypeSet to_download,
261     ModelTypeSet to_purge,
262     ModelTypeSet to_journal,
263     ModelTypeSet to_unapply,
264     const ModelSafeRoutingInfo& new_routing_info,
265     const base::Closure& ready_task,
266     const base::Closure& retry_task) {
267   DCHECK(thread_checker_.CalledOnValidThread());
268   DCHECK(!ready_task.is_null());
269   DCHECK(!retry_task.is_null());
270 
271   DVLOG(1) << "Configuring -"
272            << "\n\t" << "current types: "
273            << ModelTypeSetToString(GetRoutingInfoTypes(new_routing_info))
274            << "\n\t" << "types to download: "
275            << ModelTypeSetToString(to_download)
276            << "\n\t" << "types to purge: "
277            << ModelTypeSetToString(to_purge)
278            << "\n\t" << "types to journal: "
279            << ModelTypeSetToString(to_journal)
280            << "\n\t" << "types to unapply: "
281            << ModelTypeSetToString(to_unapply);
282   if (!PurgeDisabledTypes(to_purge,
283                           to_journal,
284                           to_unapply)) {
285     // We failed to cleanup the types. Invoke the ready task without actually
286     // configuring any types. The caller should detect this as a configuration
287     // failure and act appropriately.
288     ready_task.Run();
289     return;
290   }
291 
292   ConfigurationParams params(GetSourceFromReason(reason),
293                              to_download,
294                              new_routing_info,
295                              ready_task,
296                              retry_task);
297 
298   scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
299   scheduler_->ScheduleConfiguration(params);
300 }
301 
Init(const base::FilePath & database_location,const WeakHandle<JsEventHandler> & event_handler,const std::string & sync_server_and_path,int port,bool use_ssl,scoped_ptr<HttpPostProviderFactory> post_factory,const std::vector<scoped_refptr<ModelSafeWorker>> & workers,ExtensionsActivity * extensions_activity,SyncManager::ChangeDelegate * change_delegate,const SyncCredentials & credentials,const std::string & invalidator_client_id,const std::string & restored_key_for_bootstrapping,const std::string & restored_keystore_key_for_bootstrapping,InternalComponentsFactory * internal_components_factory,Encryptor * encryptor,scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,ReportUnrecoverableErrorFunction report_unrecoverable_error_function,CancelationSignal * cancelation_signal)302 void SyncManagerImpl::Init(
303     const base::FilePath& database_location,
304     const WeakHandle<JsEventHandler>& event_handler,
305     const std::string& sync_server_and_path,
306     int port,
307     bool use_ssl,
308     scoped_ptr<HttpPostProviderFactory> post_factory,
309     const std::vector<scoped_refptr<ModelSafeWorker> >& workers,
310     ExtensionsActivity* extensions_activity,
311     SyncManager::ChangeDelegate* change_delegate,
312     const SyncCredentials& credentials,
313     const std::string& invalidator_client_id,
314     const std::string& restored_key_for_bootstrapping,
315     const std::string& restored_keystore_key_for_bootstrapping,
316     InternalComponentsFactory* internal_components_factory,
317     Encryptor* encryptor,
318     scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
319     ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
320     CancelationSignal* cancelation_signal) {
321   CHECK(!initialized_);
322   DCHECK(thread_checker_.CalledOnValidThread());
323   DCHECK(post_factory.get());
324   DCHECK(!credentials.email.empty());
325   DCHECK(!credentials.sync_token.empty());
326   DCHECK(cancelation_signal);
327   DVLOG(1) << "SyncManager starting Init...";
328 
329   weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
330 
331   change_delegate_ = change_delegate;
332 
333   AddObserver(&js_sync_manager_observer_);
334   SetJsEventHandler(event_handler);
335 
336   AddObserver(&debug_info_event_listener_);
337 
338   database_path_ = database_location.Append(
339       syncable::Directory::kSyncDatabaseFilename);
340   unrecoverable_error_handler_ = unrecoverable_error_handler.Pass();
341   report_unrecoverable_error_function_ = report_unrecoverable_error_function;
342 
343   allstatus_.SetHasKeystoreKey(
344       !restored_keystore_key_for_bootstrapping.empty());
345   sync_encryption_handler_.reset(new SyncEncryptionHandlerImpl(
346       &share_,
347       encryptor,
348       restored_key_for_bootstrapping,
349       restored_keystore_key_for_bootstrapping));
350   sync_encryption_handler_->AddObserver(this);
351   sync_encryption_handler_->AddObserver(&debug_info_event_listener_);
352   sync_encryption_handler_->AddObserver(&js_sync_encryption_handler_observer_);
353 
354   base::FilePath absolute_db_path = database_path_;
355   DCHECK(absolute_db_path.IsAbsolute());
356 
357   scoped_ptr<syncable::DirectoryBackingStore> backing_store =
358       internal_components_factory->BuildDirectoryBackingStore(
359           credentials.email, absolute_db_path).Pass();
360 
361   DCHECK(backing_store.get());
362   const std::string& username = credentials.email;
363   share_.directory.reset(
364       new syncable::Directory(
365           backing_store.release(),
366           unrecoverable_error_handler_.get(),
367           report_unrecoverable_error_function_,
368           sync_encryption_handler_.get(),
369           sync_encryption_handler_->GetCryptographerUnsafe()));
370 
371   DVLOG(1) << "Username: " << username;
372   if (!OpenDirectory(username)) {
373     NotifyInitializationFailure();
374     LOG(ERROR) << "Sync manager initialization failed!";
375     return;
376   }
377 
378   connection_manager_.reset(new SyncAPIServerConnectionManager(
379       sync_server_and_path, port, use_ssl,
380       post_factory.release(), cancelation_signal));
381   connection_manager_->set_client_id(directory()->cache_guid());
382   connection_manager_->AddListener(this);
383 
384   std::string sync_id = directory()->cache_guid();
385 
386   DVLOG(1) << "Setting sync client ID: " << sync_id;
387   allstatus_.SetSyncId(sync_id);
388   DVLOG(1) << "Setting invalidator client ID: " << invalidator_client_id;
389   allstatus_.SetInvalidatorClientId(invalidator_client_id);
390 
391   model_type_registry_.reset(new ModelTypeRegistry(workers, directory()));
392 
393   sync_core_.reset(new SyncCore(model_type_registry_.get()));
394 
395   // Bind the SyncCore WeakPtr to this thread.  This helps us crash earlier if
396   // the pointer is misused in debug mode.
397   base::WeakPtr<SyncCore> weak_core = sync_core_->AsWeakPtr();
398   weak_core.get();
399 
400   sync_core_proxy_.reset(
401       new SyncCoreProxyImpl(base::MessageLoopProxy::current(), weak_core));
402 
403   // Build a SyncSessionContext and store the worker in it.
404   DVLOG(1) << "Sync is bringing up SyncSessionContext.";
405   std::vector<SyncEngineEventListener*> listeners;
406   listeners.push_back(&allstatus_);
407   listeners.push_back(this);
408   session_context_ = internal_components_factory->BuildContext(
409       connection_manager_.get(),
410       directory(),
411       extensions_activity,
412       listeners,
413       &debug_info_event_listener_,
414       model_type_registry_.get(),
415       invalidator_client_id).Pass();
416   session_context_->set_account_name(credentials.email);
417   scheduler_ = internal_components_factory->BuildScheduler(
418       name_, session_context_.get(), cancelation_signal).Pass();
419 
420   scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
421 
422   initialized_ = true;
423 
424   net::NetworkChangeNotifier::AddIPAddressObserver(this);
425   net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
426   observing_network_connectivity_changes_ = true;
427 
428   UpdateCredentials(credentials);
429 
430   NotifyInitializationSuccess();
431 }
432 
NotifyInitializationSuccess()433 void SyncManagerImpl::NotifyInitializationSuccess() {
434   FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
435                     OnInitializationComplete(
436                         MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
437                         MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()),
438                         true, InitialSyncEndedTypes()));
439 }
440 
NotifyInitializationFailure()441 void SyncManagerImpl::NotifyInitializationFailure() {
442   FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
443                     OnInitializationComplete(
444                         MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
445                         MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()),
446                         false, ModelTypeSet()));
447 }
448 
OnPassphraseRequired(PassphraseRequiredReason reason,const sync_pb::EncryptedData & pending_keys)449 void SyncManagerImpl::OnPassphraseRequired(
450     PassphraseRequiredReason reason,
451     const sync_pb::EncryptedData& pending_keys) {
452   // Does nothing.
453 }
454 
OnPassphraseAccepted()455 void SyncManagerImpl::OnPassphraseAccepted() {
456   // Does nothing.
457 }
458 
OnBootstrapTokenUpdated(const std::string & bootstrap_token,BootstrapTokenType type)459 void SyncManagerImpl::OnBootstrapTokenUpdated(
460     const std::string& bootstrap_token,
461     BootstrapTokenType type) {
462   if (type == KEYSTORE_BOOTSTRAP_TOKEN)
463     allstatus_.SetHasKeystoreKey(true);
464 }
465 
OnEncryptedTypesChanged(ModelTypeSet encrypted_types,bool encrypt_everything)466 void SyncManagerImpl::OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
467                                               bool encrypt_everything) {
468   allstatus_.SetEncryptedTypes(encrypted_types);
469 }
470 
OnEncryptionComplete()471 void SyncManagerImpl::OnEncryptionComplete() {
472   // Does nothing.
473 }
474 
OnCryptographerStateChanged(Cryptographer * cryptographer)475 void SyncManagerImpl::OnCryptographerStateChanged(
476     Cryptographer* cryptographer) {
477   allstatus_.SetCryptographerReady(cryptographer->is_ready());
478   allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
479   allstatus_.SetKeystoreMigrationTime(
480       sync_encryption_handler_->migration_time());
481 }
482 
OnPassphraseTypeChanged(PassphraseType type,base::Time explicit_passphrase_time)483 void SyncManagerImpl::OnPassphraseTypeChanged(
484     PassphraseType type,
485     base::Time explicit_passphrase_time) {
486   allstatus_.SetPassphraseType(type);
487   allstatus_.SetKeystoreMigrationTime(
488       sync_encryption_handler_->migration_time());
489 }
490 
StartSyncingNormally(const ModelSafeRoutingInfo & routing_info)491 void SyncManagerImpl::StartSyncingNormally(
492     const ModelSafeRoutingInfo& routing_info) {
493   // Start the sync scheduler.
494   // TODO(sync): We always want the newest set of routes when we switch back
495   // to normal mode. Figure out how to enforce set_routing_info is always
496   // appropriately set and that it's only modified when switching to normal
497   // mode.
498   DCHECK(thread_checker_.CalledOnValidThread());
499   session_context_->SetRoutingInfo(routing_info);
500   scheduler_->Start(SyncScheduler::NORMAL_MODE);
501 }
502 
directory()503 syncable::Directory* SyncManagerImpl::directory() {
504   return share_.directory.get();
505 }
506 
scheduler() const507 const SyncScheduler* SyncManagerImpl::scheduler() const {
508   return scheduler_.get();
509 }
510 
GetHasInvalidAuthTokenForTest() const511 bool SyncManagerImpl::GetHasInvalidAuthTokenForTest() const {
512   return connection_manager_->HasInvalidAuthToken();
513 }
514 
OpenDirectory(const std::string & username)515 bool SyncManagerImpl::OpenDirectory(const std::string& username) {
516   DCHECK(!initialized_) << "Should only happen once";
517 
518   // Set before Open().
519   change_observer_ = MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr());
520   WeakHandle<syncable::TransactionObserver> transaction_observer(
521       MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr()));
522 
523   syncable::DirOpenResult open_result = syncable::NOT_INITIALIZED;
524   open_result = directory()->Open(username, this, transaction_observer);
525   if (open_result != syncable::OPENED) {
526     LOG(ERROR) << "Could not open share for:" << username;
527     return false;
528   }
529 
530   // Unapplied datatypes (those that do not have initial sync ended set) get
531   // re-downloaded during any configuration. But, it's possible for a datatype
532   // to have a progress marker but not have initial sync ended yet, making
533   // it a candidate for migration. This is a problem, as the DataTypeManager
534   // does not support a migration while it's already in the middle of a
535   // configuration. As a result, any partially synced datatype can stall the
536   // DTM, waiting for the configuration to complete, which it never will due
537   // to the migration error. In addition, a partially synced nigori will
538   // trigger the migration logic before the backend is initialized, resulting
539   // in crashes. We therefore detect and purge any partially synced types as
540   // part of initialization.
541   if (!PurgePartiallySyncedTypes())
542     return false;
543 
544   return true;
545 }
546 
PurgePartiallySyncedTypes()547 bool SyncManagerImpl::PurgePartiallySyncedTypes() {
548   ModelTypeSet partially_synced_types = ModelTypeSet::All();
549   partially_synced_types.RemoveAll(InitialSyncEndedTypes());
550   partially_synced_types.RemoveAll(GetTypesWithEmptyProgressMarkerToken(
551       ModelTypeSet::All()));
552 
553   DVLOG(1) << "Purging partially synced types "
554            << ModelTypeSetToString(partially_synced_types);
555   UMA_HISTOGRAM_COUNTS("Sync.PartiallySyncedTypes",
556                        partially_synced_types.Size());
557   if (partially_synced_types.Empty())
558     return true;
559   return directory()->PurgeEntriesWithTypeIn(partially_synced_types,
560                                              ModelTypeSet(),
561                                              ModelTypeSet());
562 }
563 
PurgeDisabledTypes(ModelTypeSet to_purge,ModelTypeSet to_journal,ModelTypeSet to_unapply)564 bool SyncManagerImpl::PurgeDisabledTypes(
565     ModelTypeSet to_purge,
566     ModelTypeSet to_journal,
567     ModelTypeSet to_unapply) {
568   if (to_purge.Empty())
569     return true;
570   DVLOG(1) << "Purging disabled types " << ModelTypeSetToString(to_purge);
571   DCHECK(to_purge.HasAll(to_journal));
572   DCHECK(to_purge.HasAll(to_unapply));
573   return directory()->PurgeEntriesWithTypeIn(to_purge, to_journal, to_unapply);
574 }
575 
UpdateCredentials(const SyncCredentials & credentials)576 void SyncManagerImpl::UpdateCredentials(const SyncCredentials& credentials) {
577   DCHECK(thread_checker_.CalledOnValidThread());
578   DCHECK(initialized_);
579   DCHECK(!credentials.email.empty());
580   DCHECK(!credentials.sync_token.empty());
581 
582   observing_network_connectivity_changes_ = true;
583   if (!connection_manager_->SetAuthToken(credentials.sync_token))
584     return;  // Auth token is known to be invalid, so exit early.
585 
586   scheduler_->OnCredentialsUpdated();
587 
588   // TODO(zea): pass the credential age to the debug info event listener.
589 }
590 
AddObserver(SyncManager::Observer * observer)591 void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) {
592   DCHECK(thread_checker_.CalledOnValidThread());
593   observers_.AddObserver(observer);
594 }
595 
RemoveObserver(SyncManager::Observer * observer)596 void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) {
597   DCHECK(thread_checker_.CalledOnValidThread());
598   observers_.RemoveObserver(observer);
599 }
600 
ShutdownOnSyncThread()601 void SyncManagerImpl::ShutdownOnSyncThread() {
602   DCHECK(thread_checker_.CalledOnValidThread());
603 
604   // Prevent any in-flight method calls from running.  Also
605   // invalidates |weak_handle_this_| and |change_observer_|.
606   weak_ptr_factory_.InvalidateWeakPtrs();
607   js_mutation_event_observer_.InvalidateWeakPtrs();
608 
609   scheduler_.reset();
610   session_context_.reset();
611   model_type_registry_.reset();
612 
613   if (sync_encryption_handler_) {
614     sync_encryption_handler_->RemoveObserver(&debug_info_event_listener_);
615     sync_encryption_handler_->RemoveObserver(this);
616   }
617 
618   SetJsEventHandler(WeakHandle<JsEventHandler>());
619   RemoveObserver(&js_sync_manager_observer_);
620 
621   RemoveObserver(&debug_info_event_listener_);
622 
623   // |connection_manager_| may end up being NULL here in tests (in synchronous
624   // initialization mode).
625   //
626   // TODO(akalin): Fix this behavior.
627   if (connection_manager_)
628     connection_manager_->RemoveListener(this);
629   connection_manager_.reset();
630 
631   net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
632   net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
633   observing_network_connectivity_changes_ = false;
634 
635   if (initialized_ && directory()) {
636     directory()->SaveChanges();
637   }
638 
639   share_.directory.reset();
640 
641   change_delegate_ = NULL;
642 
643   initialized_ = false;
644 
645   // We reset these here, since only now we know they will not be
646   // accessed from other threads (since we shut down everything).
647   change_observer_.Reset();
648   weak_handle_this_.Reset();
649 }
650 
OnIPAddressChanged()651 void SyncManagerImpl::OnIPAddressChanged() {
652   if (!observing_network_connectivity_changes_) {
653     DVLOG(1) << "IP address change dropped.";
654     return;
655   }
656   DVLOG(1) << "IP address change detected.";
657   OnNetworkConnectivityChangedImpl();
658 }
659 
OnConnectionTypeChanged(net::NetworkChangeNotifier::ConnectionType)660 void SyncManagerImpl::OnConnectionTypeChanged(
661   net::NetworkChangeNotifier::ConnectionType) {
662   if (!observing_network_connectivity_changes_) {
663     DVLOG(1) << "Connection type change dropped.";
664     return;
665   }
666   DVLOG(1) << "Connection type change detected.";
667   OnNetworkConnectivityChangedImpl();
668 }
669 
OnNetworkConnectivityChangedImpl()670 void SyncManagerImpl::OnNetworkConnectivityChangedImpl() {
671   DCHECK(thread_checker_.CalledOnValidThread());
672   scheduler_->OnConnectionStatusChange();
673 }
674 
OnServerConnectionEvent(const ServerConnectionEvent & event)675 void SyncManagerImpl::OnServerConnectionEvent(
676     const ServerConnectionEvent& event) {
677   DCHECK(thread_checker_.CalledOnValidThread());
678   if (event.connection_code ==
679       HttpResponse::SERVER_CONNECTION_OK) {
680     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
681                       OnConnectionStatusChange(CONNECTION_OK));
682   }
683 
684   if (event.connection_code == HttpResponse::SYNC_AUTH_ERROR) {
685     observing_network_connectivity_changes_ = false;
686     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
687                       OnConnectionStatusChange(CONNECTION_AUTH_ERROR));
688   }
689 
690   if (event.connection_code == HttpResponse::SYNC_SERVER_ERROR) {
691     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
692                       OnConnectionStatusChange(CONNECTION_SERVER_ERROR));
693   }
694 }
695 
HandleTransactionCompleteChangeEvent(ModelTypeSet models_with_changes)696 void SyncManagerImpl::HandleTransactionCompleteChangeEvent(
697     ModelTypeSet models_with_changes) {
698   // This notification happens immediately after the transaction mutex is
699   // released. This allows work to be performed without blocking other threads
700   // from acquiring a transaction.
701   if (!change_delegate_)
702     return;
703 
704   // Call commit.
705   for (ModelTypeSet::Iterator it = models_with_changes.First();
706        it.Good(); it.Inc()) {
707     change_delegate_->OnChangesComplete(it.Get());
708     change_observer_.Call(
709         FROM_HERE,
710         &SyncManager::ChangeObserver::OnChangesComplete,
711         it.Get());
712   }
713 }
714 
715 ModelTypeSet
HandleTransactionEndingChangeEvent(const ImmutableWriteTransactionInfo & write_transaction_info,syncable::BaseTransaction * trans)716 SyncManagerImpl::HandleTransactionEndingChangeEvent(
717     const ImmutableWriteTransactionInfo& write_transaction_info,
718     syncable::BaseTransaction* trans) {
719   // This notification happens immediately before a syncable WriteTransaction
720   // falls out of scope. It happens while the channel mutex is still held,
721   // and while the transaction mutex is held, so it cannot be re-entrant.
722   if (!change_delegate_ || change_records_.empty())
723     return ModelTypeSet();
724 
725   // This will continue the WriteTransaction using a read only wrapper.
726   // This is the last chance for read to occur in the WriteTransaction
727   // that's closing. This special ReadTransaction will not close the
728   // underlying transaction.
729   ReadTransaction read_trans(GetUserShare(), trans);
730 
731   ModelTypeSet models_with_changes;
732   for (ChangeRecordMap::const_iterator it = change_records_.begin();
733       it != change_records_.end(); ++it) {
734     DCHECK(!it->second.Get().empty());
735     ModelType type = ModelTypeFromInt(it->first);
736     change_delegate_->
737         OnChangesApplied(type, trans->directory()->GetTransactionVersion(type),
738                          &read_trans, it->second);
739     change_observer_.Call(FROM_HERE,
740         &SyncManager::ChangeObserver::OnChangesApplied,
741         type, write_transaction_info.Get().id, it->second);
742     models_with_changes.Put(type);
743   }
744   change_records_.clear();
745   return models_with_changes;
746 }
747 
HandleCalculateChangesChangeEventFromSyncApi(const ImmutableWriteTransactionInfo & write_transaction_info,syncable::BaseTransaction * trans,std::vector<int64> * entries_changed)748 void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncApi(
749     const ImmutableWriteTransactionInfo& write_transaction_info,
750     syncable::BaseTransaction* trans,
751     std::vector<int64>* entries_changed) {
752   // We have been notified about a user action changing a sync model.
753   LOG_IF(WARNING, !change_records_.empty()) <<
754       "CALCULATE_CHANGES called with unapplied old changes.";
755 
756   // The mutated model type, or UNSPECIFIED if nothing was mutated.
757   ModelTypeSet mutated_model_types;
758 
759   const syncable::ImmutableEntryKernelMutationMap& mutations =
760       write_transaction_info.Get().mutations;
761   for (syncable::EntryKernelMutationMap::const_iterator it =
762            mutations.Get().begin(); it != mutations.Get().end(); ++it) {
763     if (!it->second.mutated.ref(syncable::IS_UNSYNCED)) {
764       continue;
765     }
766 
767     ModelType model_type =
768         GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS));
769     if (model_type < FIRST_REAL_MODEL_TYPE) {
770       NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
771       continue;
772     }
773 
774     // Found real mutation.
775     if (model_type != UNSPECIFIED) {
776       mutated_model_types.Put(model_type);
777       entries_changed->push_back(it->second.mutated.ref(syncable::META_HANDLE));
778     }
779   }
780 
781   // Nudge if necessary.
782   if (!mutated_model_types.Empty()) {
783     if (weak_handle_this_.IsInitialized()) {
784       weak_handle_this_.Call(FROM_HERE,
785                              &SyncManagerImpl::RequestNudgeForDataTypes,
786                              FROM_HERE,
787                              mutated_model_types);
788     } else {
789       NOTREACHED();
790     }
791   }
792 }
793 
SetExtraChangeRecordData(int64 id,ModelType type,ChangeReorderBuffer * buffer,Cryptographer * cryptographer,const syncable::EntryKernel & original,bool existed_before,bool exists_now)794 void SyncManagerImpl::SetExtraChangeRecordData(int64 id,
795     ModelType type, ChangeReorderBuffer* buffer,
796     Cryptographer* cryptographer, const syncable::EntryKernel& original,
797     bool existed_before, bool exists_now) {
798   // If this is a deletion and the datatype was encrypted, we need to decrypt it
799   // and attach it to the buffer.
800   if (!exists_now && existed_before) {
801     sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
802     if (type == PASSWORDS) {
803       // Passwords must use their own legacy ExtraPasswordChangeRecordData.
804       scoped_ptr<sync_pb::PasswordSpecificsData> data(
805           DecryptPasswordSpecifics(original_specifics, cryptographer));
806       if (!data) {
807         NOTREACHED();
808         return;
809       }
810       buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
811     } else if (original_specifics.has_encrypted()) {
812       // All other datatypes can just create a new unencrypted specifics and
813       // attach it.
814       const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
815       if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
816         NOTREACHED();
817         return;
818       }
819     }
820     buffer->SetSpecificsForId(id, original_specifics);
821   }
822 }
823 
HandleCalculateChangesChangeEventFromSyncer(const ImmutableWriteTransactionInfo & write_transaction_info,syncable::BaseTransaction * trans,std::vector<int64> * entries_changed)824 void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncer(
825     const ImmutableWriteTransactionInfo& write_transaction_info,
826     syncable::BaseTransaction* trans,
827     std::vector<int64>* entries_changed) {
828   // We only expect one notification per sync step, so change_buffers_ should
829   // contain no pending entries.
830   LOG_IF(WARNING, !change_records_.empty()) <<
831       "CALCULATE_CHANGES called with unapplied old changes.";
832 
833   ChangeReorderBuffer change_buffers[MODEL_TYPE_COUNT];
834 
835   Cryptographer* crypto = directory()->GetCryptographer(trans);
836   const syncable::ImmutableEntryKernelMutationMap& mutations =
837       write_transaction_info.Get().mutations;
838   for (syncable::EntryKernelMutationMap::const_iterator it =
839            mutations.Get().begin(); it != mutations.Get().end(); ++it) {
840     bool existed_before = !it->second.original.ref(syncable::IS_DEL);
841     bool exists_now = !it->second.mutated.ref(syncable::IS_DEL);
842 
843     // Omit items that aren't associated with a model.
844     ModelType type =
845         GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS));
846     if (type < FIRST_REAL_MODEL_TYPE)
847       continue;
848 
849     int64 handle = it->first;
850     if (exists_now && !existed_before)
851       change_buffers[type].PushAddedItem(handle);
852     else if (!exists_now && existed_before)
853       change_buffers[type].PushDeletedItem(handle);
854     else if (exists_now && existed_before &&
855              VisiblePropertiesDiffer(it->second, crypto)) {
856       change_buffers[type].PushUpdatedItem(handle);
857     }
858 
859     SetExtraChangeRecordData(handle, type, &change_buffers[type], crypto,
860                              it->second.original, existed_before, exists_now);
861   }
862 
863   ReadTransaction read_trans(GetUserShare(), trans);
864   for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
865     if (!change_buffers[i].IsEmpty()) {
866       if (change_buffers[i].GetAllChangesInTreeOrder(&read_trans,
867                                                      &(change_records_[i]))) {
868         for (size_t j = 0; j < change_records_[i].Get().size(); ++j)
869           entries_changed->push_back((change_records_[i].Get())[j].id);
870       }
871       if (change_records_[i].Get().empty())
872         change_records_.erase(i);
873     }
874   }
875 }
876 
GetNudgeDelayTimeDelta(const ModelType & model_type)877 TimeDelta SyncManagerImpl::GetNudgeDelayTimeDelta(
878     const ModelType& model_type) {
879   return NudgeStrategy::GetNudgeDelayTimeDelta(model_type, this);
880 }
881 
RequestNudgeForDataTypes(const tracked_objects::Location & nudge_location,ModelTypeSet types)882 void SyncManagerImpl::RequestNudgeForDataTypes(
883     const tracked_objects::Location& nudge_location,
884     ModelTypeSet types) {
885   debug_info_event_listener_.OnNudgeFromDatatype(types.First().Get());
886 
887   // TODO(lipalani) : Calculate the nudge delay based on all types.
888   base::TimeDelta nudge_delay = NudgeStrategy::GetNudgeDelayTimeDelta(
889       types.First().Get(),
890       this);
891   scheduler_->ScheduleLocalNudge(nudge_delay,
892                                  types,
893                                  nudge_location);
894 }
895 
OnSyncCycleEvent(const SyncCycleEvent & event)896 void SyncManagerImpl::OnSyncCycleEvent(const SyncCycleEvent& event) {
897   DCHECK(thread_checker_.CalledOnValidThread());
898   // Only send an event if this is due to a cycle ending and this cycle
899   // concludes a canonical "sync" process; that is, based on what is known
900   // locally we are "all happy" and up-to-date.  There may be new changes on
901   // the server, but we'll get them on a subsequent sync.
902   //
903   // Notifications are sent at the end of every sync cycle, regardless of
904   // whether we should sync again.
905   if (event.what_happened == SyncCycleEvent::SYNC_CYCLE_ENDED) {
906     if (!initialized_) {
907       DVLOG(1) << "OnSyncCycleCompleted not sent because sync api is not "
908                << "initialized";
909       return;
910     }
911 
912     DVLOG(1) << "Sending OnSyncCycleCompleted";
913     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
914                       OnSyncCycleCompleted(event.snapshot));
915   }
916 }
917 
OnActionableError(const SyncProtocolError & error)918 void SyncManagerImpl::OnActionableError(const SyncProtocolError& error) {
919   FOR_EACH_OBSERVER(
920       SyncManager::Observer, observers_,
921       OnActionableError(error));
922 }
923 
OnRetryTimeChanged(base::Time)924 void SyncManagerImpl::OnRetryTimeChanged(base::Time) {}
925 
OnThrottledTypesChanged(ModelTypeSet)926 void SyncManagerImpl::OnThrottledTypesChanged(ModelTypeSet) {}
927 
OnMigrationRequested(ModelTypeSet types)928 void SyncManagerImpl::OnMigrationRequested(ModelTypeSet types) {
929   FOR_EACH_OBSERVER(
930       SyncManager::Observer, observers_,
931       OnMigrationRequested(types));
932 }
933 
OnProtocolEvent(const ProtocolEvent & event)934 void SyncManagerImpl::OnProtocolEvent(const ProtocolEvent& event) {
935   protocol_event_buffer_.RecordProtocolEvent(event);
936   FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
937                     OnProtocolEvent(event));
938 }
939 
SetJsEventHandler(const WeakHandle<JsEventHandler> & event_handler)940 void SyncManagerImpl::SetJsEventHandler(
941     const WeakHandle<JsEventHandler>& event_handler) {
942   js_sync_manager_observer_.SetJsEventHandler(event_handler);
943   js_mutation_event_observer_.SetJsEventHandler(event_handler);
944   js_sync_encryption_handler_observer_.SetJsEventHandler(event_handler);
945 }
946 
GetAllNodesForType(syncer::ModelType type)947 scoped_ptr<base::ListValue> SyncManagerImpl::GetAllNodesForType(
948     syncer::ModelType type) {
949   DirectoryTypeDebugInfoEmitterMap* emitter_map =
950       model_type_registry_->directory_type_debug_info_emitter_map();
951   DirectoryTypeDebugInfoEmitterMap::iterator it = emitter_map->find(type);
952 
953   if (it == emitter_map->end()) {
954     // This can happen in some cases.  The UI thread makes requests of us
955     // when it doesn't really know which types are enabled or disabled.
956     DLOG(WARNING) << "Asked to return debug info for invalid type "
957                   << ModelTypeToString(type);
958     return scoped_ptr<base::ListValue>();
959   }
960 
961   return it->second->GetAllNodes();
962 }
963 
OnInvalidatorStateChange(InvalidatorState state)964 void SyncManagerImpl::OnInvalidatorStateChange(InvalidatorState state) {
965   DCHECK(thread_checker_.CalledOnValidThread());
966 
967   const std::string& state_str = InvalidatorStateToString(state);
968   invalidator_state_ = state;
969   DVLOG(1) << "Invalidator state changed to: " << state_str;
970   const bool notifications_enabled =
971       (invalidator_state_ == INVALIDATIONS_ENABLED);
972   allstatus_.SetNotificationsEnabled(notifications_enabled);
973   scheduler_->SetNotificationsEnabled(notifications_enabled);
974 }
975 
OnIncomingInvalidation(const ObjectIdInvalidationMap & invalidation_map)976 void SyncManagerImpl::OnIncomingInvalidation(
977     const ObjectIdInvalidationMap& invalidation_map) {
978   DCHECK(thread_checker_.CalledOnValidThread());
979 
980   // We should never receive IDs from non-sync objects.
981   ObjectIdSet ids = invalidation_map.GetObjectIds();
982   for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
983     ModelType type;
984     if (!ObjectIdToRealModelType(*it, &type)) {
985       DLOG(WARNING) << "Notification has invalid id: " << ObjectIdToString(*it);
986     }
987   }
988 
989   if (invalidation_map.Empty()) {
990     LOG(WARNING) << "Sync received invalidation without any type information.";
991   } else {
992     scheduler_->ScheduleInvalidationNudge(
993         TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
994         invalidation_map, FROM_HERE);
995     debug_info_event_listener_.OnIncomingNotification(invalidation_map);
996   }
997 }
998 
GetOwnerName() const999 std::string SyncManagerImpl::GetOwnerName() const { return "SyncManagerImpl"; }
1000 
RefreshTypes(ModelTypeSet types)1001 void SyncManagerImpl::RefreshTypes(ModelTypeSet types) {
1002   DCHECK(thread_checker_.CalledOnValidThread());
1003   if (types.Empty()) {
1004     LOG(WARNING) << "Sync received refresh request with no types specified.";
1005   } else {
1006     scheduler_->ScheduleLocalRefreshRequest(
1007         TimeDelta::FromMilliseconds(kSyncRefreshDelayMsec),
1008         types, FROM_HERE);
1009   }
1010 }
1011 
GetDetailedStatus() const1012 SyncStatus SyncManagerImpl::GetDetailedStatus() const {
1013   return allstatus_.status();
1014 }
1015 
SaveChanges()1016 void SyncManagerImpl::SaveChanges() {
1017   directory()->SaveChanges();
1018 }
1019 
GetUserShare()1020 UserShare* SyncManagerImpl::GetUserShare() {
1021   DCHECK(initialized_);
1022   return &share_;
1023 }
1024 
GetSyncCoreProxy()1025 syncer::SyncCoreProxy* SyncManagerImpl::GetSyncCoreProxy() {
1026   DCHECK(initialized_);
1027   return sync_core_proxy_.get();
1028 }
1029 
cache_guid()1030 const std::string SyncManagerImpl::cache_guid() {
1031   DCHECK(initialized_);
1032   return directory()->cache_guid();
1033 }
1034 
ReceivedExperiment(Experiments * experiments)1035 bool SyncManagerImpl::ReceivedExperiment(Experiments* experiments) {
1036   ReadTransaction trans(FROM_HERE, GetUserShare());
1037   ReadNode nigori_node(&trans);
1038   if (nigori_node.InitTypeRoot(NIGORI) != BaseNode::INIT_OK) {
1039     DVLOG(1) << "Couldn't find Nigori node.";
1040     return false;
1041   }
1042   bool found_experiment = false;
1043 
1044   ReadNode favicon_sync_node(&trans);
1045   if (favicon_sync_node.InitByClientTagLookup(
1046           syncer::EXPERIMENTS,
1047           syncer::kFaviconSyncTag) == BaseNode::INIT_OK) {
1048     experiments->favicon_sync_limit =
1049         favicon_sync_node.GetExperimentsSpecifics().favicon_sync().
1050             favicon_sync_limit();
1051     found_experiment = true;
1052   }
1053 
1054   ReadNode pre_commit_update_avoidance_node(&trans);
1055   if (pre_commit_update_avoidance_node.InitByClientTagLookup(
1056           syncer::EXPERIMENTS,
1057           syncer::kPreCommitUpdateAvoidanceTag) == BaseNode::INIT_OK) {
1058     session_context_->set_server_enabled_pre_commit_update_avoidance(
1059         pre_commit_update_avoidance_node.GetExperimentsSpecifics().
1060             pre_commit_update_avoidance().enabled());
1061     // We don't bother setting found_experiment.  The frontend doesn't need to
1062     // know about this.
1063   }
1064 
1065   ReadNode gcm_channel_node(&trans);
1066   if (gcm_channel_node.InitByClientTagLookup(
1067           syncer::EXPERIMENTS,
1068           syncer::kGCMChannelTag) == BaseNode::INIT_OK &&
1069       gcm_channel_node.GetExperimentsSpecifics().gcm_channel().has_enabled()) {
1070     experiments->gcm_channel_state =
1071         (gcm_channel_node.GetExperimentsSpecifics().gcm_channel().enabled() ?
1072          syncer::Experiments::ENABLED : syncer::Experiments::SUPPRESSED);
1073     found_experiment = true;
1074   }
1075 
1076   ReadNode enhanced_bookmarks_node(&trans);
1077   if (enhanced_bookmarks_node.InitByClientTagLookup(
1078           syncer::EXPERIMENTS, syncer::kEnhancedBookmarksTag) ==
1079           BaseNode::INIT_OK &&
1080       enhanced_bookmarks_node.GetExperimentsSpecifics()
1081           .has_enhanced_bookmarks()) {
1082     const sync_pb::EnhancedBookmarksFlags& enhanced_bookmarks =
1083         enhanced_bookmarks_node.GetExperimentsSpecifics().enhanced_bookmarks();
1084     if (enhanced_bookmarks.has_enabled())
1085       experiments->enhanced_bookmarks_enabled = enhanced_bookmarks.enabled();
1086     if (enhanced_bookmarks.has_extension_id()) {
1087       experiments->enhanced_bookmarks_ext_id =
1088           enhanced_bookmarks.extension_id();
1089     }
1090     found_experiment = true;
1091   }
1092 
1093   ReadNode gcm_invalidations_node(&trans);
1094   if (gcm_invalidations_node.InitByClientTagLookup(
1095           syncer::EXPERIMENTS, syncer::kGCMInvalidationsTag) ==
1096       BaseNode::INIT_OK) {
1097     const sync_pb::GcmInvalidationsFlags& gcm_invalidations =
1098         gcm_invalidations_node.GetExperimentsSpecifics().gcm_invalidations();
1099     if (gcm_invalidations.has_enabled()) {
1100       experiments->gcm_invalidations_enabled = gcm_invalidations.enabled();
1101       found_experiment = true;
1102     }
1103   }
1104 
1105   return found_experiment;
1106 }
1107 
HasUnsyncedItems()1108 bool SyncManagerImpl::HasUnsyncedItems() {
1109   ReadTransaction trans(FROM_HERE, GetUserShare());
1110   return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
1111 }
1112 
GetEncryptionHandler()1113 SyncEncryptionHandler* SyncManagerImpl::GetEncryptionHandler() {
1114   return sync_encryption_handler_.get();
1115 }
1116 
1117 ScopedVector<syncer::ProtocolEvent>
GetBufferedProtocolEvents()1118     SyncManagerImpl::GetBufferedProtocolEvents() {
1119   return protocol_event_buffer_.GetBufferedProtocolEvents();
1120 }
1121 
RegisterDirectoryTypeDebugInfoObserver(syncer::TypeDebugInfoObserver * observer)1122 void SyncManagerImpl::RegisterDirectoryTypeDebugInfoObserver(
1123     syncer::TypeDebugInfoObserver* observer) {
1124   model_type_registry_->RegisterDirectoryTypeDebugInfoObserver(observer);
1125 }
1126 
UnregisterDirectoryTypeDebugInfoObserver(syncer::TypeDebugInfoObserver * observer)1127 void SyncManagerImpl::UnregisterDirectoryTypeDebugInfoObserver(
1128     syncer::TypeDebugInfoObserver* observer) {
1129   model_type_registry_->UnregisterDirectoryTypeDebugInfoObserver(observer);
1130 }
1131 
HasDirectoryTypeDebugInfoObserver(syncer::TypeDebugInfoObserver * observer)1132 bool SyncManagerImpl::HasDirectoryTypeDebugInfoObserver(
1133     syncer::TypeDebugInfoObserver* observer) {
1134   return model_type_registry_->HasDirectoryTypeDebugInfoObserver(observer);
1135 }
1136 
RequestEmitDebugInfo()1137 void SyncManagerImpl::RequestEmitDebugInfo() {
1138   model_type_registry_->RequestEmitDebugInfo();
1139 }
1140 
1141 // static.
GetDefaultNudgeDelay()1142 int SyncManagerImpl::GetDefaultNudgeDelay() {
1143   return kDefaultNudgeDelayMilliseconds;
1144 }
1145 
1146 // static.
GetPreferencesNudgeDelay()1147 int SyncManagerImpl::GetPreferencesNudgeDelay() {
1148   return kPreferencesNudgeDelayMilliseconds;
1149 }
1150 
1151 }  // namespace syncer
1152