Disable flaky test ExtensionActionContextMenuTest.RunInspectPopup
[chromium-blink-merge.git] / sync / internal_api / sync_manager_impl.cc
blob352a57ead56342d41b9743c9680f26a41bb960b1
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.
5 #include "sync/internal_api/sync_manager_impl.h"
7 #include <string>
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/json/json_writer.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/metrics/histogram.h"
17 #include "base/observer_list.h"
18 #include "base/string_number_conversions.h"
19 #include "base/values.h"
20 #include "sync/engine/sync_scheduler.h"
21 #include "sync/engine/syncer_types.h"
22 #include "sync/internal_api/change_reorder_buffer.h"
23 #include "sync/internal_api/public/base/model_type.h"
24 #include "sync/internal_api/public/base/model_type_invalidation_map.h"
25 #include "sync/internal_api/public/base_node.h"
26 #include "sync/internal_api/public/configure_reason.h"
27 #include "sync/internal_api/public/engine/polling_constants.h"
28 #include "sync/internal_api/public/http_post_provider_factory.h"
29 #include "sync/internal_api/public/internal_components_factory.h"
30 #include "sync/internal_api/public/read_node.h"
31 #include "sync/internal_api/public/read_transaction.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/syncapi_internal.h"
37 #include "sync/internal_api/syncapi_server_connection_manager.h"
38 #include "sync/js/js_arg_list.h"
39 #include "sync/js/js_event_details.h"
40 #include "sync/js/js_event_handler.h"
41 #include "sync/js/js_reply_handler.h"
42 #include "sync/notifier/invalidation_util.h"
43 #include "sync/notifier/invalidator.h"
44 #include "sync/protocol/proto_value_conversions.h"
45 #include "sync/protocol/sync.pb.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"
51 using base::TimeDelta;
52 using sync_pb::GetUpdatesCallerInfo;
54 namespace syncer {
56 using sessions::SyncSessionContext;
57 using syncable::ImmutableWriteTransactionInfo;
58 using syncable::SPECIFICS;
60 namespace {
62 // Delays for syncer nudges.
63 static const int kDefaultNudgeDelayMilliseconds = 200;
64 static const int kPreferencesNudgeDelayMilliseconds = 2000;
65 static const int kSyncRefreshDelayMsec = 500;
66 static const int kSyncSchedulerDelayMsec = 250;
68 // Maximum count and size for traffic recorder.
69 static const unsigned int kMaxMessagesToRecord = 10;
70 static const unsigned int kMaxMessageSizeToRecord = 5 * 1024;
72 GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason(
73 ConfigureReason reason) {
74 switch (reason) {
75 case CONFIGURE_REASON_RECONFIGURATION:
76 return GetUpdatesCallerInfo::RECONFIGURATION;
77 case CONFIGURE_REASON_MIGRATION:
78 return GetUpdatesCallerInfo::MIGRATION;
79 case CONFIGURE_REASON_NEW_CLIENT:
80 return GetUpdatesCallerInfo::NEW_CLIENT;
81 case CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE:
82 return GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE;
83 default:
84 NOTREACHED();
86 return GetUpdatesCallerInfo::UNKNOWN;
89 } // namespace
91 // A class to calculate nudge delays for types.
92 class NudgeStrategy {
93 public:
94 static TimeDelta GetNudgeDelayTimeDelta(const ModelType& model_type,
95 SyncManagerImpl* core) {
96 NudgeDelayStrategy delay_type = GetNudgeDelayStrategy(model_type);
97 return GetNudgeDelayTimeDeltaFromType(delay_type,
98 model_type,
99 core);
102 private:
103 // Possible types of nudge delay for datatypes.
104 // Note: These are just hints. If a sync happens then all dirty entries
105 // would be committed as part of the sync.
106 enum NudgeDelayStrategy {
107 // Sync right away.
108 IMMEDIATE,
110 // Sync this change while syncing another change.
111 ACCOMPANY_ONLY,
113 // The datatype does not use one of the predefined wait times but defines
114 // its own wait time logic for nudge.
115 CUSTOM,
118 static NudgeDelayStrategy GetNudgeDelayStrategy(const ModelType& type) {
119 switch (type) {
120 case AUTOFILL:
121 return ACCOMPANY_ONLY;
122 case PREFERENCES:
123 case SESSIONS:
124 return CUSTOM;
125 default:
126 return IMMEDIATE;
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 delay = core->scheduler()->GetSessionsCommitDelay();
152 break;
153 default:
154 NOTREACHED();
156 break;
157 default:
158 NOTREACHED();
160 return delay;
164 SyncManagerImpl::SyncManagerImpl(const std::string& name)
165 : name_(name),
166 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
167 change_delegate_(NULL),
168 initialized_(false),
169 observing_network_connectivity_changes_(false),
170 invalidator_state_(DEFAULT_INVALIDATION_ERROR),
171 throttled_data_type_tracker_(&allstatus_),
172 traffic_recorder_(kMaxMessagesToRecord, kMaxMessageSizeToRecord),
173 encryptor_(NULL),
174 unrecoverable_error_handler_(NULL),
175 report_unrecoverable_error_function_(NULL) {
176 // Pre-fill |notification_info_map_|.
177 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
178 notification_info_map_.insert(
179 std::make_pair(ModelTypeFromInt(i), NotificationInfo()));
182 // Bind message handlers.
183 BindJsMessageHandler(
184 "getNotificationState",
185 &SyncManagerImpl::GetNotificationState);
186 BindJsMessageHandler(
187 "getNotificationInfo",
188 &SyncManagerImpl::GetNotificationInfo);
189 BindJsMessageHandler(
190 "getRootNodeDetails",
191 &SyncManagerImpl::GetRootNodeDetails);
192 BindJsMessageHandler(
193 "getNodeSummariesById",
194 &SyncManagerImpl::GetNodeSummariesById);
195 BindJsMessageHandler(
196 "getNodeDetailsById",
197 &SyncManagerImpl::GetNodeDetailsById);
198 BindJsMessageHandler(
199 "getAllNodes",
200 &SyncManagerImpl::GetAllNodes);
201 BindJsMessageHandler(
202 "getChildNodeIds",
203 &SyncManagerImpl::GetChildNodeIds);
204 BindJsMessageHandler(
205 "getClientServerTraffic",
206 &SyncManagerImpl::GetClientServerTraffic);
209 SyncManagerImpl::~SyncManagerImpl() {
210 DCHECK(thread_checker_.CalledOnValidThread());
211 CHECK(!initialized_);
214 SyncManagerImpl::NotificationInfo::NotificationInfo() : total_count(0) {}
215 SyncManagerImpl::NotificationInfo::~NotificationInfo() {}
217 base::DictionaryValue* SyncManagerImpl::NotificationInfo::ToValue() const {
218 base::DictionaryValue* value = new base::DictionaryValue();
219 value->SetInteger("totalCount", total_count);
220 value->SetString("payload", payload);
221 return value;
224 bool SyncManagerImpl::VisiblePositionsDiffer(
225 const syncable::EntryKernelMutation& mutation) const {
226 const syncable::EntryKernel& a = mutation.original;
227 const syncable::EntryKernel& b = mutation.mutated;
228 // If the datatype isn't one where the browser model cares about position,
229 // don't bother notifying that data model of position-only changes.
230 if (!ShouldMaintainPosition(GetModelTypeFromSpecifics(b.ref(SPECIFICS)))) {
231 return false;
233 if (a.ref(syncable::NEXT_ID) != b.ref(syncable::NEXT_ID))
234 return true;
235 if (a.ref(syncable::PARENT_ID) != b.ref(syncable::PARENT_ID))
236 return true;
237 return false;
240 bool SyncManagerImpl::VisiblePropertiesDiffer(
241 const syncable::EntryKernelMutation& mutation,
242 Cryptographer* cryptographer) const {
243 const syncable::EntryKernel& a = mutation.original;
244 const syncable::EntryKernel& b = mutation.mutated;
245 const sync_pb::EntitySpecifics& a_specifics = a.ref(SPECIFICS);
246 const sync_pb::EntitySpecifics& b_specifics = b.ref(SPECIFICS);
247 DCHECK_EQ(GetModelTypeFromSpecifics(a_specifics),
248 GetModelTypeFromSpecifics(b_specifics));
249 ModelType model_type = GetModelTypeFromSpecifics(b_specifics);
250 // Suppress updates to items that aren't tracked by any browser model.
251 if (model_type < FIRST_REAL_MODEL_TYPE ||
252 !a.ref(syncable::UNIQUE_SERVER_TAG).empty()) {
253 return false;
255 if (a.ref(syncable::IS_DIR) != b.ref(syncable::IS_DIR))
256 return true;
257 if (!AreSpecificsEqual(cryptographer,
258 a.ref(syncable::SPECIFICS),
259 b.ref(syncable::SPECIFICS))) {
260 return true;
262 // We only care if the name has changed if neither specifics is encrypted
263 // (encrypted nodes blow away the NON_UNIQUE_NAME).
264 if (!a_specifics.has_encrypted() && !b_specifics.has_encrypted() &&
265 a.ref(syncable::NON_UNIQUE_NAME) != b.ref(syncable::NON_UNIQUE_NAME))
266 return true;
267 if (VisiblePositionsDiffer(mutation))
268 return true;
269 return false;
272 void SyncManagerImpl::ThrowUnrecoverableError() {
273 DCHECK(thread_checker_.CalledOnValidThread());
274 ReadTransaction trans(FROM_HERE, GetUserShare());
275 trans.GetWrappedTrans()->OnUnrecoverableError(
276 FROM_HERE, "Simulating unrecoverable error for testing purposes.");
279 ModelTypeSet SyncManagerImpl::InitialSyncEndedTypes() {
280 return directory()->InitialSyncEndedTypes();
283 ModelTypeSet SyncManagerImpl::GetTypesWithEmptyProgressMarkerToken(
284 ModelTypeSet types) {
285 ModelTypeSet result;
286 for (ModelTypeSet::Iterator i = types.First(); i.Good(); i.Inc()) {
287 sync_pb::DataTypeProgressMarker marker;
288 directory()->GetDownloadProgress(i.Get(), &marker);
290 if (marker.token().empty())
291 result.Put(i.Get());
293 return result;
296 void SyncManagerImpl::ConfigureSyncer(
297 ConfigureReason reason,
298 ModelTypeSet types_to_config,
299 ModelTypeSet failed_types,
300 const ModelSafeRoutingInfo& new_routing_info,
301 const base::Closure& ready_task,
302 const base::Closure& retry_task) {
303 DCHECK(thread_checker_.CalledOnValidThread());
304 DCHECK(!ready_task.is_null());
305 DCHECK(!retry_task.is_null());
307 // Cleanup any types that might have just been disabled.
308 ModelTypeSet previous_types = ModelTypeSet::All();
309 if (!session_context_->routing_info().empty())
310 previous_types = GetRoutingInfoTypes(session_context_->routing_info());
311 if (!PurgeDisabledTypes(previous_types,
312 GetRoutingInfoTypes(new_routing_info),
313 failed_types)) {
314 // We failed to cleanup the types. Invoke the ready task without actually
315 // configuring any types. The caller should detect this as a configuration
316 // failure and act appropriately.
317 ready_task.Run();
318 return;
321 ConfigurationParams params(GetSourceFromReason(reason),
322 types_to_config,
323 new_routing_info,
324 ready_task);
326 scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
327 if (!scheduler_->ScheduleConfiguration(params))
328 retry_task.Run();
331 void SyncManagerImpl::Init(
332 const base::FilePath& database_location,
333 const WeakHandle<JsEventHandler>& event_handler,
334 const std::string& sync_server_and_path,
335 int port,
336 bool use_ssl,
337 scoped_ptr<HttpPostProviderFactory> post_factory,
338 const std::vector<ModelSafeWorker*>& workers,
339 ExtensionsActivityMonitor* extensions_activity_monitor,
340 SyncManager::ChangeDelegate* change_delegate,
341 const SyncCredentials& credentials,
342 scoped_ptr<Invalidator> invalidator,
343 const std::string& restored_key_for_bootstrapping,
344 const std::string& restored_keystore_key_for_bootstrapping,
345 scoped_ptr<InternalComponentsFactory> internal_components_factory,
346 Encryptor* encryptor,
347 UnrecoverableErrorHandler* unrecoverable_error_handler,
348 ReportUnrecoverableErrorFunction report_unrecoverable_error_function) {
349 CHECK(!initialized_);
350 DCHECK(thread_checker_.CalledOnValidThread());
351 DCHECK(post_factory.get());
352 DCHECK(!credentials.email.empty());
353 DCHECK(!credentials.sync_token.empty());
354 DVLOG(1) << "SyncManager starting Init...";
356 weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
358 change_delegate_ = change_delegate;
360 invalidator_ = invalidator.Pass();
361 invalidator_->RegisterHandler(this);
363 AddObserver(&js_sync_manager_observer_);
364 SetJsEventHandler(event_handler);
366 AddObserver(&debug_info_event_listener_);
368 database_path_ = database_location.Append(
369 syncable::Directory::kSyncDatabaseFilename);
370 encryptor_ = encryptor;
371 unrecoverable_error_handler_ = unrecoverable_error_handler;
372 report_unrecoverable_error_function_ = report_unrecoverable_error_function;
374 allstatus_.SetHasKeystoreKey(
375 !restored_keystore_key_for_bootstrapping.empty());
376 sync_encryption_handler_.reset(new SyncEncryptionHandlerImpl(
377 &share_,
378 encryptor,
379 restored_key_for_bootstrapping,
380 restored_keystore_key_for_bootstrapping));
381 sync_encryption_handler_->AddObserver(this);
382 sync_encryption_handler_->AddObserver(&debug_info_event_listener_);
383 sync_encryption_handler_->AddObserver(&js_sync_encryption_handler_observer_);
385 base::FilePath absolute_db_path(database_path_);
386 file_util::AbsolutePath(&absolute_db_path);
387 scoped_ptr<syncable::DirectoryBackingStore> backing_store =
388 internal_components_factory->BuildDirectoryBackingStore(
389 credentials.email, absolute_db_path).Pass();
391 DCHECK(backing_store.get());
392 const std::string& username = credentials.email;
393 share_.directory.reset(
394 new syncable::Directory(
395 backing_store.release(),
396 unrecoverable_error_handler_,
397 report_unrecoverable_error_function_,
398 sync_encryption_handler_.get(),
399 sync_encryption_handler_->GetCryptographerUnsafe()));
401 DVLOG(1) << "Username: " << username;
402 if (!OpenDirectory(username)) {
403 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
404 OnInitializationComplete(
405 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
406 MakeWeakHandle(
407 debug_info_event_listener_.GetWeakPtr()),
408 false, ModelTypeSet()));
409 LOG(ERROR) << "Sync manager initialization failed!";
410 return;
413 connection_manager_.reset(new SyncAPIServerConnectionManager(
414 sync_server_and_path, port, use_ssl, post_factory.release()));
415 connection_manager_->set_client_id(directory()->cache_guid());
416 connection_manager_->AddListener(this);
418 std::string sync_id = directory()->cache_guid();
420 // TODO(rlarocque): The invalidator client ID should be independent from the
421 // sync client ID. See crbug.com/124142.
422 const std::string invalidator_client_id = sync_id;
424 allstatus_.SetSyncId(sync_id);
425 allstatus_.SetInvalidatorClientId(invalidator_client_id);
427 DVLOG(1) << "Setting sync client ID: " << sync_id;
428 DVLOG(1) << "Setting invalidator client ID: " << invalidator_client_id;
429 invalidator_->SetUniqueId(invalidator_client_id);
431 // Build a SyncSessionContext and store the worker in it.
432 DVLOG(1) << "Sync is bringing up SyncSessionContext.";
433 std::vector<SyncEngineEventListener*> listeners;
434 listeners.push_back(&allstatus_);
435 listeners.push_back(this);
436 session_context_ = internal_components_factory->BuildContext(
437 connection_manager_.get(),
438 directory(),
439 workers,
440 extensions_activity_monitor,
441 &throttled_data_type_tracker_,
442 listeners,
443 &debug_info_event_listener_,
444 &traffic_recorder_,
445 invalidator_client_id).Pass();
446 session_context_->set_account_name(credentials.email);
447 scheduler_ = internal_components_factory->BuildScheduler(
448 name_, session_context_.get()).Pass();
450 scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
452 initialized_ = true;
454 net::NetworkChangeNotifier::AddIPAddressObserver(this);
455 net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
456 observing_network_connectivity_changes_ = true;
458 UpdateCredentials(credentials);
460 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
461 OnInitializationComplete(
462 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
463 MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()),
464 true, InitialSyncEndedTypes()));
467 void SyncManagerImpl::OnPassphraseRequired(
468 PassphraseRequiredReason reason,
469 const sync_pb::EncryptedData& pending_keys) {
470 // Does nothing.
473 void SyncManagerImpl::OnPassphraseAccepted() {
474 // Does nothing.
477 void SyncManagerImpl::OnBootstrapTokenUpdated(
478 const std::string& bootstrap_token,
479 BootstrapTokenType type) {
480 if (type == KEYSTORE_BOOTSTRAP_TOKEN)
481 allstatus_.SetHasKeystoreKey(true);
484 void SyncManagerImpl::OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
485 bool encrypt_everything) {
486 allstatus_.SetEncryptedTypes(encrypted_types);
489 void SyncManagerImpl::OnEncryptionComplete() {
490 // Does nothing.
493 void SyncManagerImpl::OnCryptographerStateChanged(
494 Cryptographer* cryptographer) {
495 allstatus_.SetCryptographerReady(cryptographer->is_ready());
496 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
497 allstatus_.SetKeystoreMigrationTime(
498 sync_encryption_handler_->migration_time());
501 void SyncManagerImpl::OnPassphraseTypeChanged(
502 PassphraseType type,
503 base::Time explicit_passphrase_time) {
504 allstatus_.SetPassphraseType(type);
505 allstatus_.SetKeystoreMigrationTime(
506 sync_encryption_handler_->migration_time());
509 void SyncManagerImpl::StartSyncingNormally(
510 const ModelSafeRoutingInfo& routing_info) {
511 // Start the sync scheduler.
512 // TODO(sync): We always want the newest set of routes when we switch back
513 // to normal mode. Figure out how to enforce set_routing_info is always
514 // appropriately set and that it's only modified when switching to normal
515 // mode.
516 DCHECK(thread_checker_.CalledOnValidThread());
517 session_context_->set_routing_info(routing_info);
518 scheduler_->Start(SyncScheduler::NORMAL_MODE);
521 syncable::Directory* SyncManagerImpl::directory() {
522 return share_.directory.get();
525 const SyncScheduler* SyncManagerImpl::scheduler() const {
526 return scheduler_.get();
529 bool SyncManagerImpl::GetHasInvalidAuthTokenForTest() const {
530 return connection_manager_->HasInvalidAuthToken();
533 bool SyncManagerImpl::OpenDirectory(const std::string& username) {
534 DCHECK(!initialized_) << "Should only happen once";
536 // Set before Open().
537 change_observer_ = MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr());
538 WeakHandle<syncable::TransactionObserver> transaction_observer(
539 MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr()));
541 syncable::DirOpenResult open_result = syncable::NOT_INITIALIZED;
542 open_result = directory()->Open(username, this, transaction_observer);
543 if (open_result != syncable::OPENED) {
544 LOG(ERROR) << "Could not open share for:" << username;
545 return false;
548 // Unapplied datatypes (those that do not have initial sync ended set) get
549 // re-downloaded during any configuration. But, it's possible for a datatype
550 // to have a progress marker but not have initial sync ended yet, making
551 // it a candidate for migration. This is a problem, as the DataTypeManager
552 // does not support a migration while it's already in the middle of a
553 // configuration. As a result, any partially synced datatype can stall the
554 // DTM, waiting for the configuration to complete, which it never will due
555 // to the migration error. In addition, a partially synced nigori will
556 // trigger the migration logic before the backend is initialized, resulting
557 // in crashes. We therefore detect and purge any partially synced types as
558 // part of initialization.
559 if (!PurgePartiallySyncedTypes())
560 return false;
562 return true;
565 bool SyncManagerImpl::PurgePartiallySyncedTypes() {
566 ModelTypeSet partially_synced_types = ModelTypeSet::All();
567 partially_synced_types.RemoveAll(InitialSyncEndedTypes());
568 partially_synced_types.RemoveAll(GetTypesWithEmptyProgressMarkerToken(
569 ModelTypeSet::All()));
571 DVLOG(1) << "Purging partially synced types "
572 << ModelTypeSetToString(partially_synced_types);
573 UMA_HISTOGRAM_COUNTS("Sync.PartiallySyncedTypes",
574 partially_synced_types.Size());
575 if (partially_synced_types.Empty())
576 return true;
577 return directory()->PurgeEntriesWithTypeIn(partially_synced_types,
578 ModelTypeSet());
581 bool SyncManagerImpl::PurgeDisabledTypes(
582 ModelTypeSet previously_enabled_types,
583 ModelTypeSet currently_enabled_types,
584 ModelTypeSet failed_types) {
585 ModelTypeSet disabled_types = Difference(previously_enabled_types,
586 currently_enabled_types);
587 if (disabled_types.Empty())
588 return true;
590 DVLOG(1) << "Purging disabled types "
591 << ModelTypeSetToString(disabled_types);
592 return directory()->PurgeEntriesWithTypeIn(disabled_types, failed_types);
595 void SyncManagerImpl::UpdateCredentials(const SyncCredentials& credentials) {
596 DCHECK(thread_checker_.CalledOnValidThread());
597 DCHECK(initialized_);
598 DCHECK(!credentials.email.empty());
599 DCHECK(!credentials.sync_token.empty());
601 observing_network_connectivity_changes_ = true;
602 if (!connection_manager_->set_auth_token(credentials.sync_token))
603 return; // Auth token is known to be invalid, so exit early.
605 invalidator_->UpdateCredentials(credentials.email, credentials.sync_token);
606 scheduler_->OnCredentialsUpdated();
609 void SyncManagerImpl::UpdateEnabledTypes(ModelTypeSet enabled_types) {
610 DCHECK(thread_checker_.CalledOnValidThread());
611 DCHECK(initialized_);
612 invalidator_->UpdateRegisteredIds(
613 this,
614 ModelTypeSetToObjectIdSet(enabled_types));
617 void SyncManagerImpl::RegisterInvalidationHandler(
618 InvalidationHandler* handler) {
619 DCHECK(thread_checker_.CalledOnValidThread());
620 DCHECK(initialized_);
621 invalidator_->RegisterHandler(handler);
624 void SyncManagerImpl::UpdateRegisteredInvalidationIds(
625 InvalidationHandler* handler,
626 const ObjectIdSet& ids) {
627 DCHECK(thread_checker_.CalledOnValidThread());
628 DCHECK(initialized_);
629 invalidator_->UpdateRegisteredIds(handler, ids);
632 void SyncManagerImpl::UnregisterInvalidationHandler(
633 InvalidationHandler* handler) {
634 DCHECK(thread_checker_.CalledOnValidThread());
635 DCHECK(initialized_);
636 invalidator_->UnregisterHandler(handler);
639 void SyncManagerImpl::AcknowledgeInvalidation(
640 const invalidation::ObjectId& id, const syncer::AckHandle& ack_handle) {
641 DCHECK(thread_checker_.CalledOnValidThread());
642 DCHECK(initialized_);
643 invalidator_->Acknowledge(id, ack_handle);
646 void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) {
647 DCHECK(thread_checker_.CalledOnValidThread());
648 observers_.AddObserver(observer);
651 void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) {
652 DCHECK(thread_checker_.CalledOnValidThread());
653 observers_.RemoveObserver(observer);
656 void SyncManagerImpl::StopSyncingForShutdown(const base::Closure& callback) {
657 DVLOG(2) << "StopSyncingForShutdown";
658 scheduler_->RequestStop(callback);
659 if (connection_manager_.get())
660 connection_manager_->TerminateAllIO();
663 void SyncManagerImpl::ShutdownOnSyncThread() {
664 DCHECK(thread_checker_.CalledOnValidThread());
666 // Prevent any in-flight method calls from running. Also
667 // invalidates |weak_handle_this_| and |change_observer_|.
668 weak_ptr_factory_.InvalidateWeakPtrs();
669 js_mutation_event_observer_.InvalidateWeakPtrs();
671 scheduler_.reset();
672 session_context_.reset();
674 if (sync_encryption_handler_.get()) {
675 sync_encryption_handler_->RemoveObserver(&debug_info_event_listener_);
676 sync_encryption_handler_->RemoveObserver(this);
679 SetJsEventHandler(WeakHandle<JsEventHandler>());
680 RemoveObserver(&js_sync_manager_observer_);
682 RemoveObserver(&debug_info_event_listener_);
684 // |invalidator_| and |connection_manager_| may end up being NULL here in
685 // tests (in synchronous initialization mode).
687 // TODO(akalin): Fix this behavior.
689 if (invalidator_.get())
690 invalidator_->UnregisterHandler(this);
691 invalidator_.reset();
693 if (connection_manager_.get())
694 connection_manager_->RemoveListener(this);
695 connection_manager_.reset();
697 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
698 net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
699 observing_network_connectivity_changes_ = false;
701 if (initialized_ && directory()) {
702 directory()->SaveChanges();
705 share_.directory.reset();
707 change_delegate_ = NULL;
709 initialized_ = false;
711 // We reset these here, since only now we know they will not be
712 // accessed from other threads (since we shut down everything).
713 change_observer_.Reset();
714 weak_handle_this_.Reset();
717 void SyncManagerImpl::OnIPAddressChanged() {
718 if (!observing_network_connectivity_changes_) {
719 DVLOG(1) << "IP address change dropped.";
720 return;
722 DVLOG(1) << "IP address change detected.";
723 OnNetworkConnectivityChangedImpl();
726 void SyncManagerImpl::OnConnectionTypeChanged(
727 net::NetworkChangeNotifier::ConnectionType) {
728 if (!observing_network_connectivity_changes_) {
729 DVLOG(1) << "Connection type change dropped.";
730 return;
732 DVLOG(1) << "Connection type change detected.";
733 OnNetworkConnectivityChangedImpl();
736 void SyncManagerImpl::OnNetworkConnectivityChangedImpl() {
737 DCHECK(thread_checker_.CalledOnValidThread());
738 scheduler_->OnConnectionStatusChange();
741 void SyncManagerImpl::OnServerConnectionEvent(
742 const ServerConnectionEvent& event) {
743 DCHECK(thread_checker_.CalledOnValidThread());
744 if (event.connection_code ==
745 HttpResponse::SERVER_CONNECTION_OK) {
746 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
747 OnConnectionStatusChange(CONNECTION_OK));
750 if (event.connection_code == HttpResponse::SYNC_AUTH_ERROR) {
751 observing_network_connectivity_changes_ = false;
752 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
753 OnConnectionStatusChange(CONNECTION_AUTH_ERROR));
756 if (event.connection_code == HttpResponse::SYNC_SERVER_ERROR) {
757 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
758 OnConnectionStatusChange(CONNECTION_SERVER_ERROR));
762 void SyncManagerImpl::HandleTransactionCompleteChangeEvent(
763 ModelTypeSet models_with_changes) {
764 // This notification happens immediately after the transaction mutex is
765 // released. This allows work to be performed without blocking other threads
766 // from acquiring a transaction.
767 if (!change_delegate_)
768 return;
770 // Call commit.
771 for (ModelTypeSet::Iterator it = models_with_changes.First();
772 it.Good(); it.Inc()) {
773 change_delegate_->OnChangesComplete(it.Get());
774 change_observer_.Call(
775 FROM_HERE,
776 &SyncManager::ChangeObserver::OnChangesComplete,
777 it.Get());
781 ModelTypeSet
782 SyncManagerImpl::HandleTransactionEndingChangeEvent(
783 const ImmutableWriteTransactionInfo& write_transaction_info,
784 syncable::BaseTransaction* trans) {
785 // This notification happens immediately before a syncable WriteTransaction
786 // falls out of scope. It happens while the channel mutex is still held,
787 // and while the transaction mutex is held, so it cannot be re-entrant.
788 if (!change_delegate_ || change_records_.empty())
789 return ModelTypeSet();
791 // This will continue the WriteTransaction using a read only wrapper.
792 // This is the last chance for read to occur in the WriteTransaction
793 // that's closing. This special ReadTransaction will not close the
794 // underlying transaction.
795 ReadTransaction read_trans(GetUserShare(), trans);
797 ModelTypeSet models_with_changes;
798 for (ChangeRecordMap::const_iterator it = change_records_.begin();
799 it != change_records_.end(); ++it) {
800 DCHECK(!it->second.Get().empty());
801 ModelType type = ModelTypeFromInt(it->first);
802 change_delegate_->
803 OnChangesApplied(type, trans->directory()->GetTransactionVersion(type),
804 &read_trans, it->second);
805 change_observer_.Call(FROM_HERE,
806 &SyncManager::ChangeObserver::OnChangesApplied,
807 type, write_transaction_info.Get().id, it->second);
808 models_with_changes.Put(type);
810 change_records_.clear();
811 return models_with_changes;
814 void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncApi(
815 const ImmutableWriteTransactionInfo& write_transaction_info,
816 syncable::BaseTransaction* trans,
817 std::vector<int64>* entries_changed) {
818 // We have been notified about a user action changing a sync model.
819 LOG_IF(WARNING, !change_records_.empty()) <<
820 "CALCULATE_CHANGES called with unapplied old changes.";
822 // The mutated model type, or UNSPECIFIED if nothing was mutated.
823 ModelTypeSet mutated_model_types;
825 const syncable::ImmutableEntryKernelMutationMap& mutations =
826 write_transaction_info.Get().mutations;
827 for (syncable::EntryKernelMutationMap::const_iterator it =
828 mutations.Get().begin(); it != mutations.Get().end(); ++it) {
829 if (!it->second.mutated.ref(syncable::IS_UNSYNCED)) {
830 continue;
833 ModelType model_type =
834 GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS));
835 if (model_type < FIRST_REAL_MODEL_TYPE) {
836 NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
837 continue;
840 // Found real mutation.
841 if (model_type != UNSPECIFIED) {
842 mutated_model_types.Put(model_type);
843 entries_changed->push_back(it->second.mutated.ref(syncable::META_HANDLE));
847 // Nudge if necessary.
848 if (!mutated_model_types.Empty()) {
849 if (weak_handle_this_.IsInitialized()) {
850 weak_handle_this_.Call(FROM_HERE,
851 &SyncManagerImpl::RequestNudgeForDataTypes,
852 FROM_HERE,
853 mutated_model_types);
854 } else {
855 NOTREACHED();
860 void SyncManagerImpl::SetExtraChangeRecordData(int64 id,
861 ModelType type, ChangeReorderBuffer* buffer,
862 Cryptographer* cryptographer, const syncable::EntryKernel& original,
863 bool existed_before, bool exists_now) {
864 // If this is a deletion and the datatype was encrypted, we need to decrypt it
865 // and attach it to the buffer.
866 if (!exists_now && existed_before) {
867 sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
868 if (type == PASSWORDS) {
869 // Passwords must use their own legacy ExtraPasswordChangeRecordData.
870 scoped_ptr<sync_pb::PasswordSpecificsData> data(
871 DecryptPasswordSpecifics(original_specifics, cryptographer));
872 if (!data.get()) {
873 NOTREACHED();
874 return;
876 buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
877 } else if (original_specifics.has_encrypted()) {
878 // All other datatypes can just create a new unencrypted specifics and
879 // attach it.
880 const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
881 if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
882 NOTREACHED();
883 return;
886 buffer->SetSpecificsForId(id, original_specifics);
890 void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncer(
891 const ImmutableWriteTransactionInfo& write_transaction_info,
892 syncable::BaseTransaction* trans,
893 std::vector<int64>* entries_changed) {
894 // We only expect one notification per sync step, so change_buffers_ should
895 // contain no pending entries.
896 LOG_IF(WARNING, !change_records_.empty()) <<
897 "CALCULATE_CHANGES called with unapplied old changes.";
899 ChangeReorderBuffer change_buffers[MODEL_TYPE_COUNT];
901 Cryptographer* crypto = directory()->GetCryptographer(trans);
902 const syncable::ImmutableEntryKernelMutationMap& mutations =
903 write_transaction_info.Get().mutations;
904 for (syncable::EntryKernelMutationMap::const_iterator it =
905 mutations.Get().begin(); it != mutations.Get().end(); ++it) {
906 bool existed_before = !it->second.original.ref(syncable::IS_DEL);
907 bool exists_now = !it->second.mutated.ref(syncable::IS_DEL);
909 // Omit items that aren't associated with a model.
910 ModelType type =
911 GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS));
912 if (type < FIRST_REAL_MODEL_TYPE)
913 continue;
915 int64 handle = it->first;
916 if (exists_now && !existed_before)
917 change_buffers[type].PushAddedItem(handle);
918 else if (!exists_now && existed_before)
919 change_buffers[type].PushDeletedItem(handle);
920 else if (exists_now && existed_before &&
921 VisiblePropertiesDiffer(it->second, crypto)) {
922 change_buffers[type].PushUpdatedItem(
923 handle, VisiblePositionsDiffer(it->second));
926 SetExtraChangeRecordData(handle, type, &change_buffers[type], crypto,
927 it->second.original, existed_before, exists_now);
930 ReadTransaction read_trans(GetUserShare(), trans);
931 for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
932 if (!change_buffers[i].IsEmpty()) {
933 if (change_buffers[i].GetAllChangesInTreeOrder(&read_trans,
934 &(change_records_[i]))) {
935 for (size_t j = 0; j < change_records_[i].Get().size(); ++j)
936 entries_changed->push_back((change_records_[i].Get())[j].id);
938 if (change_records_[i].Get().empty())
939 change_records_.erase(i);
944 TimeDelta SyncManagerImpl::GetNudgeDelayTimeDelta(
945 const ModelType& model_type) {
946 return NudgeStrategy::GetNudgeDelayTimeDelta(model_type, this);
949 void SyncManagerImpl::RequestNudgeForDataTypes(
950 const tracked_objects::Location& nudge_location,
951 ModelTypeSet types) {
952 debug_info_event_listener_.OnNudgeFromDatatype(types.First().Get());
954 // TODO(lipalani) : Calculate the nudge delay based on all types.
955 base::TimeDelta nudge_delay = NudgeStrategy::GetNudgeDelayTimeDelta(
956 types.First().Get(),
957 this);
958 allstatus_.IncrementNudgeCounter(NUDGE_SOURCE_LOCAL);
959 scheduler_->ScheduleNudgeAsync(nudge_delay,
960 NUDGE_SOURCE_LOCAL,
961 types,
962 nudge_location);
965 void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) {
966 DCHECK(thread_checker_.CalledOnValidThread());
967 // Only send an event if this is due to a cycle ending and this cycle
968 // concludes a canonical "sync" process; that is, based on what is known
969 // locally we are "all happy" and up-to-date. There may be new changes on
970 // the server, but we'll get them on a subsequent sync.
972 // Notifications are sent at the end of every sync cycle, regardless of
973 // whether we should sync again.
974 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
975 if (!initialized_) {
976 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
977 << "initialized";
978 return;
981 DVLOG(1) << "Sending OnSyncCycleCompleted";
982 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
983 OnSyncCycleCompleted(event.snapshot));
985 // This is here for tests, which are still using p2p notifications.
986 bool is_notifiable_commit =
987 (event.snapshot.model_neutral_state().num_successful_commits > 0);
988 if (is_notifiable_commit) {
989 if (invalidator_.get()) {
990 const ObjectIdInvalidationMap& invalidation_map =
991 ModelTypeInvalidationMapToObjectIdInvalidationMap(
992 event.snapshot.source().types);
993 invalidator_->SendInvalidation(invalidation_map);
994 } else {
995 DVLOG(1) << "Not sending invalidation: invalidator_ is NULL";
1000 if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
1001 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1002 OnStopSyncingPermanently());
1003 return;
1006 if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
1007 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1008 OnUpdatedToken(event.updated_token));
1009 return;
1012 if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) {
1013 FOR_EACH_OBSERVER(
1014 SyncManager::Observer, observers_,
1015 OnActionableError(
1016 event.snapshot.model_neutral_state().sync_protocol_error));
1017 return;
1021 void SyncManagerImpl::SetJsEventHandler(
1022 const WeakHandle<JsEventHandler>& event_handler) {
1023 js_event_handler_ = event_handler;
1024 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_);
1025 js_mutation_event_observer_.SetJsEventHandler(js_event_handler_);
1026 js_sync_encryption_handler_observer_.SetJsEventHandler(js_event_handler_);
1029 void SyncManagerImpl::ProcessJsMessage(
1030 const std::string& name, const JsArgList& args,
1031 const WeakHandle<JsReplyHandler>& reply_handler) {
1032 if (!initialized_) {
1033 NOTREACHED();
1034 return;
1037 if (!reply_handler.IsInitialized()) {
1038 DVLOG(1) << "Uninitialized reply handler; dropping unknown message "
1039 << name << " with args " << args.ToString();
1040 return;
1043 JsMessageHandler js_message_handler = js_message_handlers_[name];
1044 if (js_message_handler.is_null()) {
1045 DVLOG(1) << "Dropping unknown message " << name
1046 << " with args " << args.ToString();
1047 return;
1050 reply_handler.Call(FROM_HERE,
1051 &JsReplyHandler::HandleJsReply,
1052 name, js_message_handler.Run(args));
1055 void SyncManagerImpl::BindJsMessageHandler(
1056 const std::string& name,
1057 UnboundJsMessageHandler unbound_message_handler) {
1058 js_message_handlers_[name] =
1059 base::Bind(unbound_message_handler, base::Unretained(this));
1062 base::DictionaryValue* SyncManagerImpl::NotificationInfoToValue(
1063 const NotificationInfoMap& notification_info) {
1064 base::DictionaryValue* value = new base::DictionaryValue();
1066 for (NotificationInfoMap::const_iterator it = notification_info.begin();
1067 it != notification_info.end(); ++it) {
1068 const std::string& model_type_str = ModelTypeToString(it->first);
1069 value->Set(model_type_str, it->second.ToValue());
1072 return value;
1075 std::string SyncManagerImpl::NotificationInfoToString(
1076 const NotificationInfoMap& notification_info) {
1077 scoped_ptr<base::DictionaryValue> value(
1078 NotificationInfoToValue(notification_info));
1079 std::string str;
1080 base::JSONWriter::Write(value.get(), &str);
1081 return str;
1084 JsArgList SyncManagerImpl::GetNotificationState(
1085 const JsArgList& args) {
1086 const std::string& notification_state =
1087 InvalidatorStateToString(invalidator_state_);
1088 DVLOG(1) << "GetNotificationState: " << notification_state;
1089 base::ListValue return_args;
1090 return_args.Append(new base::StringValue(notification_state));
1091 return JsArgList(&return_args);
1094 JsArgList SyncManagerImpl::GetNotificationInfo(
1095 const JsArgList& args) {
1096 DVLOG(1) << "GetNotificationInfo: "
1097 << NotificationInfoToString(notification_info_map_);
1098 base::ListValue return_args;
1099 return_args.Append(NotificationInfoToValue(notification_info_map_));
1100 return JsArgList(&return_args);
1103 JsArgList SyncManagerImpl::GetRootNodeDetails(
1104 const JsArgList& args) {
1105 ReadTransaction trans(FROM_HERE, GetUserShare());
1106 ReadNode root(&trans);
1107 root.InitByRootLookup();
1108 base::ListValue return_args;
1109 return_args.Append(root.GetDetailsAsValue());
1110 return JsArgList(&return_args);
1113 JsArgList SyncManagerImpl::GetClientServerTraffic(
1114 const JsArgList& args) {
1115 base::ListValue return_args;
1116 base::ListValue* value = traffic_recorder_.ToValue();
1117 if (value != NULL)
1118 return_args.Append(value);
1119 return JsArgList(&return_args);
1122 namespace {
1124 int64 GetId(const base::ListValue& ids, int i) {
1125 std::string id_str;
1126 if (!ids.GetString(i, &id_str)) {
1127 return kInvalidId;
1129 int64 id = kInvalidId;
1130 if (!base::StringToInt64(id_str, &id)) {
1131 return kInvalidId;
1133 return id;
1136 JsArgList GetNodeInfoById(
1137 const JsArgList& args,
1138 UserShare* user_share,
1139 base::DictionaryValue* (BaseNode::*info_getter)() const) {
1140 CHECK(info_getter);
1141 base::ListValue return_args;
1142 base::ListValue* node_summaries = new base::ListValue();
1143 return_args.Append(node_summaries);
1144 const base::ListValue* id_list = NULL;
1145 ReadTransaction trans(FROM_HERE, user_share);
1146 if (args.Get().GetList(0, &id_list)) {
1147 CHECK(id_list);
1148 for (size_t i = 0; i < id_list->GetSize(); ++i) {
1149 int64 id = GetId(*id_list, i);
1150 if (id == kInvalidId) {
1151 continue;
1153 ReadNode node(&trans);
1154 if (node.InitByIdLookup(id) != BaseNode::INIT_OK) {
1155 continue;
1157 node_summaries->Append((node.*info_getter)());
1160 return JsArgList(&return_args);
1163 } // namespace
1165 JsArgList SyncManagerImpl::GetNodeSummariesById(const JsArgList& args) {
1166 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetSummaryAsValue);
1169 JsArgList SyncManagerImpl::GetNodeDetailsById(const JsArgList& args) {
1170 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetDetailsAsValue);
1173 JsArgList SyncManagerImpl::GetAllNodes(const JsArgList& args) {
1174 base::ListValue return_args;
1175 base::ListValue* result = new base::ListValue();
1176 return_args.Append(result);
1178 ReadTransaction trans(FROM_HERE, GetUserShare());
1179 std::vector<const syncable::EntryKernel*> entry_kernels;
1180 trans.GetDirectory()->GetAllEntryKernels(trans.GetWrappedTrans(),
1181 &entry_kernels);
1183 for (std::vector<const syncable::EntryKernel*>::const_iterator it =
1184 entry_kernels.begin(); it != entry_kernels.end(); ++it) {
1185 result->Append((*it)->ToValue(trans.GetCryptographer()));
1188 return JsArgList(&return_args);
1191 JsArgList SyncManagerImpl::GetChildNodeIds(const JsArgList& args) {
1192 base::ListValue return_args;
1193 base::ListValue* child_ids = new base::ListValue();
1194 return_args.Append(child_ids);
1195 int64 id = GetId(args.Get(), 0);
1196 if (id != kInvalidId) {
1197 ReadTransaction trans(FROM_HERE, GetUserShare());
1198 syncable::Directory::ChildHandles child_handles;
1199 trans.GetDirectory()->GetChildHandlesByHandle(trans.GetWrappedTrans(),
1200 id, &child_handles);
1201 for (syncable::Directory::ChildHandles::const_iterator it =
1202 child_handles.begin(); it != child_handles.end(); ++it) {
1203 child_ids->Append(new base::StringValue(base::Int64ToString(*it)));
1206 return JsArgList(&return_args);
1209 void SyncManagerImpl::UpdateNotificationInfo(
1210 const ModelTypeInvalidationMap& invalidation_map) {
1211 for (ModelTypeInvalidationMap::const_iterator it = invalidation_map.begin();
1212 it != invalidation_map.end(); ++it) {
1213 NotificationInfo* info = &notification_info_map_[it->first];
1214 info->total_count++;
1215 info->payload = it->second.payload;
1219 void SyncManagerImpl::OnInvalidatorStateChange(InvalidatorState state) {
1220 const std::string& state_str = InvalidatorStateToString(state);
1221 invalidator_state_ = state;
1222 DVLOG(1) << "Invalidator state changed to: " << state_str;
1223 const bool notifications_enabled =
1224 (invalidator_state_ == INVALIDATIONS_ENABLED);
1225 allstatus_.SetNotificationsEnabled(notifications_enabled);
1226 scheduler_->SetNotificationsEnabled(notifications_enabled);
1228 if (invalidator_state_ == syncer::INVALIDATION_CREDENTIALS_REJECTED) {
1229 // If the invalidator's credentials were rejected, that means that
1230 // our sync credentials are also bad, so invalidate those.
1231 connection_manager_->OnInvalidationCredentialsRejected();
1234 if (js_event_handler_.IsInitialized()) {
1235 base::DictionaryValue details;
1236 details.SetString("state", state_str);
1237 js_event_handler_.Call(FROM_HERE,
1238 &JsEventHandler::HandleJsEvent,
1239 "onNotificationStateChange",
1240 JsEventDetails(&details));
1244 void SyncManagerImpl::OnIncomingInvalidation(
1245 const ObjectIdInvalidationMap& invalidation_map) {
1246 DCHECK(thread_checker_.CalledOnValidThread());
1248 // TODO(dcheng): Acknowledge immediately for now. Fix this once the
1249 // invalidator doesn't repeatedly ping for unacknowledged invaliations, since
1250 // it conflicts with the sync scheduler's internal backoff algorithm.
1251 // See http://crbug.com/124149 for more information.
1252 for (ObjectIdInvalidationMap::const_iterator it = invalidation_map.begin();
1253 it != invalidation_map.end(); ++it) {
1254 invalidator_->Acknowledge(it->first, it->second.ack_handle);
1257 const ModelTypeInvalidationMap& type_invalidation_map =
1258 ObjectIdInvalidationMapToModelTypeInvalidationMap(invalidation_map);
1259 if (type_invalidation_map.empty()) {
1260 LOG(WARNING) << "Sync received invalidation without any type information.";
1261 } else {
1262 allstatus_.IncrementNudgeCounter(NUDGE_SOURCE_NOTIFICATION);
1263 scheduler_->ScheduleNudgeWithStatesAsync(
1264 TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
1265 NUDGE_SOURCE_NOTIFICATION,
1266 type_invalidation_map, FROM_HERE);
1267 allstatus_.IncrementNotificationsReceived();
1268 UpdateNotificationInfo(type_invalidation_map);
1269 debug_info_event_listener_.OnIncomingNotification(type_invalidation_map);
1272 if (js_event_handler_.IsInitialized()) {
1273 base::DictionaryValue details;
1274 base::ListValue* changed_types = new base::ListValue();
1275 details.Set("changedTypes", changed_types);
1276 for (ModelTypeInvalidationMap::const_iterator it =
1277 type_invalidation_map.begin(); it != type_invalidation_map.end();
1278 ++it) {
1279 const std::string& model_type_str =
1280 ModelTypeToString(it->first);
1281 changed_types->Append(new base::StringValue(model_type_str));
1283 details.SetString("source", "REMOTE_INVALIDATION");
1284 js_event_handler_.Call(FROM_HERE,
1285 &JsEventHandler::HandleJsEvent,
1286 "onIncomingNotification",
1287 JsEventDetails(&details));
1291 void SyncManagerImpl::RefreshTypes(ModelTypeSet types) {
1292 DCHECK(thread_checker_.CalledOnValidThread());
1293 const ModelTypeInvalidationMap& type_invalidation_map =
1294 ModelTypeSetToInvalidationMap(types, "");
1295 if (type_invalidation_map.empty()) {
1296 LOG(WARNING) << "Sync received refresh request with no types specified.";
1297 } else {
1298 allstatus_.IncrementNudgeCounter(NUDGE_SOURCE_LOCAL_REFRESH);
1299 scheduler_->ScheduleNudgeWithStatesAsync(
1300 TimeDelta::FromMilliseconds(kSyncRefreshDelayMsec),
1301 NUDGE_SOURCE_LOCAL_REFRESH,
1302 type_invalidation_map, FROM_HERE);
1305 if (js_event_handler_.IsInitialized()) {
1306 base::DictionaryValue details;
1307 base::ListValue* changed_types = new base::ListValue();
1308 details.Set("changedTypes", changed_types);
1309 for (ModelTypeInvalidationMap::const_iterator it =
1310 type_invalidation_map.begin(); it != type_invalidation_map.end();
1311 ++it) {
1312 const std::string& model_type_str =
1313 ModelTypeToString(it->first);
1314 changed_types->Append(new base::StringValue(model_type_str));
1316 details.SetString("source", "LOCAL_INVALIDATION");
1317 js_event_handler_.Call(FROM_HERE,
1318 &JsEventHandler::HandleJsEvent,
1319 "onIncomingNotification",
1320 JsEventDetails(&details));
1324 SyncStatus SyncManagerImpl::GetDetailedStatus() const {
1325 return allstatus_.status();
1328 void SyncManagerImpl::SaveChanges() {
1329 directory()->SaveChanges();
1332 UserShare* SyncManagerImpl::GetUserShare() {
1333 DCHECK(initialized_);
1334 return &share_;
1337 const std::string SyncManagerImpl::cache_guid() {
1338 DCHECK(initialized_);
1339 return directory()->cache_guid();
1342 bool SyncManagerImpl::ReceivedExperiment(Experiments* experiments) {
1343 ReadTransaction trans(FROM_HERE, GetUserShare());
1344 ReadNode nigori_node(&trans);
1345 if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
1346 DVLOG(1) << "Couldn't find Nigori node.";
1347 return false;
1349 bool found_experiment = false;
1350 if (nigori_node.GetNigoriSpecifics().sync_tab_favicons()) {
1351 experiments->sync_tab_favicons = true;
1352 found_experiment = true;
1355 ReadNode keystore_node(&trans);
1356 if (keystore_node.InitByClientTagLookup(
1357 syncer::EXPERIMENTS,
1358 syncer::kKeystoreEncryptionTag) == BaseNode::INIT_OK &&
1359 keystore_node.GetExperimentsSpecifics().keystore_encryption().enabled()) {
1360 experiments->keystore_encryption = true;
1361 found_experiment = true;
1364 ReadNode autofill_culling_node(&trans);
1365 if (autofill_culling_node.InitByClientTagLookup(
1366 syncer::EXPERIMENTS,
1367 syncer::kAutofillCullingTag) == BaseNode::INIT_OK &&
1368 autofill_culling_node.GetExperimentsSpecifics().
1369 autofill_culling().enabled()) {
1370 experiments->autofill_culling = true;
1371 found_experiment = true;
1374 ReadNode full_history_sync_node(&trans);
1375 if (full_history_sync_node.InitByClientTagLookup(
1376 syncer::EXPERIMENTS,
1377 syncer::kFullHistorySyncTag) == BaseNode::INIT_OK &&
1378 full_history_sync_node.GetExperimentsSpecifics().
1379 history_delete_directives().enabled()) {
1380 experiments->full_history_sync = true;
1381 found_experiment = true;
1384 return found_experiment;
1387 bool SyncManagerImpl::HasUnsyncedItems() {
1388 ReadTransaction trans(FROM_HERE, GetUserShare());
1389 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
1392 SyncEncryptionHandler* SyncManagerImpl::GetEncryptionHandler() {
1393 return sync_encryption_handler_.get();
1396 // static.
1397 int SyncManagerImpl::GetDefaultNudgeDelay() {
1398 return kDefaultNudgeDelayMilliseconds;
1401 // static.
1402 int SyncManagerImpl::GetPreferencesNudgeDelay() {
1403 return kPreferencesNudgeDelayMilliseconds;
1406 } // namespace syncer