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

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

Issue 10704214: [Sync] Refactor sync manager into interface. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address Comments Created 8 years, 5 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 | Annotate | Revision Log
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/public/sync_manager.h"
6
7 #include <string>
8
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 "net/base/network_change_notifier.h"
21 #include "sync/engine/all_status.h"
22 #include "sync/engine/net/server_connection_manager.h"
23 #include "sync/engine/sync_scheduler.h"
24 #include "sync/engine/syncer_types.h"
25 #include "sync/engine/throttled_data_type_tracker.h"
26 #include "sync/internal_api/change_reorder_buffer.h"
27 #include "sync/internal_api/debug_info_event_listener.h"
28 #include "sync/internal_api/js_mutation_event_observer.h"
29 #include "sync/internal_api/js_sync_manager_observer.h"
30 #include "sync/internal_api/public/base/model_type.h"
31 #include "sync/internal_api/public/base/model_type_payload_map.h"
32 #include "sync/internal_api/public/base_node.h"
33 #include "sync/internal_api/public/configure_reason.h"
34 #include "sync/internal_api/public/engine/polling_constants.h"
35 #include "sync/internal_api/public/read_node.h"
36 #include "sync/internal_api/public/read_transaction.h"
37 #include "sync/internal_api/public/user_share.h"
38 #include "sync/internal_api/public/util/experiments.h"
39 #include "sync/internal_api/public/write_node.h"
40 #include "sync/internal_api/public/write_transaction.h"
41 #include "sync/internal_api/syncapi_internal.h"
42 #include "sync/internal_api/syncapi_server_connection_manager.h"
43 #include "sync/js/js_arg_list.h"
44 #include "sync/js/js_backend.h"
45 #include "sync/js/js_event_details.h"
46 #include "sync/js/js_event_handler.h"
47 #include "sync/js/js_reply_handler.h"
48 #include "sync/notifier/notifications_disabled_reason.h"
49 #include "sync/notifier/sync_notifier.h"
50 #include "sync/notifier/sync_notifier_observer.h"
51 #include "sync/protocol/encryption.pb.h"
52 #include "sync/protocol/proto_value_conversions.h"
53 #include "sync/protocol/sync.pb.h"
54 #include "sync/syncable/directory.h"
55 #include "sync/syncable/directory_change_delegate.h"
56 #include "sync/syncable/entry.h"
57 #include "sync/syncable/in_memory_directory_backing_store.h"
58 #include "sync/syncable/nigori_util.h"
59 #include "sync/syncable/on_disk_directory_backing_store.h"
60 #include "sync/util/cryptographer.h"
61 #include "sync/util/get_session_name.h"
62 #include "sync/util/time.h"
63
64 using base::TimeDelta;
65 using sync_pb::GetUpdatesCallerInfo;
66
67 namespace {
68
69 // Delays for syncer nudges.
70 static const int kSyncRefreshDelayMsec = 500;
71 static const int kSyncSchedulerDelayMsec = 250;
72
73 GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason(
74 syncer::ConfigureReason reason) {
75 switch (reason) {
76 case syncer::CONFIGURE_REASON_RECONFIGURATION:
77 return GetUpdatesCallerInfo::RECONFIGURATION;
78 case syncer::CONFIGURE_REASON_MIGRATION:
79 return GetUpdatesCallerInfo::MIGRATION;
80 case syncer::CONFIGURE_REASON_NEW_CLIENT:
81 return GetUpdatesCallerInfo::NEW_CLIENT;
82 case syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE:
83 return GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE;
84 default:
85 NOTREACHED();
86 }
87
88 return GetUpdatesCallerInfo::UNKNOWN;
89 }
90
91 // The maximum number of times we will automatically overwrite the nigori node
92 // because the encryption keys don't match (per chrome instantiation).
93 static const int kNigoriOverwriteLimit = 10;
94
95 } // namespace
96
97 namespace syncer {
98
99 using sessions::SyncSessionContext;
100 using syncable::ImmutableWriteTransactionInfo;
101 using syncable::SPECIFICS;
102
103 const int SyncManager::kDefaultNudgeDelayMilliseconds = 200;
104 const int SyncManager::kPreferencesNudgeDelayMilliseconds = 2000;
105
106 // Maximum count and size for traffic recorder.
107 const unsigned int kMaxMessagesToRecord = 10;
108 const unsigned int kMaxMessageSizeToRecord = 5 * 1024;
109
110 //////////////////////////////////////////////////////////////////////////
111 // SyncManager's implementation: SyncManager::SyncInternal
112 class SyncManager::SyncInternal
113 : public net::NetworkChangeNotifier::IPAddressObserver,
114 public syncer::Cryptographer::Observer,
115 public syncer::SyncNotifierObserver,
116 public JsBackend,
117 public SyncEngineEventListener,
118 public ServerConnectionEventListener,
119 public syncable::DirectoryChangeDelegate {
120 public:
121 explicit SyncInternal(const std::string& name)
122 : name_(name),
123 weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
124 change_delegate_(NULL),
125 initialized_(false),
126 testing_mode_(NON_TEST),
127 observing_ip_address_changes_(false),
128 throttled_data_type_tracker_(&allstatus_),
129 traffic_recorder_(kMaxMessagesToRecord, kMaxMessageSizeToRecord),
130 encryptor_(NULL),
131 unrecoverable_error_handler_(NULL),
132 report_unrecoverable_error_function_(NULL),
133 created_on_loop_(MessageLoop::current()),
134 nigori_overwrite_count_(0) {
135 // Pre-fill |notification_info_map_|.
136 for (int i = syncer::FIRST_REAL_MODEL_TYPE;
137 i < syncer::MODEL_TYPE_COUNT; ++i) {
138 notification_info_map_.insert(
139 std::make_pair(syncer::ModelTypeFromInt(i), NotificationInfo()));
140 }
141
142 // Bind message handlers.
143 BindJsMessageHandler(
144 "getNotificationState",
145 &SyncManager::SyncInternal::GetNotificationState);
146 BindJsMessageHandler(
147 "getNotificationInfo",
148 &SyncManager::SyncInternal::GetNotificationInfo);
149 BindJsMessageHandler(
150 "getRootNodeDetails",
151 &SyncManager::SyncInternal::GetRootNodeDetails);
152 BindJsMessageHandler(
153 "getNodeSummariesById",
154 &SyncManager::SyncInternal::GetNodeSummariesById);
155 BindJsMessageHandler(
156 "getNodeDetailsById",
157 &SyncManager::SyncInternal::GetNodeDetailsById);
158 BindJsMessageHandler(
159 "getAllNodes",
160 &SyncManager::SyncInternal::GetAllNodes);
161 BindJsMessageHandler(
162 "getChildNodeIds",
163 &SyncManager::SyncInternal::GetChildNodeIds);
164 BindJsMessageHandler(
165 "getClientServerTraffic",
166 &SyncManager::SyncInternal::GetClientServerTraffic);
167 }
168
169 virtual ~SyncInternal() {
170 CHECK(!initialized_);
171 }
172
173 bool Init(const FilePath& database_location,
174 const WeakHandle<JsEventHandler>& event_handler,
175 const std::string& sync_server_and_path,
176 int port,
177 bool use_ssl,
178 const scoped_refptr<base::TaskRunner>& blocking_task_runner,
179 HttpPostProviderFactory* post_factory,
180 const syncer::ModelSafeRoutingInfo& model_safe_routing_info,
181 const std::vector<syncer::ModelSafeWorker*>& workers,
182 syncer::ExtensionsActivityMonitor*
183 extensions_activity_monitor,
184 ChangeDelegate* change_delegate,
185 const SyncCredentials& credentials,
186 syncer::SyncNotifier* sync_notifier,
187 const std::string& restored_key_for_bootstrapping,
188 TestingMode testing_mode,
189 Encryptor* encryptor,
190 UnrecoverableErrorHandler* unrecoverable_error_handler,
191 ReportUnrecoverableErrorFunction
192 report_unrecoverable_error_function);
193
194 // Sign into sync with given credentials.
195 // We do not verify the tokens given. After this call, the tokens are set
196 // and the sync DB is open. True if successful, false if something
197 // went wrong.
198 bool SignIn(const SyncCredentials& credentials);
199
200 // Purge from the directory those types with non-empty progress markers
201 // but without initial synced ended set.
202 // Returns false if an error occurred, true otherwise.
203 bool PurgePartiallySyncedTypes();
204
205 // Update tokens that we're using in Sync. Email must stay the same.
206 void UpdateCredentials(const SyncCredentials& credentials);
207
208 // Called when the user disables or enables a sync type.
209 void UpdateEnabledTypes(const ModelTypeSet& enabled_types);
210
211 // Tell the sync engine to start the syncing process.
212 void StartSyncingNormally(
213 const syncer::ModelSafeRoutingInfo& routing_info);
214
215 // Whether or not the Nigori node is encrypted using an explicit passphrase.
216 bool IsUsingExplicitPassphrase();
217
218 // Update the Cryptographer from the current nigori node and write back any
219 // necessary changes to the nigori node. We also detect missing encryption
220 // keys and write them into the nigori node.
221 // Also updates or adds the device information into the nigori node.
222 // Note: opens a transaction and can trigger an ON_PASSPHRASE_REQUIRED, so
223 // should only be called after syncapi is fully initialized.
224 // Calls the callback argument with true if cryptographer is ready, false
225 // otherwise.
226 void UpdateCryptographerAndNigori(
227 const std::string& chrome_version,
228 const base::Closure& done_callback);
229
230 // Stores the current set of encryption keys (if the cryptographer is ready)
231 // and encrypted types into the nigori node.
232 void UpdateNigoriEncryptionState(Cryptographer* cryptographer,
233 WriteNode* nigori_node);
234
235 // Updates the nigori node with any new encrypted types and then
236 // encrypts the nodes for those new data types as well as other
237 // nodes that should be encrypted but aren't. Triggers
238 // OnPassphraseRequired if the cryptographer isn't ready.
239 void RefreshEncryption();
240
241 // Re-encrypts the encrypted data types using the passed passphrase, and sets
242 // a flag in the nigori node specifying whether the current passphrase is
243 // explicit (custom passphrase) or non-explicit (GAIA). If the existing
244 // encryption passphrase is "explicit", the data cannot be re-encrypted and
245 // SetEncryptionPassphrase will do nothing.
246 // If !is_explicit and there are pending keys, we will attempt to decrypt them
247 // using this passphrase. If this fails, we will save this encryption key to
248 // be applied later after the pending keys are resolved.
249 // Calls FinishSetPassphrase at the end, which notifies observers of the
250 // result of the set passphrase operation, updates the nigori node, and does
251 // re-encryption.
252 void SetEncryptionPassphrase(const std::string& passphrase, bool is_explicit);
253
254 // Provides a passphrase for decrypting the user's existing sync data. Calls
255 // FinishSetPassphrase at the end, which notifies observers of the result of
256 // the set passphrase operation, updates the nigori node, and does
257 // re-encryption.
258 void SetDecryptionPassphrase(const std::string& passphrase);
259
260 // The final step of SetEncryptionPassphrase and SetDecryptionPassphrase that
261 // notifies observers of the result of the set passphrase operation, updates
262 // the nigori node, and does re-encryption.
263 // |success|: true if the operation was successful and false otherwise. If
264 // success == false, we send an OnPassphraseRequired notification.
265 // |bootstrap_token|: used to inform observers if the cryptographer's
266 // bootstrap token was updated.
267 // |is_explicit|: used to differentiate between a custom passphrase (true) and
268 // a GAIA passphrase that is implicitly used for encryption
269 // (false).
270 // |trans| and |nigori_node|: used to access data in the cryptographer.
271 void FinishSetPassphrase(
272 bool success,
273 const std::string& bootstrap_token,
274 bool is_explicit,
275 WriteTransaction* trans,
276 WriteNode* nigori_node);
277
278 // Call periodically from a database-safe thread to persist recent changes
279 // to the syncapi model.
280 void SaveChanges();
281
282 // DirectoryChangeDelegate implementation.
283 // This listener is called upon completion of a syncable transaction, and
284 // builds the list of sync-engine initiated changes that will be forwarded to
285 // the SyncManager's Observers.
286 virtual void HandleTransactionCompleteChangeEvent(
287 ModelTypeSet models_with_changes) OVERRIDE;
288 virtual ModelTypeSet HandleTransactionEndingChangeEvent(
289 const ImmutableWriteTransactionInfo& write_transaction_info,
290 syncable::BaseTransaction* trans) OVERRIDE;
291 virtual void HandleCalculateChangesChangeEventFromSyncApi(
292 const ImmutableWriteTransactionInfo& write_transaction_info,
293 syncable::BaseTransaction* trans) OVERRIDE;
294 virtual void HandleCalculateChangesChangeEventFromSyncer(
295 const ImmutableWriteTransactionInfo& write_transaction_info,
296 syncable::BaseTransaction* trans) OVERRIDE;
297
298 // Open the directory named with username_for_share
299 bool OpenDirectory();
300
301 // Cryptographer::Observer implementation.
302 virtual void OnEncryptedTypesChanged(
303 syncer::ModelTypeSet encrypted_types,
304 bool encrypt_everything) OVERRIDE;
305
306 // SyncNotifierObserver implementation.
307 virtual void OnNotificationsEnabled() OVERRIDE;
308 virtual void OnNotificationsDisabled(
309 syncer::NotificationsDisabledReason reason) OVERRIDE;
310 virtual void OnIncomingNotification(
311 const syncer::ModelTypePayloadMap& type_payloads,
312 syncer::IncomingNotificationSource source) OVERRIDE;
313
314 void AddObserver(SyncManager::Observer* observer);
315 void RemoveObserver(SyncManager::Observer* observer);
316
317 // Accessors for the private members.
318 syncable::Directory* directory() { return share_.directory.get(); }
319 SyncAPIServerConnectionManager* connection_manager() {
320 return connection_manager_.get();
321 }
322 SyncSessionContext* session_context() { return session_context_.get(); }
323 SyncScheduler* scheduler() const { return scheduler_.get(); }
324 UserShare* GetUserShare() {
325 DCHECK(initialized_);
326 return &share_;
327 }
328
329 // Return the currently active (validated) username for use with syncable
330 // types.
331 const std::string& username_for_share() const {
332 return share_.name;
333 }
334
335 SyncStatus GetStatus();
336
337 void RequestNudge(const tracked_objects::Location& nudge_location);
338
339 void RequestNudgeForDataTypes(
340 const tracked_objects::Location& nudge_location,
341 ModelTypeSet type);
342
343 TimeDelta GetNudgeDelayTimeDelta(const ModelType& model_type);
344
345 void NotifyCryptographerState(Cryptographer* cryptographer);
346
347 // See SyncManager::Shutdown* for information.
348 void StopSyncingForShutdown(const base::Closure& callback);
349 void ShutdownOnSyncThread();
350
351 // If this is a deletion for a password, sets the legacy
352 // ExtraPasswordChangeRecordData field of |buffer|. Otherwise sets
353 // |buffer|'s specifics field to contain the unencrypted data.
354 void SetExtraChangeRecordData(int64 id,
355 syncer::ModelType type,
356 ChangeReorderBuffer* buffer,
357 Cryptographer* cryptographer,
358 const syncable::EntryKernel& original,
359 bool existed_before,
360 bool exists_now);
361
362 // Called only by our NetworkChangeNotifier.
363 virtual void OnIPAddressChanged() OVERRIDE;
364
365 ModelTypeSet GetTypesWithEmptyProgressMarkerToken(ModelTypeSet types) {
366 DCHECK(initialized_);
367 syncer::ModelTypeSet result;
368 for (syncer::ModelTypeSet::Iterator i = types.First();
369 i.Good(); i.Inc()) {
370 sync_pb::DataTypeProgressMarker marker;
371 directory()->GetDownloadProgress(i.Get(), &marker);
372
373 if (marker.token().empty())
374 result.Put(i.Get());
375
376 }
377 return result;
378 }
379
380 syncer::ModelTypeSet InitialSyncEndedTypes() {
381 DCHECK(initialized_);
382 return directory()->initial_sync_ended_types();
383 }
384
385 // SyncEngineEventListener implementation.
386 virtual void OnSyncEngineEvent(const SyncEngineEvent& event) OVERRIDE;
387
388 // ServerConnectionEventListener implementation.
389 virtual void OnServerConnectionEvent(
390 const ServerConnectionEvent& event) OVERRIDE;
391
392 // JsBackend implementation.
393 virtual void SetJsEventHandler(
394 const WeakHandle<JsEventHandler>& event_handler) OVERRIDE;
395 virtual void ProcessJsMessage(
396 const std::string& name, const JsArgList& args,
397 const WeakHandle<JsReplyHandler>& reply_handler) OVERRIDE;
398
399 void SetSyncSchedulerForTest(scoped_ptr<SyncScheduler> scheduler);
400
401 private:
402 struct NotificationInfo {
403 int total_count;
404 std::string payload;
405
406 NotificationInfo() : total_count(0) {}
407
408 ~NotificationInfo() {}
409
410 // Returned pointer owned by the caller.
411 DictionaryValue* ToValue() const {
412 DictionaryValue* value = new DictionaryValue();
413 value->SetInteger("totalCount", total_count);
414 value->SetString("payload", payload);
415 return value;
416 }
417 };
418
419 typedef std::map<syncer::ModelType, NotificationInfo> NotificationInfoMap;
420 typedef JsArgList
421 (SyncManager::SyncInternal::*UnboundJsMessageHandler)(const JsArgList&);
422 typedef base::Callback<JsArgList(const JsArgList&)> JsMessageHandler;
423 typedef std::map<std::string, JsMessageHandler> JsMessageHandlerMap;
424
425 // Internal callback of UpdateCryptographerAndNigoriCallback.
426 void UpdateCryptographerAndNigoriCallback(
427 const std::string& chrome_version,
428 const base::Closure& done_callback,
429 const std::string& session_name);
430
431 // Determine if the parents or predecessors differ between the old and new
432 // versions of an entry stored in |a| and |b|. Note that a node's index may
433 // change without its NEXT_ID changing if the node at NEXT_ID also moved (but
434 // the relative order is unchanged). To handle such cases, we rely on the
435 // caller to treat a position update on any sibling as updating the positions
436 // of all siblings.
437 static bool VisiblePositionsDiffer(
438 const syncable::EntryKernelMutation& mutation) {
439 const syncable::EntryKernel& a = mutation.original;
440 const syncable::EntryKernel& b = mutation.mutated;
441 // If the datatype isn't one where the browser model cares about position,
442 // don't bother notifying that data model of position-only changes.
443 if (!ShouldMaintainPosition(
444 syncer::GetModelTypeFromSpecifics(b.ref(SPECIFICS))))
445 return false;
446 if (a.ref(syncable::NEXT_ID) != b.ref(syncable::NEXT_ID))
447 return true;
448 if (a.ref(syncable::PARENT_ID) != b.ref(syncable::PARENT_ID))
449 return true;
450 return false;
451 }
452
453 // Determine if any of the fields made visible to clients of the Sync API
454 // differ between the versions of an entry stored in |a| and |b|. A return
455 // value of false means that it should be OK to ignore this change.
456 static bool VisiblePropertiesDiffer(
457 const syncable::EntryKernelMutation& mutation,
458 Cryptographer* cryptographer) {
459 const syncable::EntryKernel& a = mutation.original;
460 const syncable::EntryKernel& b = mutation.mutated;
461 const sync_pb::EntitySpecifics& a_specifics = a.ref(SPECIFICS);
462 const sync_pb::EntitySpecifics& b_specifics = b.ref(SPECIFICS);
463 DCHECK_EQ(syncer::GetModelTypeFromSpecifics(a_specifics),
464 syncer::GetModelTypeFromSpecifics(b_specifics));
465 syncer::ModelType model_type =
466 syncer::GetModelTypeFromSpecifics(b_specifics);
467 // Suppress updates to items that aren't tracked by any browser model.
468 if (model_type < syncer::FIRST_REAL_MODEL_TYPE ||
469 !a.ref(syncable::UNIQUE_SERVER_TAG).empty()) {
470 return false;
471 }
472 if (a.ref(syncable::IS_DIR) != b.ref(syncable::IS_DIR))
473 return true;
474 if (!AreSpecificsEqual(cryptographer,
475 a.ref(syncable::SPECIFICS),
476 b.ref(syncable::SPECIFICS))) {
477 return true;
478 }
479 // We only care if the name has changed if neither specifics is encrypted
480 // (encrypted nodes blow away the NON_UNIQUE_NAME).
481 if (!a_specifics.has_encrypted() && !b_specifics.has_encrypted() &&
482 a.ref(syncable::NON_UNIQUE_NAME) != b.ref(syncable::NON_UNIQUE_NAME))
483 return true;
484 if (VisiblePositionsDiffer(mutation))
485 return true;
486 return false;
487 }
488
489 bool ChangeBuffersAreEmpty() {
490 for (int i = 0; i < syncer::MODEL_TYPE_COUNT; ++i) {
491 if (!change_buffers_[i].IsEmpty())
492 return false;
493 }
494 return true;
495 }
496
497 void ReEncryptEverything(WriteTransaction* trans);
498
499 // Called for every notification. This updates the notification statistics
500 // to be displayed in about:sync.
501 void UpdateNotificationInfo(
502 const syncer::ModelTypePayloadMap& type_payloads);
503
504 // Checks for server reachabilty and requests a nudge.
505 void OnIPAddressChangedImpl();
506
507 // Helper function used only by the constructor.
508 void BindJsMessageHandler(
509 const std::string& name, UnboundJsMessageHandler unbound_message_handler);
510
511 // Returned pointer is owned by the caller.
512 static DictionaryValue* NotificationInfoToValue(
513 const NotificationInfoMap& notification_info);
514
515 // JS message handlers.
516 JsArgList GetNotificationState(const JsArgList& args);
517 JsArgList GetNotificationInfo(const JsArgList& args);
518 JsArgList GetRootNodeDetails(const JsArgList& args);
519 JsArgList GetAllNodes(const JsArgList& args);
520 JsArgList GetNodeSummariesById(const JsArgList& args);
521 JsArgList GetNodeDetailsById(const JsArgList& args);
522 JsArgList GetChildNodeIds(const JsArgList& args);
523 JsArgList GetClientServerTraffic(const JsArgList& args);
524
525 FilePath database_path_;
526
527 const std::string name_;
528
529 base::ThreadChecker thread_checker_;
530
531 base::WeakPtrFactory<SyncInternal> weak_ptr_factory_;
532
533 // Thread-safe handle used by
534 // HandleCalculateChangesChangeEventFromSyncApi(), which can be
535 // called from any thread. Valid only between between calls to
536 // Init() and Shutdown().
537 //
538 // TODO(akalin): Ideally, we wouldn't need to store this; instead,
539 // we'd have another worker class which implements
540 // HandleCalculateChangesChangeEventFromSyncApi() and we'd pass it a
541 // WeakHandle when we construct it.
542 WeakHandle<SyncInternal> weak_handle_this_;
543
544 // |blocking_task_runner| is a TaskRunner to be used for tasks that
545 // may block on disk I/O.
546 scoped_refptr<base::TaskRunner> blocking_task_runner_;
547
548 // We give a handle to share_ to clients of the API for use when constructing
549 // any transaction type.
550 UserShare share_;
551
552 // This can be called from any thread, but only between calls to
553 // OpenDirectory() and ShutdownOnSyncThread().
554 syncer::WeakHandle<SyncManager::ChangeObserver> change_observer_;
555
556 ObserverList<SyncManager::Observer> observers_;
557
558 // The ServerConnectionManager used to abstract communication between the
559 // client (the Syncer) and the sync server.
560 scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
561
562 // A container of various bits of information used by the SyncScheduler to
563 // create SyncSessions. Must outlive the SyncScheduler.
564 scoped_ptr<SyncSessionContext> session_context_;
565
566 // The scheduler that runs the Syncer. Needs to be explicitly
567 // Start()ed.
568 scoped_ptr<SyncScheduler> scheduler_;
569
570 // The SyncNotifier which notifies us when updates need to be downloaded.
571 scoped_ptr<syncer::SyncNotifier> sync_notifier_;
572
573 // A multi-purpose status watch object that aggregates stats from various
574 // sync components.
575 AllStatus allstatus_;
576
577 // Each element of this array is a store of change records produced by
578 // HandleChangeEvent during the CALCULATE_CHANGES step. The changes are
579 // segregated by model type, and are stored here to be processed and
580 // forwarded to the observer slightly later, at the TRANSACTION_ENDING
581 // step by HandleTransactionEndingChangeEvent. The list is cleared in the
582 // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
583 ChangeReorderBuffer change_buffers_[syncer::MODEL_TYPE_COUNT];
584
585 SyncManager::ChangeDelegate* change_delegate_;
586
587 // Set to true once Init has been called.
588 bool initialized_;
589
590 // Controls the disabling of certain SyncManager features.
591 // Can be used to disable communication with the server and the use of an
592 // on-disk file for maintaining syncer state.
593 // TODO(117836): Clean up implementation of SyncManager unit tests.
594 TestingMode testing_mode_;
595
596 bool observing_ip_address_changes_;
597
598 // Map used to store the notification info to be displayed in
599 // about:sync page.
600 NotificationInfoMap notification_info_map_;
601
602 // These are for interacting with chrome://sync-internals.
603 JsMessageHandlerMap js_message_handlers_;
604 WeakHandle<JsEventHandler> js_event_handler_;
605 JsSyncManagerObserver js_sync_manager_observer_;
606 JsMutationEventObserver js_mutation_event_observer_;
607
608 syncer::ThrottledDataTypeTracker throttled_data_type_tracker_;
609
610 // This is for keeping track of client events to send to the server.
611 DebugInfoEventListener debug_info_event_listener_;
612
613 syncer::TrafficRecorder traffic_recorder_;
614
615 Encryptor* encryptor_;
616 UnrecoverableErrorHandler* unrecoverable_error_handler_;
617 ReportUnrecoverableErrorFunction report_unrecoverable_error_function_;
618
619 MessageLoop* const created_on_loop_;
620
621 // The number of times we've automatically (i.e. not via SetPassphrase or
622 // conflict resolver) updated the nigori's encryption keys in this chrome
623 // instantiation.
624 int nigori_overwrite_count_;
625 };
626
627 // A class to calculate nudge delays for types.
628 class NudgeStrategy {
629 public:
630 static TimeDelta GetNudgeDelayTimeDelta(const ModelType& model_type,
631 SyncManager::SyncInternal* core) {
632 NudgeDelayStrategy delay_type = GetNudgeDelayStrategy(model_type);
633 return GetNudgeDelayTimeDeltaFromType(delay_type,
634 model_type,
635 core);
636 }
637
638 private:
639 // Possible types of nudge delay for datatypes.
640 // Note: These are just hints. If a sync happens then all dirty entries
641 // would be committed as part of the sync.
642 enum NudgeDelayStrategy {
643 // Sync right away.
644 IMMEDIATE,
645
646 // Sync this change while syncing another change.
647 ACCOMPANY_ONLY,
648
649 // The datatype does not use one of the predefined wait times but defines
650 // its own wait time logic for nudge.
651 CUSTOM,
652 };
653
654 static NudgeDelayStrategy GetNudgeDelayStrategy(const ModelType& type) {
655 switch (type) {
656 case syncer::AUTOFILL:
657 return ACCOMPANY_ONLY;
658 case syncer::PREFERENCES:
659 case syncer::SESSIONS:
660 return CUSTOM;
661 default:
662 return IMMEDIATE;
663 }
664 }
665
666 static TimeDelta GetNudgeDelayTimeDeltaFromType(
667 const NudgeDelayStrategy& delay_type, const ModelType& model_type,
668 const SyncManager::SyncInternal* core) {
669 CHECK(core);
670 TimeDelta delay = TimeDelta::FromMilliseconds(
671 SyncManager::kDefaultNudgeDelayMilliseconds);
672 switch (delay_type) {
673 case IMMEDIATE:
674 delay = TimeDelta::FromMilliseconds(
675 SyncManager::kDefaultNudgeDelayMilliseconds);
676 break;
677 case ACCOMPANY_ONLY:
678 delay = TimeDelta::FromSeconds(
679 syncer::kDefaultShortPollIntervalSeconds);
680 break;
681 case CUSTOM:
682 switch (model_type) {
683 case syncer::PREFERENCES:
684 delay = TimeDelta::FromMilliseconds(
685 SyncManager::kPreferencesNudgeDelayMilliseconds);
686 break;
687 case syncer::SESSIONS:
688 delay = core->scheduler()->sessions_commit_delay();
689 break;
690 default:
691 NOTREACHED();
692 }
693 break;
694 default:
695 NOTREACHED();
696 }
697 return delay;
698 }
699 };
700
701 SyncManager::ChangeDelegate::~ChangeDelegate() {}
702
703 SyncManager::ChangeObserver::~ChangeObserver() {}
704
705 SyncManager::Observer::~Observer() {}
706
707 SyncManager::SyncManager(const std::string& name)
708 : data_(new SyncInternal(name)) {}
709
710 bool SyncManager::Init(
711 const FilePath& database_location,
712 const WeakHandle<JsEventHandler>& event_handler,
713 const std::string& sync_server_and_path,
714 int sync_server_port,
715 bool use_ssl,
716 const scoped_refptr<base::TaskRunner>& blocking_task_runner,
717 HttpPostProviderFactory* post_factory,
718 const syncer::ModelSafeRoutingInfo& model_safe_routing_info,
719 const std::vector<syncer::ModelSafeWorker*>& workers,
720 syncer::ExtensionsActivityMonitor* extensions_activity_monitor,
721 ChangeDelegate* change_delegate,
722 const SyncCredentials& credentials,
723 syncer::SyncNotifier* sync_notifier,
724 const std::string& restored_key_for_bootstrapping,
725 TestingMode testing_mode,
726 Encryptor* encryptor,
727 UnrecoverableErrorHandler* unrecoverable_error_handler,
728 ReportUnrecoverableErrorFunction report_unrecoverable_error_function) {
729 DCHECK(thread_checker_.CalledOnValidThread());
730 DCHECK(post_factory);
731 DVLOG(1) << "SyncManager starting Init...";
732 std::string server_string(sync_server_and_path);
733 return data_->Init(database_location,
734 event_handler,
735 server_string,
736 sync_server_port,
737 use_ssl,
738 blocking_task_runner,
739 post_factory,
740 model_safe_routing_info,
741 workers,
742 extensions_activity_monitor,
743 change_delegate,
744 credentials,
745 sync_notifier,
746 restored_key_for_bootstrapping,
747 testing_mode,
748 encryptor,
749 unrecoverable_error_handler,
750 report_unrecoverable_error_function);
751 }
752
753 void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
754 DCHECK(thread_checker_.CalledOnValidThread());
755 data_->UpdateCredentials(credentials);
756 }
757
758 void SyncManager::UpdateEnabledTypes(const ModelTypeSet& enabled_types) {
759 DCHECK(thread_checker_.CalledOnValidThread());
760 data_->UpdateEnabledTypes(enabled_types);
761 }
762
763 void SyncManager::ThrowUnrecoverableError() {
764 DCHECK(thread_checker_.CalledOnValidThread());
765 ReadTransaction trans(FROM_HERE, GetUserShare());
766 trans.GetWrappedTrans()->OnUnrecoverableError(
767 FROM_HERE, "Simulating unrecoverable error for testing purposes.");
768 }
769
770 syncer::ModelTypeSet SyncManager::InitialSyncEndedTypes() {
771 return data_->InitialSyncEndedTypes();
772 }
773
774 syncer::ModelTypeSet SyncManager::GetTypesWithEmptyProgressMarkerToken(
775 syncer::ModelTypeSet types) {
776 return data_->GetTypesWithEmptyProgressMarkerToken(types);
777 }
778
779 bool SyncManager::PurgePartiallySyncedTypes() {
780 return data_->PurgePartiallySyncedTypes();
781 }
782
783 void SyncManager::StartSyncingNormally(
784 const syncer::ModelSafeRoutingInfo& routing_info) {
785 DCHECK(thread_checker_.CalledOnValidThread());
786 data_->StartSyncingNormally(routing_info);
787 }
788
789 void SyncManager::SetEncryptionPassphrase(const std::string& passphrase,
790 bool is_explicit) {
791 DCHECK(thread_checker_.CalledOnValidThread());
792 data_->SetEncryptionPassphrase(passphrase, is_explicit);
793 }
794
795 void SyncManager::SetDecryptionPassphrase(const std::string& passphrase) {
796 DCHECK(thread_checker_.CalledOnValidThread());
797 data_->SetDecryptionPassphrase(passphrase);
798 }
799
800 void SyncManager::EnableEncryptEverything() {
801 DCHECK(thread_checker_.CalledOnValidThread());
802 {
803 // Update the cryptographer to know we're now encrypting everything.
804 WriteTransaction trans(FROM_HERE, GetUserShare());
805 Cryptographer* cryptographer = trans.GetCryptographer();
806 // Only set encrypt everything if we know we can encrypt. This allows the
807 // user to cancel encryption if they have forgotten their passphrase.
808 if (cryptographer->is_ready())
809 cryptographer->set_encrypt_everything();
810 }
811
812 // Reads from cryptographer so will automatically encrypt all
813 // datatypes and update the nigori node as necessary. Will trigger
814 // OnPassphraseRequired if necessary.
815 data_->RefreshEncryption();
816 }
817
818 bool SyncManager::EncryptEverythingEnabledForTest() const {
819 ReadTransaction trans(FROM_HERE, GetUserShare());
820 return trans.GetCryptographer()->encrypt_everything();
821 }
822
823 bool SyncManager::IsUsingExplicitPassphrase() {
824 return data_ && data_->IsUsingExplicitPassphrase();
825 }
826
827 void SyncManager::ConfigureSyncer(
828 ConfigureReason reason,
829 const syncer::ModelTypeSet& types_to_config,
830 const syncer::ModelSafeRoutingInfo& new_routing_info,
831 const base::Closure& ready_task,
832 const base::Closure& retry_task) {
833 DCHECK(thread_checker_.CalledOnValidThread());
834 DCHECK(!ready_task.is_null());
835 DCHECK(!retry_task.is_null());
836
837 // TODO(zea): set this based on whether cryptographer has keystore
838 // encryption key or not (requires opening a transaction). crbug.com/129665.
839 ConfigurationParams::KeystoreKeyStatus keystore_key_status =
840 ConfigurationParams::KEYSTORE_KEY_UNNECESSARY;
841
842 ConfigurationParams params(GetSourceFromReason(reason),
843 types_to_config,
844 new_routing_info,
845 keystore_key_status,
846 ready_task);
847
848 if (!data_->scheduler()) {
849 LOG(INFO)
850 << "SyncManager::ConfigureSyncer: could not configure because "
851 << "scheduler is null";
852 params.ready_task.Run();
853 return;
854 }
855
856 data_->scheduler()->Start(syncer::SyncScheduler::CONFIGURATION_MODE);
857 if (!data_->scheduler()->ScheduleConfiguration(params))
858 retry_task.Run();
859
860 }
861
862 bool SyncManager::SyncInternal::Init(
863 const FilePath& database_location,
864 const WeakHandle<JsEventHandler>& event_handler,
865 const std::string& sync_server_and_path,
866 int port,
867 bool use_ssl,
868 const scoped_refptr<base::TaskRunner>& blocking_task_runner,
869 HttpPostProviderFactory* post_factory,
870 const syncer::ModelSafeRoutingInfo& model_safe_routing_info,
871 const std::vector<syncer::ModelSafeWorker*>& workers,
872 syncer::ExtensionsActivityMonitor* extensions_activity_monitor,
873 ChangeDelegate* change_delegate,
874 const SyncCredentials& credentials,
875 syncer::SyncNotifier* sync_notifier,
876 const std::string& restored_key_for_bootstrapping,
877 TestingMode testing_mode,
878 Encryptor* encryptor,
879 UnrecoverableErrorHandler* unrecoverable_error_handler,
880 ReportUnrecoverableErrorFunction report_unrecoverable_error_function) {
881 CHECK(!initialized_);
882
883 DCHECK(thread_checker_.CalledOnValidThread());
884
885 DVLOG(1) << "Starting SyncInternal initialization.";
886
887 weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
888
889 blocking_task_runner_ = blocking_task_runner;
890
891 change_delegate_ = change_delegate;
892 testing_mode_ = testing_mode;
893
894 sync_notifier_.reset(sync_notifier);
895
896 AddObserver(&js_sync_manager_observer_);
897 SetJsEventHandler(event_handler);
898
899 AddObserver(&debug_info_event_listener_);
900
901 database_path_ = database_location.Append(
902 syncable::Directory::kSyncDatabaseFilename);
903 encryptor_ = encryptor;
904 unrecoverable_error_handler_ = unrecoverable_error_handler;
905 report_unrecoverable_error_function_ = report_unrecoverable_error_function;
906
907 syncable::DirectoryBackingStore* backing_store = NULL;
908 if (testing_mode_ == TEST_IN_MEMORY) {
909 // TODO(tim): 117836. Use a factory or delegate to create this and don't
910 // depend on TEST_IN_MEMORY here.
911 backing_store =
912 new syncable::InMemoryDirectoryBackingStore(credentials.email);
913 } else {
914 FilePath absolute_db_path(database_path_);
915 file_util::AbsolutePath(&absolute_db_path);
916 backing_store = new syncable::OnDiskDirectoryBackingStore(
917 credentials.email, absolute_db_path);
918 }
919
920 DCHECK(backing_store);
921 share_.directory.reset(
922 new syncable::Directory(encryptor_,
923 unrecoverable_error_handler_,
924 report_unrecoverable_error_function_,
925 backing_store));
926
927 connection_manager_.reset(new SyncAPIServerConnectionManager(
928 sync_server_and_path, port, use_ssl, post_factory));
929
930 net::NetworkChangeNotifier::AddIPAddressObserver(this);
931 observing_ip_address_changes_ = true;
932
933 connection_manager()->AddListener(this);
934
935 // Test mode does not use a syncer context or syncer thread.
936 if (testing_mode_ == NON_TEST) {
937 // Build a SyncSessionContext and store the worker in it.
938 DVLOG(1) << "Sync is bringing up SyncSessionContext.";
939 std::vector<SyncEngineEventListener*> listeners;
940 listeners.push_back(&allstatus_);
941 listeners.push_back(this);
942 session_context_.reset(new SyncSessionContext(
943 connection_manager_.get(),
944 directory(),
945 model_safe_routing_info,
946 workers,
947 extensions_activity_monitor,
948 &throttled_data_type_tracker_,
949 listeners,
950 &debug_info_event_listener_,
951 &traffic_recorder_));
952 session_context()->set_account_name(credentials.email);
953 scheduler_.reset(new SyncScheduler(name_, session_context(), new Syncer()));
954 }
955
956 bool success = SignIn(credentials);
957
958 if (success) {
959 if (scheduler()) {
960 scheduler()->Start(syncer::SyncScheduler::CONFIGURATION_MODE);
961 }
962
963 initialized_ = true;
964
965 // Unapplied datatypes (those that do not have initial sync ended set) get
966 // re-downloaded during any configuration. But, it's possible for a datatype
967 // to have a progress marker but not have initial sync ended yet, making
968 // it a candidate for migration. This is a problem, as the DataTypeManager
969 // does not support a migration while it's already in the middle of a
970 // configuration. As a result, any partially synced datatype can stall the
971 // DTM, waiting for the configuration to complete, which it never will due
972 // to the migration error. In addition, a partially synced nigori will
973 // trigger the migration logic before the backend is initialized, resulting
974 // in crashes. We therefore detect and purge any partially synced types as
975 // part of initialization.
976 if (!PurgePartiallySyncedTypes())
977 success = false;
978
979 // Cryptographer should only be accessed while holding a
980 // transaction. Grabbing the user share for the transaction
981 // checks the initialization state, so this must come after
982 // |initialized_| is set to true.
983 ReadTransaction trans(FROM_HERE, GetUserShare());
984 trans.GetCryptographer()->Bootstrap(restored_key_for_bootstrapping);
985 trans.GetCryptographer()->AddObserver(this);
986 }
987
988 // Notify that initialization is complete. Note: This should be the last to
989 // execute if |signed_in| is false. Reason being in that case we would
990 // post a task to shutdown sync. But if this function posts any other tasks
991 // on the UI thread and if shutdown wins then that tasks would execute on
992 // a freed pointer. This is because UI thread is not shut down.
993 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
994 OnInitializationComplete(
995 MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
996 success));
997
998 if (!success && testing_mode_ == NON_TEST)
999 return false;
1000
1001 sync_notifier_->AddObserver(this);
1002
1003 return success;
1004 }
1005
1006 void SyncManager::SyncInternal::UpdateCryptographerAndNigori(
1007 const std::string& chrome_version,
1008 const base::Closure& done_callback) {
1009 DCHECK(initialized_);
1010 syncer::GetSessionName(
1011 blocking_task_runner_,
1012 base::Bind(
1013 &SyncManager::SyncInternal::UpdateCryptographerAndNigoriCallback,
1014 weak_ptr_factory_.GetWeakPtr(),
1015 chrome_version,
1016 done_callback));
1017 }
1018
1019 void SyncManager::SyncInternal::UpdateNigoriEncryptionState(
1020 Cryptographer* cryptographer,
1021 WriteNode* nigori_node) {
1022 DCHECK(nigori_node);
1023 sync_pb::NigoriSpecifics nigori = nigori_node->GetNigoriSpecifics();
1024
1025 if (cryptographer->is_ready() &&
1026 nigori_overwrite_count_ < kNigoriOverwriteLimit) {
1027 // Does not modify the encrypted blob if the unencrypted data already
1028 // matches what is about to be written.
1029 sync_pb::EncryptedData original_keys = nigori.encrypted();
1030 if (!cryptographer->GetKeys(nigori.mutable_encrypted()))
1031 NOTREACHED();
1032
1033 if (nigori.encrypted().SerializeAsString() !=
1034 original_keys.SerializeAsString()) {
1035 // We've updated the nigori node's encryption keys. In order to prevent
1036 // a possible looping of two clients constantly overwriting each other,
1037 // we limit the absolute number of overwrites per client instantiation.
1038 nigori_overwrite_count_++;
1039 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites",
1040 nigori_overwrite_count_);
1041 }
1042
1043 // Note: we don't try to set using_explicit_passphrase here since if that
1044 // is lost the user can always set it again. The main point is to preserve
1045 // the encryption keys so all data remains decryptable.
1046 }
1047 cryptographer->UpdateNigoriFromEncryptedTypes(&nigori);
1048
1049 // If nothing has changed, this is a no-op.
1050 nigori_node->SetNigoriSpecifics(nigori);
1051 }
1052
1053 void SyncManager::SyncInternal::UpdateCryptographerAndNigoriCallback(
1054 const std::string& chrome_version,
1055 const base::Closure& done_callback,
1056 const std::string& session_name) {
1057 if (!directory()->initial_sync_ended_for_type(syncer::NIGORI)) {
1058 done_callback.Run(); // Should only happen during first time sync.
1059 return;
1060 }
1061
1062 bool success = false;
1063 {
1064 WriteTransaction trans(FROM_HERE, GetUserShare());
1065 Cryptographer* cryptographer = trans.GetCryptographer();
1066 WriteNode node(&trans);
1067
1068 if (node.InitByTagLookup(kNigoriTag) == syncer::BaseNode::INIT_OK) {
1069 sync_pb::NigoriSpecifics nigori(node.GetNigoriSpecifics());
1070 Cryptographer::UpdateResult result = cryptographer->Update(nigori);
1071 if (result == Cryptographer::NEEDS_PASSPHRASE) {
1072 sync_pb::EncryptedData pending_keys;
1073 if (cryptographer->has_pending_keys())
1074 pending_keys = cryptographer->GetPendingKeys();
1075 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1076 OnPassphraseRequired(syncer::REASON_DECRYPTION,
1077 pending_keys));
1078 }
1079
1080
1081 // Add or update device information.
1082 bool contains_this_device = false;
1083 for (int i = 0; i < nigori.device_information_size(); ++i) {
1084 const sync_pb::DeviceInformation& device_information =
1085 nigori.device_information(i);
1086 if (device_information.cache_guid() == directory()->cache_guid()) {
1087 // Update the version number in case it changed due to an update.
1088 if (device_information.chrome_version() != chrome_version) {
1089 sync_pb::DeviceInformation* mutable_device_information =
1090 nigori.mutable_device_information(i);
1091 mutable_device_information->set_chrome_version(
1092 chrome_version);
1093 }
1094 contains_this_device = true;
1095 }
1096 }
1097
1098 if (!contains_this_device) {
1099 sync_pb::DeviceInformation* device_information =
1100 nigori.add_device_information();
1101 device_information->set_cache_guid(directory()->cache_guid());
1102 #if defined(OS_CHROMEOS)
1103 device_information->set_platform("ChromeOS");
1104 #elif defined(OS_LINUX)
1105 device_information->set_platform("Linux");
1106 #elif defined(OS_MACOSX)
1107 device_information->set_platform("Mac");
1108 #elif defined(OS_WIN)
1109 device_information->set_platform("Windows");
1110 #endif
1111 device_information->set_name(session_name);
1112 device_information->set_chrome_version(chrome_version);
1113 }
1114 // Disabled to avoid nigori races. TODO(zea): re-enable. crbug.com/122837
1115 // node.SetNigoriSpecifics(nigori);
1116
1117 // Make sure the nigori node has the up to date encryption info.
1118 UpdateNigoriEncryptionState(cryptographer, &node);
1119
1120 NotifyCryptographerState(cryptographer);
1121 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
1122
1123 success = cryptographer->is_ready();
1124 } else {
1125 NOTREACHED();
1126 }
1127 }
1128
1129 if (success)
1130 RefreshEncryption();
1131 done_callback.Run();
1132 }
1133
1134 void SyncManager::SyncInternal::NotifyCryptographerState(
1135 Cryptographer * cryptographer) {
1136 // TODO(lipalani): Explore the possibility of hooking this up to
1137 // SyncManager::Observer and making |AllStatus| a listener for that.
1138 allstatus_.SetCryptographerReady(cryptographer->is_ready());
1139 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
1140 debug_info_event_listener_.SetCryptographerReady(cryptographer->is_ready());
1141 debug_info_event_listener_.SetCrytographerHasPendingKeys(
1142 cryptographer->has_pending_keys());
1143 }
1144
1145 void SyncManager::SyncInternal::StartSyncingNormally(
1146 const syncer::ModelSafeRoutingInfo& routing_info) {
1147 // Start the sync scheduler.
1148 if (scheduler()) { // NULL during certain unittests.
1149 // TODO(sync): We always want the newest set of routes when we switch back
1150 // to normal mode. Figure out how to enforce set_routing_info is always
1151 // appropriately set and that it's only modified when switching to normal
1152 // mode.
1153 session_context()->set_routing_info(routing_info);
1154 scheduler()->Start(SyncScheduler::NORMAL_MODE);
1155 }
1156 }
1157
1158 bool SyncManager::SyncInternal::OpenDirectory() {
1159 DCHECK(!initialized_) << "Should only happen once";
1160
1161 // Set before Open().
1162 change_observer_ =
1163 syncer::MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr());
1164 WeakHandle<syncable::TransactionObserver> transaction_observer(
1165 syncer::MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr()));
1166
1167 syncable::DirOpenResult open_result = syncable::NOT_INITIALIZED;
1168 open_result = directory()->Open(username_for_share(), this,
1169 transaction_observer);
1170 if (open_result != syncable::OPENED) {
1171 LOG(ERROR) << "Could not open share for:" << username_for_share();
1172 return false;
1173 }
1174
1175 connection_manager()->set_client_id(directory()->cache_guid());
1176 return true;
1177 }
1178
1179 bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
1180 DCHECK(thread_checker_.CalledOnValidThread());
1181 DCHECK(share_.name.empty());
1182 share_.name = credentials.email;
1183
1184 DVLOG(1) << "Signing in user: " << username_for_share();
1185 if (!OpenDirectory())
1186 return false;
1187
1188 // Retrieve and set the sync notifier state. This should be done
1189 // only after OpenDirectory is called.
1190 std::string unique_id = directory()->cache_guid();
1191 std::string state = directory()->GetNotificationState();
1192 DVLOG(1) << "Read notification unique ID: " << unique_id;
1193 if (VLOG_IS_ON(1)) {
1194 std::string encoded_state;
1195 base::Base64Encode(state, &encoded_state);
1196 DVLOG(1) << "Read notification state: " << encoded_state;
1197 }
1198 allstatus_.SetUniqueId(unique_id);
1199 sync_notifier_->SetUniqueId(unique_id);
1200 // TODO(tim): Remove once invalidation state has been migrated to new
1201 // InvalidationStateTracker store. Bug 124140.
1202 sync_notifier_->SetStateDeprecated(state);
1203
1204 UpdateCredentials(credentials);
1205 return true;
1206 }
1207
1208 bool SyncManager::SyncInternal::PurgePartiallySyncedTypes() {
1209 syncer::ModelTypeSet partially_synced_types =
1210 syncer::ModelTypeSet::All();
1211 partially_synced_types.RemoveAll(InitialSyncEndedTypes());
1212 partially_synced_types.RemoveAll(GetTypesWithEmptyProgressMarkerToken(
1213 syncer::ModelTypeSet::All()));
1214
1215 UMA_HISTOGRAM_COUNTS("Sync.PartiallySyncedTypes",
1216 partially_synced_types.Size());
1217 if (partially_synced_types.Empty())
1218 return true;
1219 return directory()->PurgeEntriesWithTypeIn(partially_synced_types);
1220 }
1221
1222 void SyncManager::SyncInternal::UpdateCredentials(
1223 const SyncCredentials& credentials) {
1224 DCHECK(thread_checker_.CalledOnValidThread());
1225 DCHECK_EQ(credentials.email, share_.name);
1226 DCHECK(!credentials.email.empty());
1227 DCHECK(!credentials.sync_token.empty());
1228
1229 observing_ip_address_changes_ = true;
1230 if (connection_manager()->set_auth_token(credentials.sync_token)) {
1231 sync_notifier_->UpdateCredentials(
1232 credentials.email, credentials.sync_token);
1233 if (initialized_ && scheduler()) {
1234 scheduler()->OnCredentialsUpdated();
1235 }
1236 }
1237 }
1238
1239 void SyncManager::SyncInternal::UpdateEnabledTypes(
1240 const ModelTypeSet& enabled_types) {
1241 DCHECK(thread_checker_.CalledOnValidThread());
1242 sync_notifier_->UpdateEnabledTypes(enabled_types);
1243 }
1244
1245 void SyncManager::SyncInternal::SetEncryptionPassphrase(
1246 const std::string& passphrase,
1247 bool is_explicit) {
1248 // We do not accept empty passphrases.
1249 if (passphrase.empty()) {
1250 NOTREACHED() << "Cannot encrypt with an empty passphrase.";
1251 return;
1252 }
1253
1254 // All accesses to the cryptographer are protected by a transaction.
1255 WriteTransaction trans(FROM_HERE, GetUserShare());
1256 Cryptographer* cryptographer = trans.GetCryptographer();
1257 KeyParams key_params = {"localhost", "dummy", passphrase};
1258 WriteNode node(&trans);
1259 if (node.InitByTagLookup(kNigoriTag) != syncer::BaseNode::INIT_OK) {
1260 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1261 NOTREACHED();
1262 return;
1263 }
1264
1265 bool nigori_has_explicit_passphrase =
1266 node.GetNigoriSpecifics().using_explicit_passphrase();
1267 std::string bootstrap_token;
1268 sync_pb::EncryptedData pending_keys;
1269 if (cryptographer->has_pending_keys())
1270 pending_keys = cryptographer->GetPendingKeys();
1271 bool success = false;
1272
1273
1274 // There are six cases to handle here:
1275 // 1. The user has no pending keys and is setting their current GAIA password
1276 // as the encryption passphrase. This happens either during first time sync
1277 // with a clean profile, or after re-authenticating on a profile that was
1278 // already signed in with the cryptographer ready.
1279 // 2. The user has no pending keys, and is overwriting an (already provided)
1280 // implicit passphrase with an explicit (custom) passphrase.
1281 // 3. The user has pending keys for an explicit passphrase that is somehow set
1282 // to their current GAIA passphrase.
1283 // 4. The user has pending keys encrypted with their current GAIA passphrase
1284 // and the caller passes in the current GAIA passphrase.
1285 // 5. The user has pending keys encrypted with an older GAIA passphrase
1286 // and the caller passes in the current GAIA passphrase.
1287 // 6. The user has previously done encryption with an explicit passphrase.
1288 // Furthermore, we enforce the fact that the bootstrap encryption token will
1289 // always be derived from the newest GAIA password if the account is using
1290 // an implicit passphrase (even if the data is encrypted with an old GAIA
1291 // password). If the account is using an explicit (custom) passphrase, the
1292 // bootstrap token will be derived from the most recently provided explicit
1293 // passphrase (that was able to decrypt the data).
1294 if (!nigori_has_explicit_passphrase) {
1295 if (!cryptographer->has_pending_keys()) {
1296 if (cryptographer->AddKey(key_params)) {
1297 // Case 1 and 2. We set a new GAIA passphrase when there are no pending
1298 // keys (1), or overwriting an implicit passphrase with a new explicit
1299 // one (2) when there are no pending keys.
1300 DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" )
1301 << " passphrase for encryption.";
1302 cryptographer->GetBootstrapToken(&bootstrap_token);
1303 success = true;
1304 } else {
1305 NOTREACHED() << "Failed to add key to cryptographer.";
1306 success = false;
1307 }
1308 } else { // cryptographer->has_pending_keys() == true
1309 if (is_explicit) {
1310 // This can only happen if the nigori node is updated with a new
1311 // implicit passphrase while a client is attempting to set a new custom
1312 // passphrase (race condition).
1313 DVLOG(1) << "Failing because an implicit passphrase is already set.";
1314 success = false;
1315 } else { // is_explicit == false
1316 if (cryptographer->DecryptPendingKeys(key_params)) {
1317 // Case 4. We successfully decrypted with the implicit GAIA passphrase
1318 // passed in.
1319 DVLOG(1) << "Implicit internal passphrase accepted for decryption.";
1320 cryptographer->GetBootstrapToken(&bootstrap_token);
1321 success = true;
1322 } else {
1323 // Case 5. Encryption was done with an old GAIA password, but we were
1324 // provided with the current GAIA password. We need to generate a new
1325 // bootstrap token to preserve it. We build a temporary cryptographer
1326 // to allow us to extract these params without polluting our current
1327 // cryptographer.
1328 DVLOG(1) << "Implicit internal passphrase failed to decrypt, adding "
1329 << "anyways as default passphrase and persisting via "
1330 << "bootstrap token.";
1331 Cryptographer temp_cryptographer(encryptor_);
1332 temp_cryptographer.AddKey(key_params);
1333 temp_cryptographer.GetBootstrapToken(&bootstrap_token);
1334 // We then set the new passphrase as the default passphrase of the
1335 // real cryptographer, even though we have pending keys. This is safe,
1336 // as although Cryptographer::is_initialized() will now be true,
1337 // is_ready() will remain false due to having pending keys.
1338 cryptographer->AddKey(key_params);
1339 success = false;
1340 }
1341 } // is_explicit
1342 } // cryptographer->has_pending_keys()
1343 } else { // nigori_has_explicit_passphrase == true
1344 // Case 6. We do not want to override a previously set explicit passphrase,
1345 // so we return a failure.
1346 DVLOG(1) << "Failing because an explicit passphrase is already set.";
1347 success = false;
1348 }
1349
1350 DVLOG_IF(1, !success)
1351 << "Failure in SetEncryptionPassphrase; notifying and returning.";
1352 DVLOG_IF(1, success)
1353 << "Successfully set encryption passphrase; updating nigori and "
1354 "reencrypting.";
1355
1356 FinishSetPassphrase(
1357 success, bootstrap_token, is_explicit, &trans, &node);
1358 }
1359
1360 void SyncManager::SyncInternal::SetDecryptionPassphrase(
1361 const std::string& passphrase) {
1362 // We do not accept empty passphrases.
1363 if (passphrase.empty()) {
1364 NOTREACHED() << "Cannot decrypt with an empty passphrase.";
1365 return;
1366 }
1367
1368 // All accesses to the cryptographer are protected by a transaction.
1369 WriteTransaction trans(FROM_HERE, GetUserShare());
1370 Cryptographer* cryptographer = trans.GetCryptographer();
1371 KeyParams key_params = {"localhost", "dummy", passphrase};
1372 WriteNode node(&trans);
1373 if (node.InitByTagLookup(kNigoriTag) != syncer::BaseNode::INIT_OK) {
1374 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1375 NOTREACHED();
1376 return;
1377 }
1378
1379 if (!cryptographer->has_pending_keys()) {
1380 // Note that this *can* happen in a rare situation where data is
1381 // re-encrypted on another client while a SetDecryptionPassphrase() call is
1382 // in-flight on this client. It is rare enough that we choose to do nothing.
1383 NOTREACHED() << "Attempt to set decryption passphrase failed because there "
1384 << "were no pending keys.";
1385 return;
1386 }
1387
1388 bool nigori_has_explicit_passphrase =
1389 node.GetNigoriSpecifics().using_explicit_passphrase();
1390 std::string bootstrap_token;
1391 sync_pb::EncryptedData pending_keys;
1392 pending_keys = cryptographer->GetPendingKeys();
1393 bool success = false;
1394
1395 // There are three cases to handle here:
1396 // 7. We're using the current GAIA password to decrypt the pending keys. This
1397 // happens when signing in to an account with a previously set implicit
1398 // passphrase, where the data is already encrypted with the newest GAIA
1399 // password.
1400 // 8. The user is providing an old GAIA password to decrypt the pending keys.
1401 // In this case, the user is using an implicit passphrase, but has changed
1402 // their password since they last encrypted their data, and therefore
1403 // their current GAIA password was unable to decrypt the data. This will
1404 // happen when the user is setting up a new profile with a previously
1405 // encrypted account (after changing passwords).
1406 // 9. The user is providing a previously set explicit passphrase to decrypt
1407 // the pending keys.
1408 if (!nigori_has_explicit_passphrase) {
1409 if (cryptographer->is_initialized()) {
1410 // We only want to change the default encryption key to the pending
1411 // one if the pending keybag already contains the current default.
1412 // This covers the case where a different client re-encrypted
1413 // everything with a newer gaia passphrase (and hence the keybag
1414 // contains keys from all previously used gaia passphrases).
1415 // Otherwise, we're in a situation where the pending keys are
1416 // encrypted with an old gaia passphrase, while the default is the
1417 // current gaia passphrase. In that case, we preserve the default.
1418 Cryptographer temp_cryptographer(encryptor_);
1419 temp_cryptographer.SetPendingKeys(cryptographer->GetPendingKeys());
1420 if (temp_cryptographer.DecryptPendingKeys(key_params)) {
1421 // Check to see if the pending bag of keys contains the current
1422 // default key.
1423 sync_pb::EncryptedData encrypted;
1424 cryptographer->GetKeys(&encrypted);
1425 if (temp_cryptographer.CanDecrypt(encrypted)) {
1426 DVLOG(1) << "Implicit user provided passphrase accepted for "
1427 << "decryption, overwriting default.";
1428 // Case 7. The pending keybag contains the current default. Go ahead
1429 // and update the cryptographer, letting the default change.
1430 cryptographer->DecryptPendingKeys(key_params);
1431 cryptographer->GetBootstrapToken(&bootstrap_token);
1432 success = true;
1433 } else {
1434 // Case 8. The pending keybag does not contain the current default
1435 // encryption key. We decrypt the pending keys here, and in
1436 // FinishSetPassphrase, re-encrypt everything with the current GAIA
1437 // passphrase instead of the passphrase just provided by the user.
1438 DVLOG(1) << "Implicit user provided passphrase accepted for "
1439 << "decryption, restoring implicit internal passphrase "
1440 << "as default.";
1441 std::string bootstrap_token_from_current_key;
1442 cryptographer->GetBootstrapToken(
1443 &bootstrap_token_from_current_key);
1444 cryptographer->DecryptPendingKeys(key_params);
1445 // Overwrite the default from the pending keys.
1446 cryptographer->AddKeyFromBootstrapToken(
1447 bootstrap_token_from_current_key);
1448 success = true;
1449 }
1450 } else { // !temp_cryptographer.DecryptPendingKeys(..)
1451 DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
1452 success = false;
1453 } // temp_cryptographer.DecryptPendingKeys(...)
1454 } else { // cryptographer->is_initialized() == false
1455 if (cryptographer->DecryptPendingKeys(key_params)) {
1456 // This can happpen in two cases:
1457 // - First time sync on android, where we'll never have a
1458 // !user_provided passphrase.
1459 // - This is a restart for a client that lost their bootstrap token.
1460 // In both cases, we should go ahead and initialize the cryptographer
1461 // and persist the new bootstrap token.
1462 //
1463 // Note: at this point, we cannot distinguish between cases 7 and 8
1464 // above. This user provided passphrase could be the current or the
1465 // old. But, as long as we persist the token, there's nothing more
1466 // we can do.
1467 cryptographer->GetBootstrapToken(&bootstrap_token);
1468 DVLOG(1) << "Implicit user provided passphrase accepted, initializing"
1469 << " cryptographer.";
1470 success = true;
1471 } else {
1472 DVLOG(1) << "Implicit user provided passphrase failed to decrypt.";
1473 success = false;
1474 }
1475 } // cryptographer->is_initialized()
1476 } else { // nigori_has_explicit_passphrase == true
1477 // Case 9. Encryption was done with an explicit passphrase, and we decrypt
1478 // with the passphrase provided by the user.
1479 if (cryptographer->DecryptPendingKeys(key_params)) {
1480 DVLOG(1) << "Explicit passphrase accepted for decryption.";
1481 cryptographer->GetBootstrapToken(&bootstrap_token);
1482 success = true;
1483 } else {
1484 DVLOG(1) << "Explicit passphrase failed to decrypt.";
1485 success = false;
1486 }
1487 } // nigori_has_explicit_passphrase
1488
1489 DVLOG_IF(1, !success)
1490 << "Failure in SetDecryptionPassphrase; notifying and returning.";
1491 DVLOG_IF(1, success)
1492 << "Successfully set decryption passphrase; updating nigori and "
1493 "reencrypting.";
1494
1495 FinishSetPassphrase(success,
1496 bootstrap_token,
1497 nigori_has_explicit_passphrase,
1498 &trans,
1499 &node);
1500 }
1501
1502 void SyncManager::SyncInternal::FinishSetPassphrase(
1503 bool success,
1504 const std::string& bootstrap_token,
1505 bool is_explicit,
1506 WriteTransaction* trans,
1507 WriteNode* nigori_node) {
1508 Cryptographer* cryptographer = trans->GetCryptographer();
1509 NotifyCryptographerState(cryptographer);
1510
1511 // It's possible we need to change the bootstrap token even if we failed to
1512 // set the passphrase (for example if we need to preserve the new GAIA
1513 // passphrase).
1514 if (!bootstrap_token.empty()) {
1515 DVLOG(1) << "Bootstrap token updated.";
1516 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1517 OnBootstrapTokenUpdated(bootstrap_token));
1518 }
1519
1520 if (!success) {
1521 if (cryptographer->is_ready()) {
1522 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer "
1523 << "was ready.";
1524 } else if (cryptographer->has_pending_keys()) {
1525 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1526 OnPassphraseRequired(syncer::REASON_DECRYPTION,
1527 cryptographer->GetPendingKeys()));
1528 } else {
1529 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1530 OnPassphraseRequired(syncer::REASON_ENCRYPTION,
1531 sync_pb::EncryptedData()));
1532 }
1533 return;
1534 }
1535
1536 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1537 OnPassphraseAccepted());
1538 DCHECK(cryptographer->is_ready());
1539
1540 // TODO(tim): Bug 58231. It would be nice if setting a passphrase didn't
1541 // require messing with the Nigori node, because we can't set a passphrase
1542 // until download conditions are met vs Cryptographer init. It seems like
1543 // it's safe to defer this work.
1544 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics());
1545 // Does not modify specifics.encrypted() if the original decrypted data was
1546 // the same.
1547 if (!cryptographer->GetKeys(specifics.mutable_encrypted())) {
1548 NOTREACHED();
1549 return;
1550 }
1551 specifics.set_using_explicit_passphrase(is_explicit);
1552 nigori_node->SetNigoriSpecifics(specifics);
1553
1554 // Does nothing if everything is already encrypted or the cryptographer has
1555 // pending keys.
1556 ReEncryptEverything(trans);
1557 }
1558
1559 bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
1560 ReadTransaction trans(FROM_HERE, &share_);
1561 ReadNode node(&trans);
1562 if (node.InitByTagLookup(kNigoriTag) != syncer::BaseNode::INIT_OK) {
1563 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1564 NOTREACHED();
1565 return false;
1566 }
1567
1568 return node.GetNigoriSpecifics().using_explicit_passphrase();
1569 }
1570
1571 void SyncManager::SyncInternal::RefreshEncryption() {
1572 DCHECK(initialized_);
1573
1574 WriteTransaction trans(FROM_HERE, GetUserShare());
1575 WriteNode node(&trans);
1576 if (node.InitByTagLookup(kNigoriTag) != syncer::BaseNode::INIT_OK) {
1577 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not "
1578 << "found.";
1579 return;
1580 }
1581
1582 Cryptographer* cryptographer = trans.GetCryptographer();
1583
1584 if (!cryptographer->is_ready()) {
1585 DVLOG(1) << "Attempting to encrypt datatypes when cryptographer not "
1586 << "initialized, prompting for passphrase.";
1587 // TODO(zea): this isn't really decryption, but that's the only way we have
1588 // to prompt the user for a passsphrase. See http://crbug.com/91379.
1589 sync_pb::EncryptedData pending_keys;
1590 if (cryptographer->has_pending_keys())
1591 pending_keys = cryptographer->GetPendingKeys();
1592 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1593 OnPassphraseRequired(syncer::REASON_DECRYPTION,
1594 pending_keys));
1595 return;
1596 }
1597
1598 UpdateNigoriEncryptionState(cryptographer, &node);
1599
1600 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
1601
1602 // We reencrypt everything regardless of whether the set of encrypted
1603 // types changed to ensure that any stray unencrypted entries are overwritten.
1604 ReEncryptEverything(&trans);
1605 }
1606
1607 // This function iterates over all encrypted types. There are many scenarios in
1608 // which data for some or all types is not currently available. In that case,
1609 // the lookup of the root node will fail and we will skip encryption for that
1610 // type.
1611 void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
1612 Cryptographer* cryptographer = trans->GetCryptographer();
1613 if (!cryptographer || !cryptographer->is_ready())
1614 return;
1615 syncer::ModelTypeSet encrypted_types = GetEncryptedTypes(trans);
1616 for (syncer::ModelTypeSet::Iterator iter = encrypted_types.First();
1617 iter.Good(); iter.Inc()) {
1618 if (iter.Get() == syncer::PASSWORDS || iter.Get() == syncer::NIGORI)
1619 continue; // These types handle encryption differently.
1620
1621 ReadNode type_root(trans);
1622 std::string tag = syncer::ModelTypeToRootTag(iter.Get());
1623 if (type_root.InitByTagLookup(tag) != syncer::BaseNode::INIT_OK)
1624 continue; // Don't try to reencrypt if the type's data is unavailable.
1625
1626 // Iterate through all children of this datatype.
1627 std::queue<int64> to_visit;
1628 int64 child_id = type_root.GetFirstChildId();
1629 to_visit.push(child_id);
1630 while (!to_visit.empty()) {
1631 child_id = to_visit.front();
1632 to_visit.pop();
1633 if (child_id == kInvalidId)
1634 continue;
1635
1636 WriteNode child(trans);
1637 if (child.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK) {
1638 NOTREACHED();
1639 continue;
1640 }
1641 if (child.GetIsFolder()) {
1642 to_visit.push(child.GetFirstChildId());
1643 }
1644 if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) {
1645 // Rewrite the specifics of the node with encrypted data if necessary
1646 // (only rewrite the non-unique folders).
1647 child.ResetFromSpecifics();
1648 }
1649 to_visit.push(child.GetSuccessorId());
1650 }
1651 }
1652
1653 // Passwords are encrypted with their own legacy scheme. Passwords are always
1654 // encrypted so we don't need to check GetEncryptedTypes() here.
1655 ReadNode passwords_root(trans);
1656 std::string passwords_tag = syncer::ModelTypeToRootTag(syncer::PASSWORDS);
1657 if (passwords_root.InitByTagLookup(passwords_tag) ==
1658 syncer::BaseNode::INIT_OK) {
1659 int64 child_id = passwords_root.GetFirstChildId();
1660 while (child_id != kInvalidId) {
1661 WriteNode child(trans);
1662 if (child.InitByIdLookup(child_id) != syncer::BaseNode::INIT_OK) {
1663 NOTREACHED();
1664 return;
1665 }
1666 child.SetPasswordSpecifics(child.GetPasswordSpecifics());
1667 child_id = child.GetSuccessorId();
1668 }
1669 }
1670
1671 // NOTE: We notify from within a transaction.
1672 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, OnEncryptionComplete());
1673 }
1674
1675 SyncManager::~SyncManager() {
1676 DCHECK(thread_checker_.CalledOnValidThread());
1677 delete data_;
1678 }
1679
1680 void SyncManager::AddObserver(Observer* observer) {
1681 DCHECK(thread_checker_.CalledOnValidThread());
1682 data_->AddObserver(observer);
1683 }
1684
1685 void SyncManager::RemoveObserver(Observer* observer) {
1686 DCHECK(thread_checker_.CalledOnValidThread());
1687 data_->RemoveObserver(observer);
1688 }
1689
1690 void SyncManager::StopSyncingForShutdown(const base::Closure& callback) {
1691 data_->StopSyncingForShutdown(callback);
1692 }
1693
1694 void SyncManager::SyncInternal::StopSyncingForShutdown(
1695 const base::Closure& callback) {
1696 DVLOG(2) << "StopSyncingForShutdown";
1697 if (scheduler()) // May be null in tests.
1698 scheduler()->RequestStop(callback);
1699 else
1700 created_on_loop_->PostTask(FROM_HERE, callback);
1701
1702 if (connection_manager_.get())
1703 connection_manager_->TerminateAllIO();
1704 }
1705
1706 void SyncManager::ShutdownOnSyncThread() {
1707 DCHECK(thread_checker_.CalledOnValidThread());
1708 data_->ShutdownOnSyncThread();
1709 }
1710
1711 void SyncManager::SyncInternal::ShutdownOnSyncThread() {
1712 DCHECK(thread_checker_.CalledOnValidThread());
1713
1714 // Prevent any in-flight method calls from running. Also
1715 // invalidates |weak_handle_this_| and |change_observer_|.
1716 weak_ptr_factory_.InvalidateWeakPtrs();
1717 js_mutation_event_observer_.InvalidateWeakPtrs();
1718
1719 scheduler_.reset();
1720 session_context_.reset();
1721
1722 SetJsEventHandler(WeakHandle<JsEventHandler>());
1723 RemoveObserver(&js_sync_manager_observer_);
1724
1725 RemoveObserver(&debug_info_event_listener_);
1726
1727 if (sync_notifier_.get()) {
1728 sync_notifier_->RemoveObserver(this);
1729 }
1730 sync_notifier_.reset();
1731
1732 if (connection_manager_.get()) {
1733 connection_manager_->RemoveListener(this);
1734 }
1735 connection_manager_.reset();
1736
1737 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
1738 observing_ip_address_changes_ = false;
1739
1740 if (initialized_ && directory()) {
1741 {
1742 // Cryptographer should only be accessed while holding a
1743 // transaction.
1744 ReadTransaction trans(FROM_HERE, GetUserShare());
1745 trans.GetCryptographer()->RemoveObserver(this);
1746 }
1747 directory()->SaveChanges();
1748 }
1749
1750 share_.directory.reset();
1751
1752 change_delegate_ = NULL;
1753
1754 initialized_ = false;
1755
1756 // We reset these here, since only now we know they will not be
1757 // accessed from other threads (since we shut down everything).
1758 change_observer_.Reset();
1759 weak_handle_this_.Reset();
1760 }
1761
1762 void SyncManager::SyncInternal::OnIPAddressChanged() {
1763 DVLOG(1) << "IP address change detected";
1764 if (!observing_ip_address_changes_) {
1765 DVLOG(1) << "IP address change dropped.";
1766 return;
1767 }
1768
1769 OnIPAddressChangedImpl();
1770 }
1771
1772 void SyncManager::SyncInternal::OnIPAddressChangedImpl() {
1773 DCHECK(thread_checker_.CalledOnValidThread());
1774 if (scheduler())
1775 scheduler()->OnConnectionStatusChange();
1776 }
1777
1778 void SyncManager::SyncInternal::OnServerConnectionEvent(
1779 const ServerConnectionEvent& event) {
1780 DCHECK(thread_checker_.CalledOnValidThread());
1781 if (event.connection_code ==
1782 syncer::HttpResponse::SERVER_CONNECTION_OK) {
1783 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1784 OnConnectionStatusChange(CONNECTION_OK));
1785 }
1786
1787 if (event.connection_code == syncer::HttpResponse::SYNC_AUTH_ERROR) {
1788 observing_ip_address_changes_ = false;
1789 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1790 OnConnectionStatusChange(CONNECTION_AUTH_ERROR));
1791 }
1792
1793 if (event.connection_code ==
1794 syncer::HttpResponse::SYNC_SERVER_ERROR) {
1795 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1796 OnConnectionStatusChange(CONNECTION_SERVER_ERROR));
1797 }
1798 }
1799
1800 void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
1801 ModelTypeSet models_with_changes) {
1802 // This notification happens immediately after the transaction mutex is
1803 // released. This allows work to be performed without blocking other threads
1804 // from acquiring a transaction.
1805 if (!change_delegate_)
1806 return;
1807
1808 // Call commit.
1809 for (ModelTypeSet::Iterator it = models_with_changes.First();
1810 it.Good(); it.Inc()) {
1811 change_delegate_->OnChangesComplete(it.Get());
1812 change_observer_.Call(
1813 FROM_HERE, &SyncManager::ChangeObserver::OnChangesComplete, it.Get());
1814 }
1815 }
1816
1817 ModelTypeSet
1818 SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
1819 const ImmutableWriteTransactionInfo& write_transaction_info,
1820 syncable::BaseTransaction* trans) {
1821 // This notification happens immediately before a syncable WriteTransaction
1822 // falls out of scope. It happens while the channel mutex is still held,
1823 // and while the transaction mutex is held, so it cannot be re-entrant.
1824 if (!change_delegate_ || ChangeBuffersAreEmpty())
1825 return ModelTypeSet();
1826
1827 // This will continue the WriteTransaction using a read only wrapper.
1828 // This is the last chance for read to occur in the WriteTransaction
1829 // that's closing. This special ReadTransaction will not close the
1830 // underlying transaction.
1831 ReadTransaction read_trans(GetUserShare(), trans);
1832
1833 ModelTypeSet models_with_changes;
1834 for (int i = syncer::FIRST_REAL_MODEL_TYPE;
1835 i < syncer::MODEL_TYPE_COUNT; ++i) {
1836 const syncer::ModelType type = syncer::ModelTypeFromInt(i);
1837 if (change_buffers_[type].IsEmpty())
1838 continue;
1839
1840 ImmutableChangeRecordList ordered_changes;
1841 // TODO(akalin): Propagate up the error further (see
1842 // http://crbug.com/100907).
1843 CHECK(change_buffers_[type].GetAllChangesInTreeOrder(&read_trans,
1844 &ordered_changes));
1845 if (!ordered_changes.Get().empty()) {
1846 change_delegate_->
1847 OnChangesApplied(type, &read_trans, ordered_changes);
1848 change_observer_.Call(FROM_HERE,
1849 &SyncManager::ChangeObserver::OnChangesApplied,
1850 type, write_transaction_info.Get().id, ordered_changes);
1851 models_with_changes.Put(type);
1852 }
1853 change_buffers_[i].Clear();
1854 }
1855 return models_with_changes;
1856 }
1857
1858 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
1859 const ImmutableWriteTransactionInfo& write_transaction_info,
1860 syncable::BaseTransaction* trans) {
1861 if (!scheduler()) {
1862 return;
1863 }
1864
1865 // We have been notified about a user action changing a sync model.
1866 LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1867 "CALCULATE_CHANGES called with unapplied old changes.";
1868
1869 // The mutated model type, or UNSPECIFIED if nothing was mutated.
1870 syncer::ModelTypeSet mutated_model_types;
1871
1872 const syncable::ImmutableEntryKernelMutationMap& mutations =
1873 write_transaction_info.Get().mutations;
1874 for (syncable::EntryKernelMutationMap::const_iterator it =
1875 mutations.Get().begin(); it != mutations.Get().end(); ++it) {
1876 if (!it->second.mutated.ref(syncable::IS_UNSYNCED)) {
1877 continue;
1878 }
1879
1880 syncer::ModelType model_type =
1881 syncer::GetModelTypeFromSpecifics(
1882 it->second.mutated.ref(SPECIFICS));
1883 if (model_type < syncer::FIRST_REAL_MODEL_TYPE) {
1884 NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
1885 continue;
1886 }
1887
1888 // Found real mutation.
1889 if (model_type != syncer::UNSPECIFIED) {
1890 mutated_model_types.Put(model_type);
1891 }
1892 }
1893
1894 // Nudge if necessary.
1895 if (!mutated_model_types.Empty()) {
1896 if (weak_handle_this_.IsInitialized()) {
1897 weak_handle_this_.Call(FROM_HERE,
1898 &SyncInternal::RequestNudgeForDataTypes,
1899 FROM_HERE,
1900 mutated_model_types);
1901 } else {
1902 NOTREACHED();
1903 }
1904 }
1905 }
1906
1907 void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
1908 syncer::ModelType type, ChangeReorderBuffer* buffer,
1909 Cryptographer* cryptographer, const syncable::EntryKernel& original,
1910 bool existed_before, bool exists_now) {
1911 // If this is a deletion and the datatype was encrypted, we need to decrypt it
1912 // and attach it to the buffer.
1913 if (!exists_now && existed_before) {
1914 sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
1915 if (type == syncer::PASSWORDS) {
1916 // Passwords must use their own legacy ExtraPasswordChangeRecordData.
1917 scoped_ptr<sync_pb::PasswordSpecificsData> data(
1918 DecryptPasswordSpecifics(original_specifics, cryptographer));
1919 if (!data.get()) {
1920 NOTREACHED();
1921 return;
1922 }
1923 buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
1924 } else if (original_specifics.has_encrypted()) {
1925 // All other datatypes can just create a new unencrypted specifics and
1926 // attach it.
1927 const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
1928 if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
1929 NOTREACHED();
1930 return;
1931 }
1932 }
1933 buffer->SetSpecificsForId(id, original_specifics);
1934 }
1935 }
1936
1937 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
1938 const ImmutableWriteTransactionInfo& write_transaction_info,
1939 syncable::BaseTransaction* trans) {
1940 // We only expect one notification per sync step, so change_buffers_ should
1941 // contain no pending entries.
1942 LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1943 "CALCULATE_CHANGES called with unapplied old changes.";
1944
1945 Cryptographer* crypto = directory()->GetCryptographer(trans);
1946 const syncable::ImmutableEntryKernelMutationMap& mutations =
1947 write_transaction_info.Get().mutations;
1948 for (syncable::EntryKernelMutationMap::const_iterator it =
1949 mutations.Get().begin(); it != mutations.Get().end(); ++it) {
1950 bool existed_before = !it->second.original.ref(syncable::IS_DEL);
1951 bool exists_now = !it->second.mutated.ref(syncable::IS_DEL);
1952
1953 // Omit items that aren't associated with a model.
1954 syncer::ModelType type =
1955 syncer::GetModelTypeFromSpecifics(
1956 it->second.mutated.ref(SPECIFICS));
1957 if (type < syncer::FIRST_REAL_MODEL_TYPE)
1958 continue;
1959
1960 int64 handle = it->first;
1961 if (exists_now && !existed_before)
1962 change_buffers_[type].PushAddedItem(handle);
1963 else if (!exists_now && existed_before)
1964 change_buffers_[type].PushDeletedItem(handle);
1965 else if (exists_now && existed_before &&
1966 VisiblePropertiesDiffer(it->second, crypto)) {
1967 change_buffers_[type].PushUpdatedItem(
1968 handle, VisiblePositionsDiffer(it->second));
1969 }
1970
1971 SetExtraChangeRecordData(handle, type, &change_buffers_[type], crypto,
1972 it->second.original, existed_before, exists_now);
1973 }
1974 }
1975
1976 SyncStatus SyncManager::SyncInternal::GetStatus() {
1977 return allstatus_.status();
1978 }
1979
1980 void SyncManager::SyncInternal::RequestNudge(
1981 const tracked_objects::Location& location) {
1982 if (scheduler()) {
1983 scheduler()->ScheduleNudgeAsync(
1984 TimeDelta::FromMilliseconds(0), syncer::NUDGE_SOURCE_LOCAL,
1985 ModelTypeSet(), location);
1986 }
1987 }
1988
1989 TimeDelta SyncManager::SyncInternal::GetNudgeDelayTimeDelta(
1990 const ModelType& model_type) {
1991 return NudgeStrategy::GetNudgeDelayTimeDelta(model_type, this);
1992 }
1993
1994 void SyncManager::SyncInternal::RequestNudgeForDataTypes(
1995 const tracked_objects::Location& nudge_location,
1996 ModelTypeSet types) {
1997 if (!scheduler()) {
1998 NOTREACHED();
1999 return;
2000 }
2001
2002 debug_info_event_listener_.OnNudgeFromDatatype(types.First().Get());
2003
2004 // TODO(lipalani) : Calculate the nudge delay based on all types.
2005 base::TimeDelta nudge_delay = NudgeStrategy::GetNudgeDelayTimeDelta(
2006 types.First().Get(),
2007 this);
2008 scheduler()->ScheduleNudgeAsync(nudge_delay,
2009 syncer::NUDGE_SOURCE_LOCAL,
2010 types,
2011 nudge_location);
2012 }
2013
2014 void SyncManager::SyncInternal::OnSyncEngineEvent(
2015 const SyncEngineEvent& event) {
2016 DCHECK(thread_checker_.CalledOnValidThread());
2017 // Only send an event if this is due to a cycle ending and this cycle
2018 // concludes a canonical "sync" process; that is, based on what is known
2019 // locally we are "all happy" and up-to-date. There may be new changes on
2020 // the server, but we'll get them on a subsequent sync.
2021 //
2022 // Notifications are sent at the end of every sync cycle, regardless of
2023 // whether we should sync again.
2024 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
2025 {
2026 // Check to see if we need to notify the frontend that we have newly
2027 // encrypted types or that we require a passphrase.
2028 ReadTransaction trans(FROM_HERE, GetUserShare());
2029 Cryptographer* cryptographer = trans.GetCryptographer();
2030 // If we've completed a sync cycle and the cryptographer isn't ready
2031 // yet, prompt the user for a passphrase.
2032 if (cryptographer->has_pending_keys()) {
2033 DVLOG(1) << "OnPassPhraseRequired Sent";
2034 sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys();
2035 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2036 OnPassphraseRequired(syncer::REASON_DECRYPTION,
2037 pending_keys));
2038 } else if (!cryptographer->is_ready() &&
2039 event.snapshot.initial_sync_ended().Has(syncer::NIGORI)) {
2040 DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
2041 << "ready";
2042 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2043 OnPassphraseRequired(syncer::REASON_ENCRYPTION,
2044 sync_pb::EncryptedData()));
2045 }
2046
2047 NotifyCryptographerState(cryptographer);
2048 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
2049 }
2050
2051 if (!initialized_) {
2052 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
2053 << "initialized";
2054 return;
2055 }
2056
2057 if (!event.snapshot.has_more_to_sync()) {
2058 // To account for a nigori node arriving with stale/bad data, we ensure
2059 // that the nigori node is up to date at the end of each cycle.
2060 WriteTransaction trans(FROM_HERE, GetUserShare());
2061 WriteNode nigori_node(&trans);
2062 if (nigori_node.InitByTagLookup(kNigoriTag) ==
2063 syncer::BaseNode::INIT_OK) {
2064 Cryptographer* cryptographer = trans.GetCryptographer();
2065 UpdateNigoriEncryptionState(cryptographer, &nigori_node);
2066 }
2067
2068 DVLOG(1) << "Sending OnSyncCycleCompleted";
2069 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2070 OnSyncCycleCompleted(event.snapshot));
2071 }
2072
2073 // This is here for tests, which are still using p2p notifications.
2074 //
2075 // TODO(chron): Consider changing this back to track has_more_to_sync
2076 // only notify peers if a successful commit has occurred.
2077 bool is_notifiable_commit =
2078 (event.snapshot.model_neutral_state().num_successful_commits > 0);
2079 if (is_notifiable_commit) {
2080 if (sync_notifier_.get()) {
2081 const ModelTypeSet changed_types =
2082 syncer::ModelTypePayloadMapToEnumSet(
2083 event.snapshot.source().types);
2084 sync_notifier_->SendNotification(changed_types);
2085 } else {
2086 DVLOG(1) << "Not sending notification: sync_notifier_ is NULL";
2087 }
2088 }
2089 }
2090
2091 if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
2092 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2093 OnStopSyncingPermanently());
2094 return;
2095 }
2096
2097 if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
2098 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2099 OnUpdatedToken(event.updated_token));
2100 return;
2101 }
2102
2103 if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) {
2104 FOR_EACH_OBSERVER(
2105 SyncManager::Observer, observers_,
2106 OnActionableError(
2107 event.snapshot.model_neutral_state().sync_protocol_error));
2108 return;
2109 }
2110
2111 }
2112
2113 void SyncManager::SyncInternal::SetJsEventHandler(
2114 const WeakHandle<JsEventHandler>& event_handler) {
2115 js_event_handler_ = event_handler;
2116 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_);
2117 js_mutation_event_observer_.SetJsEventHandler(js_event_handler_);
2118 }
2119
2120 void SyncManager::SyncInternal::ProcessJsMessage(
2121 const std::string& name, const JsArgList& args,
2122 const WeakHandle<JsReplyHandler>& reply_handler) {
2123 if (!initialized_) {
2124 NOTREACHED();
2125 return;
2126 }
2127
2128 if (!reply_handler.IsInitialized()) {
2129 DVLOG(1) << "Uninitialized reply handler; dropping unknown message "
2130 << name << " with args " << args.ToString();
2131 return;
2132 }
2133
2134 JsMessageHandler js_message_handler = js_message_handlers_[name];
2135 if (js_message_handler.is_null()) {
2136 DVLOG(1) << "Dropping unknown message " << name
2137 << " with args " << args.ToString();
2138 return;
2139 }
2140
2141 reply_handler.Call(FROM_HERE,
2142 &JsReplyHandler::HandleJsReply,
2143 name, js_message_handler.Run(args));
2144 }
2145
2146 void SyncManager::SyncInternal::BindJsMessageHandler(
2147 const std::string& name,
2148 UnboundJsMessageHandler unbound_message_handler) {
2149 js_message_handlers_[name] =
2150 base::Bind(unbound_message_handler, base::Unretained(this));
2151 }
2152
2153 DictionaryValue* SyncManager::SyncInternal::NotificationInfoToValue(
2154 const NotificationInfoMap& notification_info) {
2155 DictionaryValue* value = new DictionaryValue();
2156
2157 for (NotificationInfoMap::const_iterator it = notification_info.begin();
2158 it != notification_info.end(); ++it) {
2159 const std::string& model_type_str =
2160 syncer::ModelTypeToString(it->first);
2161 value->Set(model_type_str, it->second.ToValue());
2162 }
2163
2164 return value;
2165 }
2166
2167 JsArgList SyncManager::SyncInternal::GetNotificationState(
2168 const JsArgList& args) {
2169 bool notifications_enabled = allstatus_.status().notifications_enabled;
2170 ListValue return_args;
2171 return_args.Append(Value::CreateBooleanValue(notifications_enabled));
2172 return JsArgList(&return_args);
2173 }
2174
2175 JsArgList SyncManager::SyncInternal::GetNotificationInfo(
2176 const JsArgList& args) {
2177 ListValue return_args;
2178 return_args.Append(NotificationInfoToValue(notification_info_map_));
2179 return JsArgList(&return_args);
2180 }
2181
2182 JsArgList SyncManager::SyncInternal::GetRootNodeDetails(
2183 const JsArgList& args) {
2184 ReadTransaction trans(FROM_HERE, GetUserShare());
2185 ReadNode root(&trans);
2186 root.InitByRootLookup();
2187 ListValue return_args;
2188 return_args.Append(root.GetDetailsAsValue());
2189 return JsArgList(&return_args);
2190 }
2191
2192 JsArgList SyncManager::SyncInternal::GetClientServerTraffic(
2193 const JsArgList& args) {
2194 ListValue return_args;
2195 ListValue* value = traffic_recorder_.ToValue();
2196 if (value != NULL)
2197 return_args.Append(value);
2198 return JsArgList(&return_args);
2199 }
2200
2201 namespace {
2202
2203 int64 GetId(const ListValue& ids, int i) {
2204 std::string id_str;
2205 if (!ids.GetString(i, &id_str)) {
2206 return kInvalidId;
2207 }
2208 int64 id = kInvalidId;
2209 if (!base::StringToInt64(id_str, &id)) {
2210 return kInvalidId;
2211 }
2212 return id;
2213 }
2214
2215 JsArgList GetNodeInfoById(const JsArgList& args,
2216 UserShare* user_share,
2217 DictionaryValue* (BaseNode::*info_getter)() const) {
2218 CHECK(info_getter);
2219 ListValue return_args;
2220 ListValue* node_summaries = new ListValue();
2221 return_args.Append(node_summaries);
2222 ListValue* id_list = NULL;
2223 ReadTransaction trans(FROM_HERE, user_share);
2224 if (args.Get().GetList(0, &id_list)) {
2225 CHECK(id_list);
2226 for (size_t i = 0; i < id_list->GetSize(); ++i) {
2227 int64 id = GetId(*id_list, i);
2228 if (id == kInvalidId) {
2229 continue;
2230 }
2231 ReadNode node(&trans);
2232 if (node.InitByIdLookup(id) != syncer::BaseNode::INIT_OK) {
2233 continue;
2234 }
2235 node_summaries->Append((node.*info_getter)());
2236 }
2237 }
2238 return JsArgList(&return_args);
2239 }
2240
2241 } // namespace
2242
2243 JsArgList SyncManager::SyncInternal::GetNodeSummariesById(
2244 const JsArgList& args) {
2245 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetSummaryAsValue);
2246 }
2247
2248 JsArgList SyncManager::SyncInternal::GetNodeDetailsById(
2249 const JsArgList& args) {
2250 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetDetailsAsValue);
2251 }
2252
2253 JsArgList SyncManager::SyncInternal::GetAllNodes(
2254 const JsArgList& args) {
2255 ListValue return_args;
2256 ListValue* result = new ListValue();
2257 return_args.Append(result);
2258
2259 ReadTransaction trans(FROM_HERE, GetUserShare());
2260 std::vector<const syncable::EntryKernel*> entry_kernels;
2261 trans.GetDirectory()->GetAllEntryKernels(trans.GetWrappedTrans(),
2262 &entry_kernels);
2263
2264 for (std::vector<const syncable::EntryKernel*>::const_iterator it =
2265 entry_kernels.begin(); it != entry_kernels.end(); ++it) {
2266 result->Append((*it)->ToValue());
2267 }
2268
2269 return JsArgList(&return_args);
2270 }
2271
2272 JsArgList SyncManager::SyncInternal::GetChildNodeIds(
2273 const JsArgList& args) {
2274 ListValue return_args;
2275 ListValue* child_ids = new ListValue();
2276 return_args.Append(child_ids);
2277 int64 id = GetId(args.Get(), 0);
2278 if (id != kInvalidId) {
2279 ReadTransaction trans(FROM_HERE, GetUserShare());
2280 syncable::Directory::ChildHandles child_handles;
2281 trans.GetDirectory()->GetChildHandlesByHandle(trans.GetWrappedTrans(),
2282 id, &child_handles);
2283 for (syncable::Directory::ChildHandles::const_iterator it =
2284 child_handles.begin(); it != child_handles.end(); ++it) {
2285 child_ids->Append(Value::CreateStringValue(
2286 base::Int64ToString(*it)));
2287 }
2288 }
2289 return JsArgList(&return_args);
2290 }
2291
2292 void SyncManager::SyncInternal::OnEncryptedTypesChanged(
2293 syncer::ModelTypeSet encrypted_types,
2294 bool encrypt_everything) {
2295 // NOTE: We're in a transaction.
2296 FOR_EACH_OBSERVER(
2297 SyncManager::Observer, observers_,
2298 OnEncryptedTypesChanged(encrypted_types, encrypt_everything));
2299 }
2300
2301 void SyncManager::SyncInternal::UpdateNotificationInfo(
2302 const syncer::ModelTypePayloadMap& type_payloads) {
2303 for (syncer::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
2304 it != type_payloads.end(); ++it) {
2305 NotificationInfo* info = &notification_info_map_[it->first];
2306 info->total_count++;
2307 info->payload = it->second;
2308 }
2309 }
2310
2311 void SyncManager::SyncInternal::OnNotificationsEnabled() {
2312 DVLOG(1) << "Notifications enabled";
2313 allstatus_.SetNotificationsEnabled(true);
2314 if (scheduler()) {
2315 scheduler()->set_notifications_enabled(true);
2316 }
2317 // TODO(akalin): Separate onNotificationStateChange into
2318 // enabled/disabled events.
2319 if (js_event_handler_.IsInitialized()) {
2320 DictionaryValue details;
2321 details.Set("enabled", Value::CreateBooleanValue(true));
2322 js_event_handler_.Call(FROM_HERE,
2323 &JsEventHandler::HandleJsEvent,
2324 "onNotificationStateChange",
2325 JsEventDetails(&details));
2326 }
2327 }
2328
2329 void SyncManager::SyncInternal::OnNotificationsDisabled(
2330 syncer::NotificationsDisabledReason reason) {
2331 DVLOG(1) << "Notifications disabled with reason "
2332 << syncer::NotificationsDisabledReasonToString(reason);
2333 allstatus_.SetNotificationsEnabled(false);
2334 if (scheduler()) {
2335 scheduler()->set_notifications_enabled(false);
2336 }
2337 if (js_event_handler_.IsInitialized()) {
2338 DictionaryValue details;
2339 details.Set("enabled", Value::CreateBooleanValue(false));
2340 js_event_handler_.Call(FROM_HERE,
2341 &JsEventHandler::HandleJsEvent,
2342 "onNotificationStateChange",
2343 JsEventDetails(&details));
2344 }
2345 // TODO(akalin): Treat a CREDENTIALS_REJECTED state as an auth
2346 // error.
2347 }
2348
2349 void SyncManager::SyncInternal::OnIncomingNotification(
2350 const syncer::ModelTypePayloadMap& type_payloads,
2351 syncer::IncomingNotificationSource source) {
2352 DCHECK(thread_checker_.CalledOnValidThread());
2353 if (source == syncer::LOCAL_NOTIFICATION) {
2354 if (scheduler()) {
2355 scheduler()->ScheduleNudgeWithPayloadsAsync(
2356 TimeDelta::FromMilliseconds(kSyncRefreshDelayMsec),
2357 syncer::NUDGE_SOURCE_LOCAL_REFRESH,
2358 type_payloads, FROM_HERE);
2359 }
2360 } else if (!type_payloads.empty()) {
2361 if (scheduler()) {
2362 scheduler()->ScheduleNudgeWithPayloadsAsync(
2363 TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
2364 syncer::NUDGE_SOURCE_NOTIFICATION,
2365 type_payloads, FROM_HERE);
2366 }
2367 allstatus_.IncrementNotificationsReceived();
2368 UpdateNotificationInfo(type_payloads);
2369 debug_info_event_listener_.OnIncomingNotification(type_payloads);
2370 } else {
2371 LOG(WARNING) << "Sync received notification without any type information.";
2372 }
2373
2374 if (js_event_handler_.IsInitialized()) {
2375 DictionaryValue details;
2376 ListValue* changed_types = new ListValue();
2377 details.Set("changedTypes", changed_types);
2378 for (syncer::ModelTypePayloadMap::const_iterator
2379 it = type_payloads.begin();
2380 it != type_payloads.end(); ++it) {
2381 const std::string& model_type_str =
2382 syncer::ModelTypeToString(it->first);
2383 changed_types->Append(Value::CreateStringValue(model_type_str));
2384 }
2385 details.SetString("source", (source == syncer::LOCAL_NOTIFICATION) ?
2386 "LOCAL_NOTIFICATION" : "REMOTE_NOTIFICATION");
2387 js_event_handler_.Call(FROM_HERE,
2388 &JsEventHandler::HandleJsEvent,
2389 "onIncomingNotification",
2390 JsEventDetails(&details));
2391 }
2392 }
2393
2394 void SyncManager::SyncInternal::AddObserver(
2395 SyncManager::Observer* observer) {
2396 observers_.AddObserver(observer);
2397 }
2398
2399 void SyncManager::SyncInternal::RemoveObserver(
2400 SyncManager::Observer* observer) {
2401 observers_.RemoveObserver(observer);
2402 }
2403
2404 void SyncManager::SyncInternal::SetSyncSchedulerForTest(
2405 scoped_ptr<SyncScheduler> sync_scheduler) {
2406 scheduler_ = sync_scheduler.Pass();
2407 }
2408
2409 SyncStatus SyncManager::GetDetailedStatus() const {
2410 return data_->GetStatus();
2411 }
2412
2413 void SyncManager::SaveChanges() {
2414 DCHECK(thread_checker_.CalledOnValidThread());
2415 data_->SaveChanges();
2416 }
2417
2418 void SyncManager::SyncInternal::SaveChanges() {
2419 directory()->SaveChanges();
2420 }
2421
2422 UserShare* SyncManager::GetUserShare() const {
2423 return data_->GetUserShare();
2424 }
2425
2426 void SyncManager::RefreshNigori(const std::string& chrome_version,
2427 const base::Closure& done_callback) {
2428 DCHECK(thread_checker_.CalledOnValidThread());
2429 data_->UpdateCryptographerAndNigori(
2430 chrome_version,
2431 done_callback);
2432 }
2433
2434 TimeDelta SyncManager::GetNudgeDelayTimeDelta(
2435 const ModelType& model_type) {
2436 return data_->GetNudgeDelayTimeDelta(model_type);
2437 }
2438
2439 void SyncManager::SetSyncSchedulerForTest(scoped_ptr<SyncScheduler> scheduler) {
2440 data_->SetSyncSchedulerForTest(scheduler.Pass());
2441 }
2442
2443 syncer::ModelTypeSet SyncManager::GetEncryptedDataTypesForTest() const {
2444 ReadTransaction trans(FROM_HERE, GetUserShare());
2445 return GetEncryptedTypes(&trans);
2446 }
2447
2448 bool SyncManager::ReceivedExperiment(syncer::Experiments* experiments)
2449 const {
2450 ReadTransaction trans(FROM_HERE, GetUserShare());
2451 ReadNode node(&trans);
2452 if (node.InitByTagLookup(kNigoriTag) != syncer::BaseNode::INIT_OK) {
2453 DVLOG(1) << "Couldn't find Nigori node.";
2454 return false;
2455 }
2456 bool found_experiment = false;
2457 if (node.GetNigoriSpecifics().sync_tab_favicons()) {
2458 experiments->sync_tab_favicons = true;
2459 found_experiment = true;
2460 }
2461 return found_experiment;
2462 }
2463
2464 bool SyncManager::HasUnsyncedItems() const {
2465 syncer::ReadTransaction trans(FROM_HERE, GetUserShare());
2466 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
2467 }
2468
2469 void SyncManager::SimulateEnableNotificationsForTest() {
2470 DCHECK(thread_checker_.CalledOnValidThread());
2471 data_->OnNotificationsEnabled();
2472 }
2473
2474 void SyncManager::SimulateDisableNotificationsForTest(int reason) {
2475 DCHECK(thread_checker_.CalledOnValidThread());
2476 data_->OnNotificationsDisabled(
2477 static_cast<syncer::NotificationsDisabledReason>(reason));
2478 }
2479
2480 void SyncManager::TriggerOnIncomingNotificationForTest(
2481 ModelTypeSet model_types) {
2482 DCHECK(thread_checker_.CalledOnValidThread());
2483 syncer::ModelTypePayloadMap model_types_with_payloads =
2484 syncer::ModelTypePayloadMapFromEnumSet(model_types,
2485 std::string());
2486
2487 data_->OnIncomingNotification(model_types_with_payloads,
2488 syncer::REMOTE_NOTIFICATION);
2489 }
2490
2491 const char* ConnectionStatusToString(ConnectionStatus status) {
2492 switch (status) {
2493 case CONNECTION_OK:
2494 return "CONNECTION_OK";
2495 case CONNECTION_AUTH_ERROR:
2496 return "CONNECTION_AUTH_ERROR";
2497 case CONNECTION_SERVER_ERROR:
2498 return "CONNECTION_SERVER_ERROR";
2499 default:
2500 NOTREACHED();
2501 return "INVALID_CONNECTION_STATUS";
2502 }
2503 }
2504
2505 // Helper function that converts a PassphraseRequiredReason value to a string.
2506 const char* PassphraseRequiredReasonToString(
2507 PassphraseRequiredReason reason) {
2508 switch (reason) {
2509 case REASON_PASSPHRASE_NOT_REQUIRED:
2510 return "REASON_PASSPHRASE_NOT_REQUIRED";
2511 case REASON_ENCRYPTION:
2512 return "REASON_ENCRYPTION";
2513 case REASON_DECRYPTION:
2514 return "REASON_DECRYPTION";
2515 default:
2516 NOTREACHED();
2517 return "INVALID_REASON";
2518 }
2519 }
2520
2521 // Helper function to determine if initial sync had ended for types.
2522 bool InitialSyncEndedForTypes(syncer::ModelTypeSet types,
2523 syncer::UserShare* share) {
2524 for (syncer::ModelTypeSet::Iterator i = types.First();
2525 i.Good(); i.Inc()) {
2526 if (!share->directory->initial_sync_ended_for_type(i.Get()))
2527 return false;
2528 }
2529 return true;
2530 }
2531
2532 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698