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

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

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

Powered by Google App Engine
This is Rietveld 408576698