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"
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
;
56 using sessions::SyncSessionContext
;
57 using syncable::ImmutableWriteTransactionInfo
;
58 using syncable::SPECIFICS
;
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
) {
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
;
86 return GetUpdatesCallerInfo::UNKNOWN
;
91 // A class to calculate nudge delays for types.
94 static TimeDelta
GetNudgeDelayTimeDelta(const ModelType
& model_type
,
95 SyncManagerImpl
* core
) {
96 NudgeDelayStrategy delay_type
= GetNudgeDelayStrategy(model_type
);
97 return GetNudgeDelayTimeDeltaFromType(delay_type
,
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
{
110 // Sync this change while syncing another change.
113 // The datatype does not use one of the predefined wait times but defines
114 // its own wait time logic for nudge.
118 static NudgeDelayStrategy
GetNudgeDelayStrategy(const ModelType
& type
) {
121 return ACCOMPANY_ONLY
;
130 static TimeDelta
GetNudgeDelayTimeDeltaFromType(
131 const NudgeDelayStrategy
& delay_type
, const ModelType
& model_type
,
132 const SyncManagerImpl
* core
) {
134 TimeDelta delay
= TimeDelta::FromMilliseconds(
135 kDefaultNudgeDelayMilliseconds
);
136 switch (delay_type
) {
138 delay
= TimeDelta::FromMilliseconds(
139 kDefaultNudgeDelayMilliseconds
);
142 delay
= TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds
);
145 switch (model_type
) {
147 delay
= TimeDelta::FromMilliseconds(
148 kPreferencesNudgeDelayMilliseconds
);
151 delay
= core
->scheduler()->GetSessionsCommitDelay();
164 SyncManagerImpl::SyncManagerImpl(const std::string
& name
)
166 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
167 change_delegate_(NULL
),
169 observing_network_connectivity_changes_(false),
170 invalidator_state_(DEFAULT_INVALIDATION_ERROR
),
171 throttled_data_type_tracker_(&allstatus_
),
172 traffic_recorder_(kMaxMessagesToRecord
, kMaxMessageSizeToRecord
),
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(
200 &SyncManagerImpl::GetAllNodes
);
201 BindJsMessageHandler(
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
);
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
)))) {
233 if (a
.ref(syncable::NEXT_ID
) != b
.ref(syncable::NEXT_ID
))
235 if (a
.ref(syncable::PARENT_ID
) != b
.ref(syncable::PARENT_ID
))
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()) {
255 if (a
.ref(syncable::IS_DIR
) != b
.ref(syncable::IS_DIR
))
257 if (!AreSpecificsEqual(cryptographer
,
258 a
.ref(syncable::SPECIFICS
),
259 b
.ref(syncable::SPECIFICS
))) {
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
))
267 if (VisiblePositionsDiffer(mutation
))
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
) {
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())
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
),
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.
321 ConfigurationParams
params(GetSourceFromReason(reason
),
326 scheduler_
->Start(SyncScheduler::CONFIGURATION_MODE
);
327 if (!scheduler_
->ScheduleConfiguration(params
))
331 void SyncManagerImpl::Init(
332 const base::FilePath
& database_location
,
333 const WeakHandle
<JsEventHandler
>& event_handler
,
334 const std::string
& sync_server_and_path
,
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(
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()),
407 debug_info_event_listener_
.GetWeakPtr()),
408 false, ModelTypeSet()));
409 LOG(ERROR
) << "Sync manager initialization failed!";
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(),
440 extensions_activity_monitor
,
441 &throttled_data_type_tracker_
,
443 &debug_info_event_listener_
,
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
);
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
) {
473 void SyncManagerImpl::OnPassphraseAccepted() {
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() {
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(
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
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
;
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())
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())
577 return directory()->PurgeEntriesWithTypeIn(partially_synced_types
,
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())
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(
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();
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.";
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.";
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_
)
771 for (ModelTypeSet::Iterator it
= models_with_changes
.First();
772 it
.Good(); it
.Inc()) {
773 change_delegate_
->OnChangesComplete(it
.Get());
774 change_observer_
.Call(
776 &SyncManager::ChangeObserver::OnChangesComplete
,
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
);
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
)) {
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.";
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
,
853 mutated_model_types
);
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
));
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
880 const sync_pb::EncryptedData
& encrypted
= original_specifics
.encrypted();
881 if (!cryptographer
->Decrypt(encrypted
, &original_specifics
)) {
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.
911 GetModelTypeFromSpecifics(it
->second
.mutated
.ref(SPECIFICS
));
912 if (type
< FIRST_REAL_MODEL_TYPE
)
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(
958 allstatus_
.IncrementNudgeCounter(NUDGE_SOURCE_LOCAL
);
959 scheduler_
->ScheduleNudgeAsync(nudge_delay
,
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
) {
976 LOG(INFO
) << "OnSyncCycleCompleted not sent because sync api is not "
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
);
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());
1006 if (event
.what_happened
== SyncEngineEvent::UPDATED_TOKEN
) {
1007 FOR_EACH_OBSERVER(SyncManager::Observer
, observers_
,
1008 OnUpdatedToken(event
.updated_token
));
1012 if (event
.what_happened
== SyncEngineEvent::ACTIONABLE_ERROR
) {
1014 SyncManager::Observer
, observers_
,
1016 event
.snapshot
.model_neutral_state().sync_protocol_error
));
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_
) {
1037 if (!reply_handler
.IsInitialized()) {
1038 DVLOG(1) << "Uninitialized reply handler; dropping unknown message "
1039 << name
<< " with args " << args
.ToString();
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();
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());
1075 std::string
SyncManagerImpl::NotificationInfoToString(
1076 const NotificationInfoMap
& notification_info
) {
1077 scoped_ptr
<base::DictionaryValue
> value(
1078 NotificationInfoToValue(notification_info
));
1080 base::JSONWriter::Write(value
.get(), &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();
1118 return_args
.Append(value
);
1119 return JsArgList(&return_args
);
1124 int64
GetId(const base::ListValue
& ids
, int i
) {
1126 if (!ids
.GetString(i
, &id_str
)) {
1129 int64 id
= kInvalidId
;
1130 if (!base::StringToInt64(id_str
, &id
)) {
1136 JsArgList
GetNodeInfoById(
1137 const JsArgList
& args
,
1138 UserShare
* user_share
,
1139 base::DictionaryValue
* (BaseNode::*info_getter
)() const) {
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
)) {
1148 for (size_t i
= 0; i
< id_list
->GetSize(); ++i
) {
1149 int64 id
= GetId(*id_list
, i
);
1150 if (id
== kInvalidId
) {
1153 ReadNode
node(&trans
);
1154 if (node
.InitByIdLookup(id
) != BaseNode::INIT_OK
) {
1157 node_summaries
->Append((node
.*info_getter
)());
1160 return JsArgList(&return_args
);
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(),
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
= ¬ification_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.";
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();
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.";
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();
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_
);
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.";
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();
1397 int SyncManagerImpl::GetDefaultNudgeDelay() {
1398 return kDefaultNudgeDelayMilliseconds
;
1402 int SyncManagerImpl::GetPreferencesNudgeDelay() {
1403 return kPreferencesNudgeDelayMilliseconds
;
1406 } // namespace syncer