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

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: Fix Win update errors 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) == sync_api::BaseNode::INIT_OK) {
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) != sync_api::BaseNode::INIT_OK) {
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) != sync_api::BaseNode::INIT_OK) {
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) != sync_api::BaseNode::INIT_OK) {
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) != sync_api::BaseNode::INIT_OK) {
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) != sync_api::BaseNode::INIT_OK) {
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) != sync_api::BaseNode::INIT_OK) {
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) != sync_api::BaseNode::INIT_OK) {
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 sync_api::BaseNode::INIT_OK) {
1690 int64 child_id = passwords_root.GetFirstChildId();
1691 while (child_id != kInvalidId) {
1692 WriteNode child(trans);
1693 if (child.InitByIdLookup(child_id) != sync_api::BaseNode::INIT_OK) {
1694 NOTREACHED();
1695 return;
1696 }
1697 child.SetPasswordSpecifics(child.GetPasswordSpecifics());
1698 child_id = child.GetSuccessorId();
1699 }
1700 }
1701 }
1702
1703 // NOTE: We notify from within a transaction.
1704 FOR_EACH_OBSERVER(SyncManager::Observer, observers_, OnEncryptionComplete());
1705 }
1706
1707 SyncManager::~SyncManager() {
1708 DCHECK(thread_checker_.CalledOnValidThread());
1709 delete data_;
1710 }
1711
1712 void SyncManager::AddObserver(Observer* observer) {
1713 DCHECK(thread_checker_.CalledOnValidThread());
1714 data_->AddObserver(observer);
1715 }
1716
1717 void SyncManager::RemoveObserver(Observer* observer) {
1718 DCHECK(thread_checker_.CalledOnValidThread());
1719 data_->RemoveObserver(observer);
1720 }
1721
1722 void SyncManager::StopSyncingForShutdown(const base::Closure& callback) {
1723 data_->StopSyncingForShutdown(callback);
1724 }
1725
1726 void SyncManager::SyncInternal::StopSyncingForShutdown(
1727 const base::Closure& callback) {
1728 DVLOG(2) << "StopSyncingForShutdown";
1729 if (scheduler()) // May be null in tests.
1730 scheduler()->RequestStop(callback);
1731 else
1732 created_on_loop_->PostTask(FROM_HERE, callback);
1733
1734 if (connection_manager_.get())
1735 connection_manager_->TerminateAllIO();
1736 }
1737
1738 void SyncManager::ShutdownOnSyncThread() {
1739 DCHECK(thread_checker_.CalledOnValidThread());
1740 data_->ShutdownOnSyncThread();
1741 }
1742
1743 void SyncManager::SyncInternal::ShutdownOnSyncThread() {
1744 DCHECK(thread_checker_.CalledOnValidThread());
1745
1746 // Prevent any in-flight method calls from running. Also
1747 // invalidates |weak_handle_this_| and |change_observer_|.
1748 weak_ptr_factory_.InvalidateWeakPtrs();
1749 js_mutation_event_observer_.InvalidateWeakPtrs();
1750
1751 scheduler_.reset();
1752
1753 SetJsEventHandler(WeakHandle<JsEventHandler>());
1754 RemoveObserver(&js_sync_manager_observer_);
1755
1756 RemoveObserver(&debug_info_event_listener_);
1757
1758 if (sync_notifier_.get()) {
1759 sync_notifier_->RemoveObserver(this);
1760 }
1761 sync_notifier_.reset();
1762
1763 if (connection_manager_.get()) {
1764 connection_manager_->RemoveListener(this);
1765 }
1766 connection_manager_.reset();
1767
1768 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
1769 observing_ip_address_changes_ = false;
1770
1771 if (initialized_ && directory()) {
1772 {
1773 // Cryptographer should only be accessed while holding a
1774 // transaction.
1775 ReadTransaction trans(FROM_HERE, GetUserShare());
1776 trans.GetCryptographer()->RemoveObserver(this);
1777 }
1778 directory()->SaveChanges();
1779 }
1780
1781 share_.directory.reset();
1782
1783 change_delegate_ = NULL;
1784 registrar_ = NULL;
1785
1786 initialized_ = false;
1787
1788 // We reset these here, since only now we know they will not be
1789 // accessed from other threads (since we shut down everything).
1790 change_observer_.Reset();
1791 weak_handle_this_.Reset();
1792 }
1793
1794 void SyncManager::SyncInternal::OnIPAddressChanged() {
1795 DVLOG(1) << "IP address change detected";
1796 if (!observing_ip_address_changes_) {
1797 DVLOG(1) << "IP address change dropped.";
1798 return;
1799 }
1800
1801 OnIPAddressChangedImpl();
1802 }
1803
1804 void SyncManager::SyncInternal::OnIPAddressChangedImpl() {
1805 DCHECK(thread_checker_.CalledOnValidThread());
1806 if (scheduler())
1807 scheduler()->OnConnectionStatusChange();
1808 }
1809
1810 void SyncManager::SyncInternal::OnServerConnectionEvent(
1811 const ServerConnectionEvent& event) {
1812 DCHECK(thread_checker_.CalledOnValidThread());
1813 if (event.connection_code ==
1814 browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
1815 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1816 OnConnectionStatusChange(CONNECTION_OK));
1817 }
1818
1819 if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
1820 observing_ip_address_changes_ = false;
1821 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1822 OnConnectionStatusChange(CONNECTION_AUTH_ERROR));
1823 }
1824
1825 if (event.connection_code ==
1826 browser_sync::HttpResponse::SYNC_SERVER_ERROR) {
1827 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1828 OnConnectionStatusChange(CONNECTION_SERVER_ERROR));
1829 }
1830 }
1831
1832 void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
1833 ModelTypeSet models_with_changes) {
1834 // This notification happens immediately after the transaction mutex is
1835 // released. This allows work to be performed without blocking other threads
1836 // from acquiring a transaction.
1837 if (!change_delegate_)
1838 return;
1839
1840 // Call commit.
1841 for (ModelTypeSet::Iterator it = models_with_changes.First();
1842 it.Good(); it.Inc()) {
1843 change_delegate_->OnChangesComplete(it.Get());
1844 change_observer_.Call(
1845 FROM_HERE, &SyncManager::ChangeObserver::OnChangesComplete, it.Get());
1846 }
1847 }
1848
1849 ModelTypeSet
1850 SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
1851 const ImmutableWriteTransactionInfo& write_transaction_info,
1852 syncable::BaseTransaction* trans) {
1853 // This notification happens immediately before a syncable WriteTransaction
1854 // falls out of scope. It happens while the channel mutex is still held,
1855 // and while the transaction mutex is held, so it cannot be re-entrant.
1856 if (!change_delegate_ || ChangeBuffersAreEmpty())
1857 return ModelTypeSet();
1858
1859 // This will continue the WriteTransaction using a read only wrapper.
1860 // This is the last chance for read to occur in the WriteTransaction
1861 // that's closing. This special ReadTransaction will not close the
1862 // underlying transaction.
1863 ReadTransaction read_trans(GetUserShare(), trans);
1864
1865 ModelTypeSet models_with_changes;
1866 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
1867 i < syncable::MODEL_TYPE_COUNT; ++i) {
1868 const syncable::ModelType type = syncable::ModelTypeFromInt(i);
1869 if (change_buffers_[type].IsEmpty())
1870 continue;
1871
1872 ImmutableChangeRecordList ordered_changes;
1873 // TODO(akalin): Propagate up the error further (see
1874 // http://crbug.com/100907).
1875 CHECK(change_buffers_[type].GetAllChangesInTreeOrder(&read_trans,
1876 &ordered_changes));
1877 if (!ordered_changes.Get().empty()) {
1878 change_delegate_->
1879 OnChangesApplied(type, &read_trans, ordered_changes);
1880 change_observer_.Call(FROM_HERE,
1881 &SyncManager::ChangeObserver::OnChangesApplied,
1882 type, write_transaction_info.Get().id, ordered_changes);
1883 models_with_changes.Put(type);
1884 }
1885 change_buffers_[i].Clear();
1886 }
1887 return models_with_changes;
1888 }
1889
1890 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
1891 const ImmutableWriteTransactionInfo& write_transaction_info,
1892 syncable::BaseTransaction* trans) {
1893 if (!scheduler()) {
1894 return;
1895 }
1896
1897 // We have been notified about a user action changing a sync model.
1898 LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1899 "CALCULATE_CHANGES called with unapplied old changes.";
1900
1901 // The mutated model type, or UNSPECIFIED if nothing was mutated.
1902 syncable::ModelTypeSet mutated_model_types;
1903
1904 const syncable::ImmutableEntryKernelMutationMap& mutations =
1905 write_transaction_info.Get().mutations;
1906 for (syncable::EntryKernelMutationMap::const_iterator it =
1907 mutations.Get().begin(); it != mutations.Get().end(); ++it) {
1908 if (!it->second.mutated.ref(syncable::IS_UNSYNCED)) {
1909 continue;
1910 }
1911
1912 syncable::ModelType model_type =
1913 syncable::GetModelTypeFromSpecifics(
1914 it->second.mutated.ref(SPECIFICS));
1915 if (model_type < syncable::FIRST_REAL_MODEL_TYPE) {
1916 NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
1917 continue;
1918 }
1919
1920 // Found real mutation.
1921 if (model_type != syncable::UNSPECIFIED) {
1922 mutated_model_types.Put(model_type);
1923 }
1924 }
1925
1926 // Nudge if necessary.
1927 if (!mutated_model_types.Empty()) {
1928 if (weak_handle_this_.IsInitialized()) {
1929 weak_handle_this_.Call(FROM_HERE,
1930 &SyncInternal::RequestNudgeForDataTypes,
1931 FROM_HERE,
1932 mutated_model_types);
1933 } else {
1934 NOTREACHED();
1935 }
1936 }
1937 }
1938
1939 void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
1940 syncable::ModelType type, ChangeReorderBuffer* buffer,
1941 Cryptographer* cryptographer, const syncable::EntryKernel& original,
1942 bool existed_before, bool exists_now) {
1943 // If this is a deletion and the datatype was encrypted, we need to decrypt it
1944 // and attach it to the buffer.
1945 if (!exists_now && existed_before) {
1946 sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
1947 if (type == syncable::PASSWORDS) {
1948 // Passwords must use their own legacy ExtraPasswordChangeRecordData.
1949 scoped_ptr<sync_pb::PasswordSpecificsData> data(
1950 DecryptPasswordSpecifics(original_specifics, cryptographer));
1951 if (!data.get()) {
1952 NOTREACHED();
1953 return;
1954 }
1955 buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
1956 } else if (original_specifics.has_encrypted()) {
1957 // All other datatypes can just create a new unencrypted specifics and
1958 // attach it.
1959 const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
1960 if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
1961 NOTREACHED();
1962 return;
1963 }
1964 }
1965 buffer->SetSpecificsForId(id, original_specifics);
1966 }
1967 }
1968
1969 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
1970 const ImmutableWriteTransactionInfo& write_transaction_info,
1971 syncable::BaseTransaction* trans) {
1972 // We only expect one notification per sync step, so change_buffers_ should
1973 // contain no pending entries.
1974 LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1975 "CALCULATE_CHANGES called with unapplied old changes.";
1976
1977 Cryptographer* crypto = directory()->GetCryptographer(trans);
1978 const syncable::ImmutableEntryKernelMutationMap& mutations =
1979 write_transaction_info.Get().mutations;
1980 for (syncable::EntryKernelMutationMap::const_iterator it =
1981 mutations.Get().begin(); it != mutations.Get().end(); ++it) {
1982 bool existed_before = !it->second.original.ref(syncable::IS_DEL);
1983 bool exists_now = !it->second.mutated.ref(syncable::IS_DEL);
1984
1985 // Omit items that aren't associated with a model.
1986 syncable::ModelType type =
1987 syncable::GetModelTypeFromSpecifics(
1988 it->second.mutated.ref(SPECIFICS));
1989 if (type < syncable::FIRST_REAL_MODEL_TYPE)
1990 continue;
1991
1992 int64 handle = it->first;
1993 if (exists_now && !existed_before)
1994 change_buffers_[type].PushAddedItem(handle);
1995 else if (!exists_now && existed_before)
1996 change_buffers_[type].PushDeletedItem(handle);
1997 else if (exists_now && existed_before &&
1998 VisiblePropertiesDiffer(it->second, crypto)) {
1999 change_buffers_[type].PushUpdatedItem(
2000 handle, VisiblePositionsDiffer(it->second));
2001 }
2002
2003 SetExtraChangeRecordData(handle, type, &change_buffers_[type], crypto,
2004 it->second.original, existed_before, exists_now);
2005 }
2006 }
2007
2008 SyncManager::Status SyncManager::SyncInternal::GetStatus() {
2009 return allstatus_.status();
2010 }
2011
2012 void SyncManager::SyncInternal::RequestNudge(
2013 const tracked_objects::Location& location) {
2014 if (scheduler()) {
2015 scheduler()->ScheduleNudge(
2016 TimeDelta::FromMilliseconds(0), browser_sync::NUDGE_SOURCE_LOCAL,
2017 ModelTypeSet(), location);
2018 }
2019 }
2020
2021 TimeDelta SyncManager::SyncInternal::GetNudgeDelayTimeDelta(
2022 const ModelType& model_type) {
2023 return NudgeStrategy::GetNudgeDelayTimeDelta(model_type, this);
2024 }
2025
2026 void SyncManager::SyncInternal::RequestNudgeForDataTypes(
2027 const tracked_objects::Location& nudge_location,
2028 ModelTypeSet types) {
2029 if (!scheduler()) {
2030 NOTREACHED();
2031 return;
2032 }
2033
2034 debug_info_event_listener_.OnNudgeFromDatatype(types.First().Get());
2035
2036 // TODO(lipalani) : Calculate the nudge delay based on all types.
2037 base::TimeDelta nudge_delay = NudgeStrategy::GetNudgeDelayTimeDelta(
2038 types.First().Get(),
2039 this);
2040 scheduler()->ScheduleNudge(nudge_delay,
2041 browser_sync::NUDGE_SOURCE_LOCAL,
2042 types,
2043 nudge_location);
2044 }
2045
2046 void SyncManager::SyncInternal::OnSyncEngineEvent(
2047 const SyncEngineEvent& event) {
2048 DCHECK(thread_checker_.CalledOnValidThread());
2049 // Only send an event if this is due to a cycle ending and this cycle
2050 // concludes a canonical "sync" process; that is, based on what is known
2051 // locally we are "all happy" and up-to-date. There may be new changes on
2052 // the server, but we'll get them on a subsequent sync.
2053 //
2054 // Notifications are sent at the end of every sync cycle, regardless of
2055 // whether we should sync again.
2056 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
2057 ModelSafeRoutingInfo enabled_types;
2058 registrar_->GetModelSafeRoutingInfo(&enabled_types);
2059 {
2060 // Check to see if we need to notify the frontend that we have newly
2061 // encrypted types or that we require a passphrase.
2062 ReadTransaction trans(FROM_HERE, GetUserShare());
2063 Cryptographer* cryptographer = trans.GetCryptographer();
2064 // If we've completed a sync cycle and the cryptographer isn't ready
2065 // yet, prompt the user for a passphrase.
2066 if (cryptographer->has_pending_keys()) {
2067 DVLOG(1) << "OnPassPhraseRequired Sent";
2068 sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys();
2069 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2070 OnPassphraseRequired(sync_api::REASON_DECRYPTION,
2071 pending_keys));
2072 } else if (!cryptographer->is_ready() &&
2073 event.snapshot->initial_sync_ended.Has(syncable::NIGORI)) {
2074 DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
2075 << "ready";
2076 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2077 OnPassphraseRequired(sync_api::REASON_ENCRYPTION,
2078 sync_pb::EncryptedData()));
2079 }
2080
2081 NotifyCryptographerState(cryptographer);
2082 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
2083 }
2084
2085 if (!initialized_) {
2086 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
2087 << "initialized";
2088 return;
2089 }
2090
2091 if (!event.snapshot->has_more_to_sync) {
2092 // To account for a nigori node arriving with stale/bad data, we ensure
2093 // that the nigori node is up to date at the end of each cycle.
2094 WriteTransaction trans(FROM_HERE, GetUserShare());
2095 WriteNode nigori_node(&trans);
2096 if (nigori_node.InitByTagLookup(kNigoriTag) ==
2097 sync_api::BaseNode::INIT_OK) {
2098 Cryptographer* cryptographer = trans.GetCryptographer();
2099 UpdateNigoriEncryptionState(cryptographer, &nigori_node);
2100 }
2101
2102 DVLOG(1) << "Sending OnSyncCycleCompleted";
2103 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2104 OnSyncCycleCompleted(event.snapshot));
2105 }
2106
2107 // This is here for tests, which are still using p2p notifications.
2108 //
2109 // TODO(chron): Consider changing this back to track has_more_to_sync
2110 // only notify peers if a successful commit has occurred.
2111 bool is_notifiable_commit =
2112 (event.snapshot->syncer_status.num_successful_commits > 0);
2113 if (is_notifiable_commit) {
2114 if (sync_notifier_.get()) {
2115 const ModelTypeSet changed_types =
2116 syncable::ModelTypePayloadMapToEnumSet(
2117 event.snapshot->source.types);
2118 sync_notifier_->SendNotification(changed_types);
2119 } else {
2120 DVLOG(1) << "Not sending notification: sync_notifier_ is NULL";
2121 }
2122 }
2123 }
2124
2125 if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
2126 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2127 OnStopSyncingPermanently());
2128 return;
2129 }
2130
2131 if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
2132 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2133 OnClearServerDataSucceeded());
2134 return;
2135 }
2136
2137 if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
2138 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2139 OnClearServerDataFailed());
2140 return;
2141 }
2142
2143 if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
2144 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2145 OnUpdatedToken(event.updated_token));
2146 return;
2147 }
2148
2149 if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) {
2150 FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2151 OnActionableError(
2152 event.snapshot->errors.sync_protocol_error));
2153 return;
2154 }
2155
2156 }
2157
2158 void SyncManager::SyncInternal::SetJsEventHandler(
2159 const WeakHandle<JsEventHandler>& event_handler) {
2160 js_event_handler_ = event_handler;
2161 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_);
2162 js_mutation_event_observer_.SetJsEventHandler(js_event_handler_);
2163 }
2164
2165 void SyncManager::SyncInternal::ProcessJsMessage(
2166 const std::string& name, const JsArgList& args,
2167 const WeakHandle<JsReplyHandler>& reply_handler) {
2168 if (!initialized_) {
2169 NOTREACHED();
2170 return;
2171 }
2172
2173 if (!reply_handler.IsInitialized()) {
2174 DVLOG(1) << "Uninitialized reply handler; dropping unknown message "
2175 << name << " with args " << args.ToString();
2176 return;
2177 }
2178
2179 JsMessageHandler js_message_handler = js_message_handlers_[name];
2180 if (js_message_handler.is_null()) {
2181 DVLOG(1) << "Dropping unknown message " << name
2182 << " with args " << args.ToString();
2183 return;
2184 }
2185
2186 reply_handler.Call(FROM_HERE,
2187 &JsReplyHandler::HandleJsReply,
2188 name, js_message_handler.Run(args));
2189 }
2190
2191 void SyncManager::SyncInternal::BindJsMessageHandler(
2192 const std::string& name,
2193 UnboundJsMessageHandler unbound_message_handler) {
2194 js_message_handlers_[name] =
2195 base::Bind(unbound_message_handler, base::Unretained(this));
2196 }
2197
2198 DictionaryValue* SyncManager::SyncInternal::NotificationInfoToValue(
2199 const NotificationInfoMap& notification_info) {
2200 DictionaryValue* value = new DictionaryValue();
2201
2202 for (NotificationInfoMap::const_iterator it = notification_info.begin();
2203 it != notification_info.end(); ++it) {
2204 const std::string& model_type_str =
2205 syncable::ModelTypeToString(it->first);
2206 value->Set(model_type_str, it->second.ToValue());
2207 }
2208
2209 return value;
2210 }
2211
2212 JsArgList SyncManager::SyncInternal::GetNotificationState(
2213 const JsArgList& args) {
2214 bool notifications_enabled = allstatus_.status().notifications_enabled;
2215 ListValue return_args;
2216 return_args.Append(Value::CreateBooleanValue(notifications_enabled));
2217 return JsArgList(&return_args);
2218 }
2219
2220 JsArgList SyncManager::SyncInternal::GetNotificationInfo(
2221 const JsArgList& args) {
2222 ListValue return_args;
2223 return_args.Append(NotificationInfoToValue(notification_info_map_));
2224 return JsArgList(&return_args);
2225 }
2226
2227 JsArgList SyncManager::SyncInternal::GetRootNodeDetails(
2228 const JsArgList& args) {
2229 ReadTransaction trans(FROM_HERE, GetUserShare());
2230 ReadNode root(&trans);
2231 root.InitByRootLookup();
2232 ListValue return_args;
2233 return_args.Append(root.GetDetailsAsValue());
2234 return JsArgList(&return_args);
2235 }
2236
2237 JsArgList SyncManager::SyncInternal::GetClientServerTraffic(
2238 const JsArgList& args) {
2239 ListValue return_args;
2240 ListValue* value = traffic_recorder_.ToValue();
2241 if (value != NULL)
2242 return_args.Append(value);
2243 return JsArgList(&return_args);
2244 }
2245
2246 namespace {
2247
2248 int64 GetId(const ListValue& ids, int i) {
2249 std::string id_str;
2250 if (!ids.GetString(i, &id_str)) {
2251 return kInvalidId;
2252 }
2253 int64 id = kInvalidId;
2254 if (!base::StringToInt64(id_str, &id)) {
2255 return kInvalidId;
2256 }
2257 return id;
2258 }
2259
2260 JsArgList GetNodeInfoById(const JsArgList& args,
2261 UserShare* user_share,
2262 DictionaryValue* (BaseNode::*info_getter)() const) {
2263 CHECK(info_getter);
2264 ListValue return_args;
2265 ListValue* node_summaries = new ListValue();
2266 return_args.Append(node_summaries);
2267 ListValue* id_list = NULL;
2268 ReadTransaction trans(FROM_HERE, user_share);
2269 if (args.Get().GetList(0, &id_list)) {
2270 CHECK(id_list);
2271 for (size_t i = 0; i < id_list->GetSize(); ++i) {
2272 int64 id = GetId(*id_list, i);
2273 if (id == kInvalidId) {
2274 continue;
2275 }
2276 ReadNode node(&trans);
2277 if (node.InitByIdLookup(id) != sync_api::BaseNode::INIT_OK) {
2278 continue;
2279 }
2280 node_summaries->Append((node.*info_getter)());
2281 }
2282 }
2283 return JsArgList(&return_args);
2284 }
2285
2286 } // namespace
2287
2288 JsArgList SyncManager::SyncInternal::GetNodeSummariesById(
2289 const JsArgList& args) {
2290 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetSummaryAsValue);
2291 }
2292
2293 JsArgList SyncManager::SyncInternal::GetNodeDetailsById(
2294 const JsArgList& args) {
2295 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetDetailsAsValue);
2296 }
2297
2298 JsArgList SyncManager::SyncInternal::GetAllNodes(
2299 const JsArgList& args) {
2300 ListValue return_args;
2301 ListValue* result = new ListValue();
2302 return_args.Append(result);
2303
2304 ReadTransaction trans(FROM_HERE, GetUserShare());
2305 std::vector<const syncable::EntryKernel*> entry_kernels;
2306 trans.GetDirectory()->GetAllEntryKernels(trans.GetWrappedTrans(),
2307 &entry_kernels);
2308
2309 for (std::vector<const syncable::EntryKernel*>::const_iterator it =
2310 entry_kernels.begin(); it != entry_kernels.end(); ++it) {
2311 result->Append((*it)->ToValue());
2312 }
2313
2314 return JsArgList(&return_args);
2315 }
2316
2317 JsArgList SyncManager::SyncInternal::GetChildNodeIds(
2318 const JsArgList& args) {
2319 ListValue return_args;
2320 ListValue* child_ids = new ListValue();
2321 return_args.Append(child_ids);
2322 int64 id = GetId(args.Get(), 0);
2323 if (id != kInvalidId) {
2324 ReadTransaction trans(FROM_HERE, GetUserShare());
2325 syncable::Directory::ChildHandles child_handles;
2326 trans.GetDirectory()->GetChildHandlesByHandle(trans.GetWrappedTrans(),
2327 id, &child_handles);
2328 for (syncable::Directory::ChildHandles::const_iterator it =
2329 child_handles.begin(); it != child_handles.end(); ++it) {
2330 child_ids->Append(Value::CreateStringValue(
2331 base::Int64ToString(*it)));
2332 }
2333 }
2334 return JsArgList(&return_args);
2335 }
2336
2337 void SyncManager::SyncInternal::OnEncryptedTypesChanged(
2338 syncable::ModelTypeSet encrypted_types,
2339 bool encrypt_everything) {
2340 // NOTE: We're in a transaction.
2341 FOR_EACH_OBSERVER(
2342 SyncManager::Observer, observers_,
2343 OnEncryptedTypesChanged(encrypted_types, encrypt_everything));
2344 }
2345
2346 void SyncManager::SyncInternal::OnNotificationStateChange(
2347 bool notifications_enabled) {
2348 DVLOG(1) << "P2P: Notifications enabled = "
2349 << (notifications_enabled ? "true" : "false");
2350 allstatus_.SetNotificationsEnabled(notifications_enabled);
2351 if (scheduler()) {
2352 scheduler()->set_notifications_enabled(notifications_enabled);
2353 }
2354 if (js_event_handler_.IsInitialized()) {
2355 DictionaryValue details;
2356 details.Set("enabled", Value::CreateBooleanValue(notifications_enabled));
2357 js_event_handler_.Call(FROM_HERE,
2358 &JsEventHandler::HandleJsEvent,
2359 "onNotificationStateChange",
2360 JsEventDetails(&details));
2361 }
2362 }
2363
2364 void SyncManager::SyncInternal::UpdateNotificationInfo(
2365 const syncable::ModelTypePayloadMap& type_payloads) {
2366 for (syncable::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
2367 it != type_payloads.end(); ++it) {
2368 NotificationInfo* info = &notification_info_map_[it->first];
2369 info->total_count++;
2370 info->payload = it->second;
2371 }
2372 }
2373
2374 void SyncManager::SyncInternal::OnIncomingNotification(
2375 const syncable::ModelTypePayloadMap& type_payloads,
2376 sync_notifier::IncomingNotificationSource source) {
2377 DCHECK(thread_checker_.CalledOnValidThread());
2378 if (source == sync_notifier::LOCAL_NOTIFICATION) {
2379 if (scheduler()) {
2380 scheduler()->ScheduleNudgeWithPayloads(
2381 TimeDelta::FromMilliseconds(kSyncRefreshDelayMsec),
2382 browser_sync::NUDGE_SOURCE_LOCAL_REFRESH,
2383 type_payloads, FROM_HERE);
2384 }
2385 } else if (!type_payloads.empty()) {
2386 if (scheduler()) {
2387 scheduler()->ScheduleNudgeWithPayloads(
2388 TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
2389 browser_sync::NUDGE_SOURCE_NOTIFICATION,
2390 type_payloads, FROM_HERE);
2391 }
2392 allstatus_.IncrementNotificationsReceived();
2393 UpdateNotificationInfo(type_payloads);
2394 debug_info_event_listener_.OnIncomingNotification(type_payloads);
2395 } else {
2396 LOG(WARNING) << "Sync received notification without any type information.";
2397 }
2398
2399 if (js_event_handler_.IsInitialized()) {
2400 DictionaryValue details;
2401 ListValue* changed_types = new ListValue();
2402 details.Set("changedTypes", changed_types);
2403 for (syncable::ModelTypePayloadMap::const_iterator
2404 it = type_payloads.begin();
2405 it != type_payloads.end(); ++it) {
2406 const std::string& model_type_str =
2407 syncable::ModelTypeToString(it->first);
2408 changed_types->Append(Value::CreateStringValue(model_type_str));
2409 }
2410 details.SetString("source", (source == sync_notifier::LOCAL_NOTIFICATION) ?
2411 "LOCAL_NOTIFICATION" : "REMOTE_NOTIFICATION");
2412 js_event_handler_.Call(FROM_HERE,
2413 &JsEventHandler::HandleJsEvent,
2414 "onIncomingNotification",
2415 JsEventDetails(&details));
2416 }
2417 }
2418
2419 void SyncManager::SyncInternal::StoreState(
2420 const std::string& state) {
2421 if (!directory()) {
2422 LOG(ERROR) << "Could not write notification state";
2423 // TODO(akalin): Propagate result callback all the way to this
2424 // function and call it with "false" to signal failure.
2425 return;
2426 }
2427 if (VLOG_IS_ON(1)) {
2428 std::string encoded_state;
2429 base::Base64Encode(state, &encoded_state);
2430 DVLOG(1) << "Writing notification state: " << encoded_state;
2431 }
2432 directory()->SetNotificationState(state);
2433 directory()->SaveChanges();
2434 }
2435
2436 void SyncManager::SyncInternal::AddObserver(
2437 SyncManager::Observer* observer) {
2438 observers_.AddObserver(observer);
2439 }
2440
2441 void SyncManager::SyncInternal::RemoveObserver(
2442 SyncManager::Observer* observer) {
2443 observers_.RemoveObserver(observer);
2444 }
2445
2446 SyncManager::Status SyncManager::GetDetailedStatus() const {
2447 return data_->GetStatus();
2448 }
2449
2450 void SyncManager::SaveChanges() {
2451 DCHECK(thread_checker_.CalledOnValidThread());
2452 data_->SaveChanges();
2453 }
2454
2455 void SyncManager::SyncInternal::SaveChanges() {
2456 directory()->SaveChanges();
2457 }
2458
2459 UserShare* SyncManager::GetUserShare() const {
2460 return data_->GetUserShare();
2461 }
2462
2463 void SyncManager::RefreshNigori(const std::string& chrome_version,
2464 const base::Closure& done_callback) {
2465 DCHECK(thread_checker_.CalledOnValidThread());
2466 data_->UpdateCryptographerAndNigori(
2467 chrome_version,
2468 done_callback);
2469 }
2470
2471 TimeDelta SyncManager::GetNudgeDelayTimeDelta(
2472 const ModelType& model_type) {
2473 return data_->GetNudgeDelayTimeDelta(model_type);
2474 }
2475
2476 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypesForTest() const {
2477 ReadTransaction trans(FROM_HERE, GetUserShare());
2478 return GetEncryptedTypes(&trans);
2479 }
2480
2481 bool SyncManager::ReceivedExperimentalTypes(syncable::ModelTypeSet* to_add)
2482 const {
2483 ReadTransaction trans(FROM_HERE, GetUserShare());
2484 ReadNode node(&trans);
2485 if (node.InitByTagLookup(kNigoriTag) != sync_api::BaseNode::INIT_OK) {
2486 DVLOG(1) << "Couldn't find Nigori node.";
2487 return false;
2488 }
2489 if (node.GetNigoriSpecifics().sync_tabs()) {
2490 to_add->Put(syncable::SESSIONS);
2491 return true;
2492 }
2493 return false;
2494 }
2495
2496 bool SyncManager::HasUnsyncedItems() const {
2497 sync_api::ReadTransaction trans(FROM_HERE, GetUserShare());
2498 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
2499 }
2500
2501 void SyncManager::TriggerOnNotificationStateChangeForTest(
2502 bool notifications_enabled) {
2503 DCHECK(thread_checker_.CalledOnValidThread());
2504 data_->OnNotificationStateChange(notifications_enabled);
2505 }
2506
2507 void SyncManager::TriggerOnIncomingNotificationForTest(
2508 ModelTypeSet model_types) {
2509 DCHECK(thread_checker_.CalledOnValidThread());
2510 syncable::ModelTypePayloadMap model_types_with_payloads =
2511 syncable::ModelTypePayloadMapFromEnumSet(model_types,
2512 std::string());
2513
2514 data_->OnIncomingNotification(model_types_with_payloads,
2515 sync_notifier::REMOTE_NOTIFICATION);
2516 }
2517
2518 const char* ConnectionStatusToString(ConnectionStatus status) {
2519 switch (status) {
2520 case CONNECTION_OK:
2521 return "CONNECTION_OK";
2522 case CONNECTION_AUTH_ERROR:
2523 return "CONNECTION_AUTH_ERROR";
2524 case CONNECTION_SERVER_ERROR:
2525 return "CONNECTION_SERVER_ERROR";
2526 default:
2527 NOTREACHED();
2528 return "INVALID_CONNECTION_STATUS";
2529 }
2530 }
2531
2532 // Helper function that converts a PassphraseRequiredReason value to a string.
2533 const char* PassphraseRequiredReasonToString(
2534 PassphraseRequiredReason reason) {
2535 switch (reason) {
2536 case REASON_PASSPHRASE_NOT_REQUIRED:
2537 return "REASON_PASSPHRASE_NOT_REQUIRED";
2538 case REASON_ENCRYPTION:
2539 return "REASON_ENCRYPTION";
2540 case REASON_DECRYPTION:
2541 return "REASON_DECRYPTION";
2542 default:
2543 NOTREACHED();
2544 return "INVALID_REASON";
2545 }
2546 }
2547
2548 // Helper function to determine if initial sync had ended for types.
2549 bool InitialSyncEndedForTypes(syncable::ModelTypeSet types,
2550 sync_api::UserShare* share) {
2551 for (syncable::ModelTypeSet::Iterator i = types.First();
2552 i.Good(); i.Inc()) {
2553 if (!share->directory->initial_sync_ended_for_type(i.Get()))
2554 return false;
2555 }
2556 return true;
2557 }
2558
2559 syncable::ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
2560 syncable::ModelTypeSet types,
2561 sync_api::UserShare* share) {
2562 syncable::ModelTypeSet result;
2563 for (syncable::ModelTypeSet::Iterator i = types.First();
2564 i.Good(); i.Inc()) {
2565 sync_pb::DataTypeProgressMarker marker;
2566 share->directory->GetDownloadProgress(i.Get(), &marker);
2567
2568 if (marker.token().empty())
2569 result.Put(i.Get());
2570
2571 }
2572 return result;
2573 }
2574
2575 } // namespace sync_api
OLDNEW
« no previous file with comments | « chrome/browser/sync/internal_api/sync_manager.h ('k') | chrome/browser/sync/internal_api/syncapi_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698