Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(403)

Side by Side Diff: sync/internal_api/sync_manager_impl.cc

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

Powered by Google App Engine
This is Rietveld 408576698