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

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

Issue 7633077: Refactor syncapi.h (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/engine/sync_manager.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/base64.h"
11 #include "base/json/json_writer.h"
12 #include "base/string_number_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/sync/engine/all_status.h"
15 #include "chrome/browser/sync/engine/base_node.h"
16 #include "chrome/browser/sync/engine/change_reorder_buffer.h"
17 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
18 #include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h"
19 #include "chrome/browser/sync/engine/nigori_util.h"
20 #include "chrome/browser/sync/engine/read_node.h"
21 #include "chrome/browser/sync/engine/syncapi_internal.h"
22 #include "chrome/browser/sync/engine/syncer_types.h"
23 #include "chrome/browser/sync/engine/sync_scheduler.h"
24 #include "chrome/browser/sync/engine/user_share.h"
25 #include "chrome/browser/sync/js/js_arg_list.h"
26 #include "chrome/browser/sync/js/js_backend.h"
27 #include "chrome/browser/sync/js/js_event_details.h"
28 #include "chrome/browser/sync/js/js_event_handler.h"
29 #include "chrome/browser/sync/js/js_reply_handler.h"
30 #include "chrome/browser/sync/js/js_sync_manager_observer.h"
31 #include "chrome/browser/sync/js/js_transaction_observer.h"
32 #include "chrome/browser/sync/notifier/sync_notifier.h"
33 #include "chrome/browser/sync/notifier/sync_notifier_observer.h"
34 #include "chrome/browser/sync/protocol/proto_value_conversions.h"
35 #include "chrome/browser/sync/syncable/directory_change_delegate.h"
36 #include "chrome/browser/sync/syncable/directory_manager.h"
37 #include "chrome/browser/sync/syncable/model_type.h"
38 #include "chrome/browser/sync/syncable/syncable.h"
39 #include "chrome/browser/sync/util/cryptographer.h"
40 #include "chrome/browser/sync/weak_handle.h"
41 #include "net/base/network_change_notifier.h"
42
43 using std::string;
44 using std::vector;
45
46 using base::TimeDelta;
47 using browser_sync::AllStatus;
48 using browser_sync::Cryptographer;
49 using browser_sync::JsArgList;
50 using browser_sync::JsBackend;
51 using browser_sync::JsEventDetails;
52 using browser_sync::JsEventHandler;
53 using browser_sync::JsEventHandler;
54 using browser_sync::JsReplyHandler;
55 using browser_sync::JsSyncManagerObserver;
56 using browser_sync::JsTransactionObserver;
57 using browser_sync::ModelSafeWorkerRegistrar;
58 using browser_sync::kNigoriTag;
59 using browser_sync::KeyParams;
60 using browser_sync::ModelSafeRoutingInfo;
61 using browser_sync::ServerConnectionEvent;
62 using browser_sync::ServerConnectionEventListener;
63 using browser_sync::SyncEngineEvent;
64 using browser_sync::SyncEngineEventListener;
65 using browser_sync::SyncScheduler;
66 using browser_sync::Syncer;
67 using browser_sync::WeakHandle;
68 using browser_sync::sessions::SyncSessionContext;
69 using syncable::DirectoryManager;
70 using syncable::EntryKernelMutationSet;
71 using syncable::ModelType;
72 using syncable::ModelTypeBitSet;
73 using syncable::SPECIFICS;
74
75 typedef GoogleServiceAuthError AuthError;
76
77 namespace {
78
79 static const int kSyncSchedulerDelayMsec = 250;
80
81 #if defined(OS_CHROMEOS)
82 static const int kChromeOSNetworkChangeReactionDelayHackMsec = 5000;
83 #endif // OS_CHROMEOS
84
85 } // namespace
86
87 namespace sync_api {
88
89 SyncManager::ChangeRecord::ChangeRecord()
90 : id(kInvalidId), action(ACTION_ADD) {}
91
92 SyncManager::ChangeRecord::~ChangeRecord() {}
93
94 DictionaryValue* SyncManager::ChangeRecord::ToValue(
95 const BaseTransaction* trans) const {
96 DictionaryValue* value = new DictionaryValue();
97 std::string action_str;
98 switch (action) {
99 case ACTION_ADD:
100 action_str = "Add";
101 break;
102 case ACTION_DELETE:
103 action_str = "Delete";
104 break;
105 case ACTION_UPDATE:
106 action_str = "Update";
107 break;
108 default:
109 NOTREACHED();
110 action_str = "Unknown";
111 break;
112 }
113 value->SetString("action", action_str);
114 Value* node_value = NULL;
115 if (action == ACTION_DELETE) {
116 DictionaryValue* node_dict = new DictionaryValue();
117 node_dict->SetString("id", base::Int64ToString(id));
118 node_dict->Set("specifics",
119 browser_sync::EntitySpecificsToValue(specifics));
120 if (extra.get()) {
121 node_dict->Set("extra", extra->ToValue());
122 }
123 node_value = node_dict;
124 } else {
125 ReadNode node(trans);
126 if (node.InitByIdLookup(id)) {
127 node_value = node.GetDetailsAsValue();
128 }
129 }
130 if (!node_value) {
131 NOTREACHED();
132 node_value = Value::CreateNullValue();
133 }
134 value->Set("node", node_value);
135 return value;
136 }
137
138 SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData() {}
139
140 SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData(
141 const sync_pb::PasswordSpecificsData& data)
142 : unencrypted_(data) {
143 }
144
145 SyncManager::ExtraPasswordChangeRecordData::~ExtraPasswordChangeRecordData() {}
146
147 DictionaryValue* SyncManager::ExtraPasswordChangeRecordData::ToValue() const {
148 return browser_sync::PasswordSpecificsDataToValue(unencrypted_);
149 }
150
151 const sync_pb::PasswordSpecificsData&
152 SyncManager::ExtraPasswordChangeRecordData::unencrypted() const {
153 return unencrypted_;
154 }
155
156 //////////////////////////////////////////////////////////////////////////
157 // SyncManager's implementation: SyncManager::SyncInternal
158 class SyncManager::SyncInternal
159 : public net::NetworkChangeNotifier::IPAddressObserver,
160 public sync_notifier::SyncNotifierObserver,
161 public JsBackend,
162 public SyncEngineEventListener,
163 public ServerConnectionEventListener,
164 public syncable::DirectoryChangeDelegate {
165 static const int kDefaultNudgeDelayMilliseconds;
166 static const int kPreferencesNudgeDelayMilliseconds;
167 public:
168 explicit SyncInternal(const std::string& name)
169 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
170 registrar_(NULL),
171 initialized_(false),
172 setup_for_test_mode_(false),
173 observing_ip_address_changes_(false) {
174 // Pre-fill |notification_info_map_|.
175 for (int i = syncable::FIRST_REAL_MODEL_TYPE;
176 i < syncable::MODEL_TYPE_COUNT; ++i) {
177 notification_info_map_.insert(
178 std::make_pair(syncable::ModelTypeFromInt(i), NotificationInfo()));
179 }
180
181 // Bind message handlers.
182 BindJsMessageHandler(
183 "getNotificationState",
184 &SyncManager::SyncInternal::GetNotificationState);
185 BindJsMessageHandler(
186 "getNotificationInfo",
187 &SyncManager::SyncInternal::GetNotificationInfo);
188 BindJsMessageHandler(
189 "getRootNodeDetails",
190 &SyncManager::SyncInternal::GetRootNodeDetails);
191 BindJsMessageHandler(
192 "getNodeSummariesById",
193 &SyncManager::SyncInternal::GetNodeSummariesById);
194 BindJsMessageHandler(
195 "getNodeDetailsById",
196 &SyncManager::SyncInternal::GetNodeDetailsById);
197 BindJsMessageHandler(
198 "getChildNodeIds",
199 &SyncManager::SyncInternal::GetChildNodeIds);
200 BindJsMessageHandler(
201 "findNodesContainingString",
202 &SyncManager::SyncInternal::FindNodesContainingString);
203 }
204
205 virtual ~SyncInternal() {
206 CHECK(!initialized_);
207 }
208
209 bool Init(const FilePath& database_location,
210 const WeakHandle<JsEventHandler>& event_handler,
211 const std::string& sync_server_and_path,
212 int port,
213 bool use_ssl,
214 HttpPostProviderFactory* post_factory,
215 ModelSafeWorkerRegistrar* model_safe_worker_registrar,
216 const std::string& user_agent,
217 const SyncCredentials& credentials,
218 sync_notifier::SyncNotifier* sync_notifier,
219 const std::string& restored_key_for_bootstrapping,
220 bool setup_for_test_mode);
221
222 // Sign into sync with given credentials.
223 // We do not verify the tokens given. After this call, the tokens are set
224 // and the sync DB is open. True if successful, false if something
225 // went wrong.
226 bool SignIn(const SyncCredentials& credentials);
227
228 // Update tokens that we're using in Sync. Email must stay the same.
229 void UpdateCredentials(const SyncCredentials& credentials);
230
231 // Called when the user disables or enables a sync type.
232 void UpdateEnabledTypes();
233
234 // Tell the sync engine to start the syncing process.
235 void StartSyncingNormally();
236
237 // Whether or not the Nigori node is encrypted using an explicit passphrase.
238 bool IsUsingExplicitPassphrase();
239
240 // Update the Cryptographer from the current 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 // Returns true if cryptographer is ready, false otherwise.
244 bool UpdateCryptographerFromNigori();
245
246 // Set the datatypes we want to encrypt and encrypt any nodes as necessary.
247 // Note: |encrypted_types| will be unioned with the current set of encrypted
248 // types, as we do not currently support decrypting datatypes.
249 void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types);
250
251 // Try to set the current passphrase to |passphrase|, and record whether
252 // it is an explicit passphrase or implicitly using gaia in the Nigori
253 // node.
254 void SetPassphrase(const std::string& passphrase, bool is_explicit);
255
256 // Call periodically from a database-safe thread to persist recent changes
257 // to the syncapi model.
258 void SaveChanges();
259
260 // DirectoryChangeDelegate implementation.
261 // This listener is called upon completion of a syncable transaction, and
262 // builds the list of sync-engine initiated changes that will be forwarded to
263 // the SyncManager's Observers.
264 virtual void HandleTransactionCompleteChangeEvent(
265 const ModelTypeBitSet& models_with_changes);
266 virtual ModelTypeBitSet HandleTransactionEndingChangeEvent(
267 syncable::BaseTransaction* trans);
268 virtual void HandleCalculateChangesChangeEventFromSyncApi(
269 const EntryKernelMutationSet& mutations,
270 syncable::BaseTransaction* trans);
271 virtual void HandleCalculateChangesChangeEventFromSyncer(
272 const EntryKernelMutationSet& mutations,
273 syncable::BaseTransaction* trans);
274
275 // Listens for notifications from the ServerConnectionManager
276 void HandleServerConnectionEvent(const ServerConnectionEvent& event);
277
278 // Open the directory named with username_for_share
279 bool OpenDirectory();
280
281 // SyncNotifierObserver implementation.
282 virtual void OnNotificationStateChange(
283 bool notifications_enabled);
284
285 virtual void OnIncomingNotification(
286 const syncable::ModelTypePayloadMap& type_payloads);
287
288 virtual void StoreState(const std::string& cookie);
289
290 // Thread-safe observers_ accessors.
291 void CopyObservers(ObserverList<SyncManager::Observer>* observers_copy);
292 bool HaveObservers() const;
293 void AddObserver(SyncManager::Observer* observer);
294 void RemoveObserver(SyncManager::Observer* observer);
295
296 // Accessors for the private members.
297 DirectoryManager* dir_manager() { return share_.dir_manager.get(); }
298 SyncAPIServerConnectionManager* connection_manager() {
299 return connection_manager_.get();
300 }
301 SyncScheduler* scheduler() { return scheduler_.get(); }
302 UserShare* GetUserShare() {
303 DCHECK(initialized_);
304 return &share_;
305 }
306
307 // Return the currently active (validated) username for use with syncable
308 // types.
309 const std::string& username_for_share() const {
310 return share_.name;
311 }
312
313 Status GetStatus();
314
315 void RequestNudge(const tracked_objects::Location& nudge_location);
316
317 void RequestNudgeForDataType(
318 const tracked_objects::Location& nudge_location,
319 const ModelType& type);
320
321 void RequestEarlyExit();
322
323 // See SyncManager::Shutdown for information.
324 void Shutdown();
325
326 // If this is a deletion for a password, sets the legacy
327 // ExtraPasswordChangeRecordData field of |buffer|. Otherwise sets
328 // |buffer|'s specifics field to contain the unencrypted data.
329 void SetExtraChangeRecordData(int64 id,
330 syncable::ModelType type,
331 ChangeReorderBuffer* buffer,
332 Cryptographer* cryptographer,
333 const syncable::EntryKernel& original,
334 bool existed_before,
335 bool exists_now);
336
337 // Called only by our NetworkChangeNotifier.
338 virtual void OnIPAddressChanged();
339
340 bool InitialSyncEndedForAllEnabledTypes() {
341 syncable::ModelTypeSet types;
342 ModelSafeRoutingInfo enabled_types;
343 registrar_->GetModelSafeRoutingInfo(&enabled_types);
344 for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
345 i != enabled_types.end(); ++i) {
346 types.insert(i->first);
347 }
348
349 return InitialSyncEndedForTypes(types, &share_);
350 }
351
352 // SyncEngineEventListener implementation.
353 virtual void OnSyncEngineEvent(const SyncEngineEvent& event);
354
355 // ServerConnectionEventListener implementation.
356 virtual void OnServerConnectionEvent(const ServerConnectionEvent& event);
357
358 // JsBackend implementation.
359 virtual void SetJsEventHandler(
360 const WeakHandle<JsEventHandler>& event_handler) OVERRIDE;
361 virtual void ProcessJsMessage(
362 const std::string& name, const JsArgList& args,
363 const WeakHandle<JsReplyHandler>& reply_handler) OVERRIDE;
364
365 private:
366 struct NotificationInfo {
367 int total_count;
368 std::string payload;
369
370 NotificationInfo() : total_count(0) {}
371
372 ~NotificationInfo() {}
373
374 // Returned pointer owned by the caller.
375 DictionaryValue* ToValue() const {
376 DictionaryValue* value = new DictionaryValue();
377 value->SetInteger("totalCount", total_count);
378 value->SetString("payload", payload);
379 return value;
380 }
381 };
382
383 typedef std::map<syncable::ModelType, NotificationInfo> NotificationInfoMap;
384 typedef JsArgList
385 (SyncManager::SyncInternal::*UnboundJsMessageHandler)(const JsArgList&);
386 typedef base::Callback<JsArgList(JsArgList)> JsMessageHandler;
387 typedef std::map<std::string, JsMessageHandler> JsMessageHandlerMap;
388
389 // Helper to call OnAuthError when no authentication credentials are
390 // available.
391 void RaiseAuthNeededEvent();
392
393 // Determine if the parents or predecessors differ between the old and new
394 // versions of an entry stored in |a| and |b|. Note that a node's index may
395 // change without its NEXT_ID changing if the node at NEXT_ID also moved (but
396 // the relative order is unchanged). To handle such cases, we rely on the
397 // caller to treat a position update on any sibling as updating the positions
398 // of all siblings.
399 static bool VisiblePositionsDiffer(
400 const syncable::EntryKernelMutation& mutation) {
401 const syncable::EntryKernel& a = mutation.original;
402 const syncable::EntryKernel& b = mutation.mutated;
403 // If the datatype isn't one where the browser model cares about position,
404 // don't bother notifying that data model of position-only changes.
405 if (!ShouldMaintainPosition(
406 syncable::GetModelTypeFromSpecifics(b.ref(SPECIFICS))))
407 return false;
408 if (a.ref(syncable::NEXT_ID) != b.ref(syncable::NEXT_ID))
409 return true;
410 if (a.ref(syncable::PARENT_ID) != b.ref(syncable::PARENT_ID))
411 return true;
412 return false;
413 }
414
415 // Determine if any of the fields made visible to clients of the Sync API
416 // differ between the versions of an entry stored in |a| and |b|. A return
417 // value of false means that it should be OK to ignore this change.
418 static bool VisiblePropertiesDiffer(
419 const syncable::EntryKernelMutation& mutation,
420 Cryptographer* cryptographer) {
421 const syncable::EntryKernel& a = mutation.original;
422 const syncable::EntryKernel& b = mutation.mutated;
423 const sync_pb::EntitySpecifics& a_specifics = a.ref(SPECIFICS);
424 const sync_pb::EntitySpecifics& b_specifics = b.ref(SPECIFICS);
425 DCHECK_EQ(syncable::GetModelTypeFromSpecifics(a_specifics),
426 syncable::GetModelTypeFromSpecifics(b_specifics));
427 syncable::ModelType model_type =
428 syncable::GetModelTypeFromSpecifics(b_specifics);
429 // Suppress updates to items that aren't tracked by any browser model.
430 if (model_type < syncable::FIRST_REAL_MODEL_TYPE ||
431 !a.ref(syncable::UNIQUE_SERVER_TAG).empty()) {
432 return false;
433 }
434 if (a.ref(syncable::IS_DIR) != b.ref(syncable::IS_DIR))
435 return true;
436 if (!AreSpecificsEqual(cryptographer,
437 a.ref(syncable::SPECIFICS),
438 b.ref(syncable::SPECIFICS))) {
439 return true;
440 }
441 // We only care if the name has changed if neither specifics is encrypted
442 // (encrypted nodes blow away the NON_UNIQUE_NAME).
443 if (!a_specifics.has_encrypted() && !b_specifics.has_encrypted() &&
444 a.ref(syncable::NON_UNIQUE_NAME) != b.ref(syncable::NON_UNIQUE_NAME))
445 return true;
446 if (VisiblePositionsDiffer(mutation))
447 return true;
448 return false;
449 }
450
451 bool ChangeBuffersAreEmpty() {
452 for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
453 if (!change_buffers_[i].IsEmpty())
454 return false;
455 }
456 return true;
457 }
458
459 void CheckServerReachable() {
460 if (connection_manager()) {
461 connection_manager()->CheckServerReachable();
462 } else {
463 NOTREACHED() << "Should be valid connection manager!";
464 }
465 }
466
467 void ReEncryptEverything(WriteTransaction* trans);
468
469 // Initializes (bootstraps) the Cryptographer if NIGORI has finished
470 // initial sync so that it can immediately start encrypting / decrypting.
471 // If the restored key is incompatible with the current version of the NIGORI
472 // node (which could happen if a restart occurred just after an update to
473 // NIGORI was downloaded and the user must enter a new passphrase to decrypt)
474 // then we will raise OnPassphraseRequired and set pending keys for
475 // decryption. Otherwise, the cryptographer is made ready (is_ready()).
476 void BootstrapEncryption(const std::string& restored_key_for_bootstrapping);
477
478 // Called for every notification. This updates the notification statistics
479 // to be displayed in about:sync.
480 void UpdateNotificationInfo(
481 const syncable::ModelTypePayloadMap& type_payloads);
482
483 // Checks for server reachabilty and requests a nudge.
484 void OnIPAddressChangedImpl();
485
486 // Helper function used only by the constructor.
487 void BindJsMessageHandler(
488 const std::string& name, UnboundJsMessageHandler unbound_message_handler);
489
490 // Returned pointer is owned by the caller.
491 static DictionaryValue* NotificationInfoToValue(
492 const NotificationInfoMap& notification_info);
493
494 // JS message handlers.
495 JsArgList GetNotificationState(const JsArgList& args);
496 JsArgList GetNotificationInfo(const JsArgList& args);
497 JsArgList GetRootNodeDetails(const JsArgList& args);
498 JsArgList GetNodeSummariesById(const JsArgList& args);
499 JsArgList GetNodeDetailsById(const JsArgList& args);
500 JsArgList GetChildNodeIds(const JsArgList& args);
501 JsArgList FindNodesContainingString(const JsArgList& args);
502
503 const std::string name_;
504
505 base::ThreadChecker thread_checker_;
506
507 base::WeakPtrFactory<SyncInternal> weak_ptr_factory_;
508
509 // Thread-safe handle used by
510 // HandleCalculateChangesChangeEventFromSyncApi(), which can be
511 // called from any thread. Valid only between between calls to
512 // Init() and Shutdown().
513 //
514 // TODO(akalin): Ideally, we wouldn't need to store this; instead,
515 // we'd have another worker class which implements
516 // HandleCalculateChangesChangeEventFromSyncApi() and we'd pass it a
517 // WeakHandle when we construct it.
518 WeakHandle<SyncInternal> weak_handle_this_;
519
520 // We couple the DirectoryManager and username together in a UserShare member
521 // so we can return a handle to share_ to clients of the API for use when
522 // constructing any transaction type.
523 UserShare share_;
524
525 // We have to lock around every observers_ access because it can get accessed
526 // from any thread and added to/removed from on the core thread.
527 mutable base::Lock observers_lock_;
528 ObserverList<SyncManager::Observer> observers_;
529
530 // The ServerConnectionManager used to abstract communication between the
531 // client (the Syncer) and the sync server.
532 scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
533
534 // The scheduler that runs the Syncer. Needs to be explicitly
535 // Start()ed.
536 scoped_ptr<SyncScheduler> scheduler_;
537
538 // The SyncNotifier which notifies us when updates need to be downloaded.
539 scoped_ptr<sync_notifier::SyncNotifier> sync_notifier_;
540
541 // A multi-purpose status watch object that aggregates stats from various
542 // sync components.
543 AllStatus allstatus_;
544
545 // Each element of this array is a store of change records produced by
546 // HandleChangeEvent during the CALCULATE_CHANGES step. The changes are
547 // segregated by model type, and are stored here to be processed and
548 // forwarded to the observer slightly later, at the TRANSACTION_ENDING
549 // step by HandleTransactionEndingChangeEvent. The list is cleared in the
550 // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
551 ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
552
553 // The entity that provides us with information about which types to sync.
554 // The instance is shared between the SyncManager and the Syncer.
555 ModelSafeWorkerRegistrar* registrar_;
556
557 // Set to true once Init has been called.
558 bool initialized_;
559
560 // True if the SyncManager should be running in test mode (no sync
561 // scheduler actually communicating with the server).
562 bool setup_for_test_mode_;
563
564 // Whether we should respond to an IP address change notification.
565 bool observing_ip_address_changes_;
566
567 // Map used to store the notification info to be displayed in
568 // about:sync page.
569 NotificationInfoMap notification_info_map_;
570
571 // These are for interacting with chrome://sync-internals.
572 JsMessageHandlerMap js_message_handlers_;
573 WeakHandle<JsEventHandler> js_event_handler_;
574 JsSyncManagerObserver js_sync_manager_observer_;
575 JsTransactionObserver js_transaction_observer_;
576 };
577 const int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
578 const int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
579
580 SyncManager::Observer::~Observer() {}
581
582 SyncManager::SyncManager(const std::string& name)
583 : data_(new SyncInternal(name)) {}
584
585 SyncManager::Status::Status()
586 : summary(INVALID),
587 authenticated(false),
588 server_up(false),
589 server_reachable(false),
590 server_broken(false),
591 notifications_enabled(false),
592 notifications_received(0),
593 notifiable_commits(0),
594 max_consecutive_errors(0),
595 unsynced_count(0),
596 conflicting_count(0),
597 syncing(false),
598 initial_sync_ended(false),
599 syncer_stuck(false),
600 updates_available(0),
601 updates_received(0),
602 tombstone_updates_received(0),
603 disk_full(false),
604 num_local_overwrites_total(0),
605 num_server_overwrites_total(0),
606 nonempty_get_updates(0),
607 empty_get_updates(0),
608 useless_sync_cycles(0),
609 useful_sync_cycles(0),
610 cryptographer_ready(false),
611 crypto_has_pending_keys(false) {
612 }
613
614 SyncManager::Status::~Status() {
615 }
616
617 bool SyncManager::Init(
618 const FilePath& database_location,
619 const WeakHandle<JsEventHandler>& event_handler,
620 const std::string& sync_server_and_path,
621 int sync_server_port,
622 bool use_ssl,
623 HttpPostProviderFactory* post_factory,
624 ModelSafeWorkerRegistrar* registrar,
625 const std::string& user_agent,
626 const SyncCredentials& credentials,
627 sync_notifier::SyncNotifier* sync_notifier,
628 const std::string& restored_key_for_bootstrapping,
629 bool setup_for_test_mode) {
630 DCHECK(post_factory);
631 VLOG(1) << "SyncManager starting Init...";
632 string server_string(sync_server_and_path);
633 return data_->Init(database_location,
634 event_handler,
635 server_string,
636 sync_server_port,
637 use_ssl,
638 post_factory,
639 registrar,
640 user_agent,
641 credentials,
642 sync_notifier,
643 restored_key_for_bootstrapping,
644 setup_for_test_mode);
645 }
646
647 void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
648 data_->UpdateCredentials(credentials);
649 }
650
651 void SyncManager::UpdateEnabledTypes() {
652 data_->UpdateEnabledTypes();
653 }
654
655 bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
656 return data_->InitialSyncEndedForAllEnabledTypes();
657 }
658
659 void SyncManager::StartSyncingNormally() {
660 data_->StartSyncingNormally();
661 }
662
663 void SyncManager::SetPassphrase(const std::string& passphrase,
664 bool is_explicit) {
665 data_->SetPassphrase(passphrase, is_explicit);
666 }
667
668 void SyncManager::EncryptDataTypes(
669 const syncable::ModelTypeSet& encrypted_types) {
670 data_->EncryptDataTypes(encrypted_types);
671 }
672
673 bool SyncManager::IsUsingExplicitPassphrase() {
674 return data_ && data_->IsUsingExplicitPassphrase();
675 }
676
677 void SyncManager::RequestCleanupDisabledTypes() {
678 if (data_->scheduler())
679 data_->scheduler()->ScheduleCleanupDisabledTypes();
680 }
681
682 void SyncManager::RequestClearServerData() {
683 if (data_->scheduler())
684 data_->scheduler()->ScheduleClearUserData();
685 }
686
687 void SyncManager::RequestConfig(const syncable::ModelTypeBitSet& types,
688 ConfigureReason reason) {
689 if (!data_->scheduler()) {
690 LOG(INFO)
691 << "SyncManager::RequestConfig: bailing out because scheduler is "
692 << "null";
693 return;
694 }
695 StartConfigurationMode(NULL);
696 data_->scheduler()->ScheduleConfig(types, reason);
697 }
698
699 void SyncManager::StartConfigurationMode(ModeChangeCallback* callback) {
700 if (!data_->scheduler()) {
701 LOG(INFO)
702 << "SyncManager::StartConfigurationMode: could not start "
703 << "configuration mode because because scheduler is null";
704 return;
705 }
706 data_->scheduler()->Start(
707 browser_sync::SyncScheduler::CONFIGURATION_MODE, callback);
708 }
709
710 const std::string& SyncManager::GetAuthenticatedUsername() {
711 DCHECK(data_);
712 return data_->username_for_share();
713 }
714
715 bool SyncManager::SyncInternal::Init(
716 const FilePath& database_location,
717 const WeakHandle<JsEventHandler>& event_handler,
718 const std::string& sync_server_and_path,
719 int port,
720 bool use_ssl,
721 HttpPostProviderFactory* post_factory,
722 ModelSafeWorkerRegistrar* model_safe_worker_registrar,
723 const std::string& user_agent,
724 const SyncCredentials& credentials,
725 sync_notifier::SyncNotifier* sync_notifier,
726 const std::string& restored_key_for_bootstrapping,
727 bool setup_for_test_mode) {
728 CHECK(!initialized_);
729
730 DCHECK(thread_checker_.CalledOnValidThread());
731
732 VLOG(1) << "Starting SyncInternal initialization.";
733
734 weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
735
736 registrar_ = model_safe_worker_registrar;
737 setup_for_test_mode_ = setup_for_test_mode;
738
739 sync_notifier_.reset(sync_notifier);
740
741 AddObserver(&js_sync_manager_observer_);
742 SetJsEventHandler(event_handler);
743
744 share_.dir_manager.reset(new DirectoryManager(database_location));
745
746 connection_manager_.reset(new SyncAPIServerConnectionManager(
747 sync_server_and_path, port, use_ssl, user_agent, post_factory));
748
749 net::NetworkChangeNotifier::AddIPAddressObserver(this);
750 observing_ip_address_changes_ = true;
751
752 connection_manager()->AddListener(this);
753
754 // TODO(akalin): CheckServerReachable() can block, which may cause jank if we
755 // try to shut down sync. Fix this.
756 MessageLoop::current()->PostTask(
757 FROM_HERE, base::Bind(&SyncInternal::CheckServerReachable,
758 weak_ptr_factory_.GetWeakPtr()));
759
760 // Test mode does not use a syncer context or syncer thread.
761 if (!setup_for_test_mode_) {
762 // Build a SyncSessionContext and store the worker in it.
763 VLOG(1) << "Sync is bringing up SyncSessionContext.";
764 std::vector<SyncEngineEventListener*> listeners;
765 listeners.push_back(&allstatus_);
766 listeners.push_back(this);
767 SyncSessionContext* context = new SyncSessionContext(
768 connection_manager_.get(),
769 dir_manager(),
770 model_safe_worker_registrar,
771 listeners);
772 context->set_account_name(credentials.email);
773 // The SyncScheduler takes ownership of |context|.
774 scheduler_.reset(new SyncScheduler(name_, context, new Syncer()));
775 }
776
777 bool signed_in = SignIn(credentials);
778
779 if (signed_in && scheduler()) {
780 scheduler()->Start(
781 browser_sync::SyncScheduler::CONFIGURATION_MODE, NULL);
782 }
783
784 initialized_ = true;
785
786 // Notify that initialization is complete.
787 ObserverList<SyncManager::Observer> temp_obs_list;
788 CopyObservers(&temp_obs_list);
789 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
790 OnInitializationComplete(
791 WeakHandle<JsBackend>(weak_ptr_factory_.GetWeakPtr())));
792
793 // The following calls check that initialized_ is true.
794
795 BootstrapEncryption(restored_key_for_bootstrapping);
796
797 sync_notifier_->AddObserver(this);
798
799 return signed_in;
800 }
801
802 void SyncManager::SyncInternal::BootstrapEncryption(
803 const std::string& restored_key_for_bootstrapping) {
804 // Cryptographer should only be accessed while holding a transaction.
805 ReadTransaction trans(FROM_HERE, GetUserShare());
806 Cryptographer* cryptographer = trans.GetCryptographer();
807
808 // Set the bootstrap token before bailing out if nigori node is not there.
809 // This could happen if server asked us to migrate nigri.
810 cryptographer->Bootstrap(restored_key_for_bootstrapping);
811 }
812
813 bool SyncManager::SyncInternal::UpdateCryptographerFromNigori() {
814 DCHECK(initialized_);
815 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
816 if (!lookup.good()) {
817 NOTREACHED() << "BootstrapEncryption: lookup not good so bailing out";
818 return false;
819 }
820 if (!lookup->initial_sync_ended_for_type(syncable::NIGORI))
821 return false; // Should only happen during first time sync.
822
823 ReadTransaction trans(FROM_HERE, GetUserShare());
824 Cryptographer* cryptographer = trans.GetCryptographer();
825
826 ReadNode node(&trans);
827 if (!node.InitByTagLookup(kNigoriTag)) {
828 NOTREACHED();
829 return false;
830 }
831 Cryptographer::UpdateResult result =
832 cryptographer->Update(node.GetNigoriSpecifics());
833 if (result == Cryptographer::NEEDS_PASSPHRASE) {
834 ObserverList<SyncManager::Observer> temp_obs_list;
835 CopyObservers(&temp_obs_list);
836 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
837 OnPassphraseRequired(sync_api::REASON_DECRYPTION));
838 }
839
840 allstatus_.SetCryptographerReady(cryptographer->is_ready());
841 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
842
843 return cryptographer->is_ready();
844 }
845
846 void SyncManager::SyncInternal::StartSyncingNormally() {
847 // Start the sync scheduler. This won't actually result in any
848 // syncing until at least the DirectoryManager broadcasts the OPENED
849 // event, and a valid server connection is detected.
850 if (scheduler()) // NULL during certain unittests.
851 scheduler()->Start(SyncScheduler::NORMAL_MODE, NULL);
852 }
853
854 bool SyncManager::SyncInternal::OpenDirectory() {
855 DCHECK(!initialized_) << "Should only happen once";
856
857 bool share_opened = dir_manager()->Open(username_for_share(), this);
858 DCHECK(share_opened);
859 if (!share_opened) {
860 ObserverList<SyncManager::Observer> temp_obs_list;
861 CopyObservers(&temp_obs_list);
862 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
863 OnStopSyncingPermanently());
864
865 LOG(ERROR) << "Could not open share for:" << username_for_share();
866 return false;
867 }
868
869 // Database has to be initialized for the guid to be available.
870 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
871 if (!lookup.good()) {
872 NOTREACHED();
873 return false;
874 }
875
876 connection_manager()->set_client_id(lookup->cache_guid());
877 lookup->AddTransactionObserver(&js_transaction_observer_);
878 return true;
879 }
880
881 bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
882 DCHECK(thread_checker_.CalledOnValidThread());
883 DCHECK(share_.name.empty());
884 share_.name = credentials.email;
885
886 VLOG(1) << "Signing in user: " << username_for_share();
887 if (!OpenDirectory())
888 return false;
889
890 // Retrieve and set the sync notifier state. This should be done
891 // only after OpenDirectory is called.
892 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
893 std::string unique_id;
894 std::string state;
895 if (lookup.good()) {
896 unique_id = lookup->cache_guid();
897 state = lookup->GetNotificationState();
898 VLOG(1) << "Read notification unique ID: " << unique_id;
899 if (VLOG_IS_ON(1)) {
900 std::string encoded_state;
901 base::Base64Encode(state, &encoded_state);
902 VLOG(1) << "Read notification state: " << encoded_state;
903 }
904 } else {
905 LOG(ERROR) << "Could not read notification unique ID/state";
906 }
907 sync_notifier_->SetUniqueId(unique_id);
908 sync_notifier_->SetState(state);
909
910 UpdateCredentials(credentials);
911 UpdateEnabledTypes();
912 return true;
913 }
914
915 void SyncManager::SyncInternal::UpdateCredentials(
916 const SyncCredentials& credentials) {
917 DCHECK(thread_checker_.CalledOnValidThread());
918 DCHECK_EQ(credentials.email, share_.name);
919 DCHECK(!credentials.email.empty());
920 DCHECK(!credentials.sync_token.empty());
921
922 observing_ip_address_changes_ = true;
923 if (connection_manager()->set_auth_token(credentials.sync_token)) {
924 sync_notifier_->UpdateCredentials(
925 credentials.email, credentials.sync_token);
926 if (!setup_for_test_mode_) {
927 CheckServerReachable();
928 }
929 }
930 }
931
932 void SyncManager::SyncInternal::UpdateEnabledTypes() {
933 DCHECK(thread_checker_.CalledOnValidThread());
934 ModelSafeRoutingInfo routes;
935 registrar_->GetModelSafeRoutingInfo(&routes);
936 syncable::ModelTypeSet enabled_types;
937 for (ModelSafeRoutingInfo::const_iterator it = routes.begin();
938 it != routes.end(); ++it) {
939 enabled_types.insert(it->first);
940 }
941 sync_notifier_->UpdateEnabledTypes(enabled_types);
942 }
943
944 void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
945 ObserverList<SyncManager::Observer> temp_obs_list;
946 CopyObservers(&temp_obs_list);
947 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
948 OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
949 }
950
951 void SyncManager::SyncInternal::SetPassphrase(
952 const std::string& passphrase, bool is_explicit) {
953 // We do not accept empty passphrases.
954 if (passphrase.empty()) {
955 VLOG(1) << "Rejecting empty passphrase.";
956 ObserverList<SyncManager::Observer> temp_obs_list;
957 CopyObservers(&temp_obs_list);
958 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
959 OnPassphraseRequired(sync_api::REASON_SET_PASSPHRASE_FAILED));
960 return;
961 }
962
963 // All accesses to the cryptographer are protected by a transaction.
964 WriteTransaction trans(FROM_HERE, GetUserShare());
965 Cryptographer* cryptographer = trans.GetCryptographer();
966 KeyParams params = {"localhost", "dummy", passphrase};
967
968 WriteNode node(&trans);
969 if (!node.InitByTagLookup(kNigoriTag)) {
970 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
971 NOTREACHED();
972 return;
973 }
974
975 if (cryptographer->has_pending_keys()) {
976 bool suceeded = false;
977
978 // See if the explicit flag matches what is set in nigori. If not we dont
979 // even try the passphrase. Note: This could mean that we wont try setting
980 // the gaia password as passphrase if custom is elected by the user. Which
981 // is fine because nigori node has all the old passwords in it.
982 if (node.GetNigoriSpecifics().using_explicit_passphrase() == is_explicit) {
983 if (cryptographer->DecryptPendingKeys(params)) {
984 suceeded = true;
985 } else {
986 VLOG(1) << "Passphrase failed to decrypt pending keys.";
987 }
988 } else {
989 VLOG(1) << "Not trying the passphrase because the explicit flags dont "
990 << "match. Nigori node's explicit flag is "
991 << node.GetNigoriSpecifics().using_explicit_passphrase();
992 }
993
994 if (!suceeded) {
995 ObserverList<SyncManager::Observer> temp_obs_list;
996 CopyObservers(&temp_obs_list);
997 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
998 OnPassphraseRequired(sync_api::REASON_SET_PASSPHRASE_FAILED));
999 return;
1000 }
1001
1002 // Nudge the syncer so that encrypted datatype updates that were waiting for
1003 // this passphrase get applied as soon as possible.
1004 RequestNudge(FROM_HERE);
1005 } else {
1006 VLOG(1) << "No pending keys, adding provided passphrase.";
1007
1008 // Prevent an implicit SetPassphrase request from changing an explicitly
1009 // set passphrase.
1010 if (!is_explicit && node.GetNigoriSpecifics().using_explicit_passphrase())
1011 return;
1012
1013 cryptographer->AddKey(params);
1014
1015 // TODO(tim): Bug 58231. It would be nice if SetPassphrase didn't require
1016 // messing with the Nigori node, because we can't call SetPassphrase until
1017 // download conditions are met vs Cryptographer init. It seems like it's
1018 // safe to defer this work.
1019 sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
1020 specifics.clear_encrypted();
1021 cryptographer->GetKeys(specifics.mutable_encrypted());
1022 specifics.set_using_explicit_passphrase(is_explicit);
1023 node.SetNigoriSpecifics(specifics);
1024 ReEncryptEverything(&trans);
1025 }
1026
1027 VLOG(1) << "Passphrase accepted, bootstrapping encryption.";
1028 std::string bootstrap_token;
1029 cryptographer->GetBootstrapToken(&bootstrap_token);
1030 ObserverList<SyncManager::Observer> temp_obs_list;
1031 CopyObservers(&temp_obs_list);
1032 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1033 OnPassphraseAccepted(bootstrap_token));
1034 }
1035
1036 bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
1037 ReadTransaction trans(FROM_HERE, &share_);
1038 ReadNode node(&trans);
1039 if (!node.InitByTagLookup(kNigoriTag)) {
1040 // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1041 NOTREACHED();
1042 return false;
1043 }
1044
1045 return node.GetNigoriSpecifics().using_explicit_passphrase();
1046 }
1047
1048 void SyncManager::SyncInternal::EncryptDataTypes(
1049 const syncable::ModelTypeSet& encrypted_types) {
1050 DCHECK(initialized_);
1051 VLOG(1) << "Attempting to encrypt datatypes "
1052 << syncable::ModelTypeSetToString(encrypted_types);
1053
1054 WriteTransaction trans(FROM_HERE, GetUserShare());
1055 WriteNode node(&trans);
1056 if (!node.InitByTagLookup(kNigoriTag)) {
1057 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not "
1058 << "found.";
1059 return;
1060 }
1061
1062 Cryptographer* cryptographer = trans.GetCryptographer();
1063
1064 if (!cryptographer->is_initialized()) {
1065 VLOG(1) << "Attempting to encrypt datatypes when cryptographer not "
1066 << "initialized, prompting for passphrase.";
1067 ObserverList<SyncManager::Observer> temp_obs_list;
1068 CopyObservers(&temp_obs_list);
1069 // TODO(zea): this isn't really decryption, but that's the only way we have
1070 // to prompt the user for a passsphrase. See http://crbug.com/91379.
1071 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1072 OnPassphraseRequired(sync_api::REASON_DECRYPTION));
1073 return;
1074 }
1075
1076 // Update the Nigori node's set of encrypted datatypes.
1077 // Note, we merge the current encrypted types with those requested. Once a
1078 // datatypes is marked as needing encryption, it is never unmarked.
1079 sync_pb::NigoriSpecifics nigori;
1080 nigori.CopyFrom(node.GetNigoriSpecifics());
1081 syncable::ModelTypeSet current_encrypted_types = GetEncryptedTypes(&trans);
1082 syncable::ModelTypeSet newly_encrypted_types;
1083 std::set_union(current_encrypted_types.begin(), current_encrypted_types.end(),
1084 encrypted_types.begin(), encrypted_types.end(),
1085 std::inserter(newly_encrypted_types,
1086 newly_encrypted_types.begin()));
1087 allstatus_.SetEncryptedTypes(newly_encrypted_types);
1088 if (newly_encrypted_types == current_encrypted_types) {
1089 // Set of encrypted types has not changed, just notify and return.
1090 ObserverList<SyncManager::Observer> temp_obs_list;
1091 CopyObservers(&temp_obs_list);
1092 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1093 OnEncryptionComplete(current_encrypted_types));
1094 return;
1095 }
1096 syncable::FillNigoriEncryptedTypes(newly_encrypted_types, &nigori);
1097 node.SetNigoriSpecifics(nigori);
1098
1099 cryptographer->SetEncryptedTypes(nigori);
1100
1101 // TODO(zea): only reencrypt this datatype? ReEncrypting everything is a
1102 // safer approach, and should not impact anything that is already encrypted
1103 // (redundant changes are ignored).
1104 ReEncryptEverything(&trans);
1105 return;
1106 }
1107
1108 // TODO(zea): Add unit tests that ensure no sync changes are made when not
1109 // needed.
1110 void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
1111 syncable::ModelTypeSet encrypted_types =
1112 GetEncryptedTypes(trans);
1113 ModelSafeRoutingInfo routes;
1114 registrar_->GetModelSafeRoutingInfo(&routes);
1115 std::string tag;
1116 for (syncable::ModelTypeSet::iterator iter = encrypted_types.begin();
1117 iter != encrypted_types.end(); ++iter) {
1118 if (*iter == syncable::PASSWORDS || routes.count(*iter) == 0)
1119 continue;
1120 ReadNode type_root(trans);
1121 tag = syncable::ModelTypeToRootTag(*iter);
1122 if (!type_root.InitByTagLookup(tag)) {
1123 NOTREACHED();
1124 return;
1125 }
1126
1127 // Iterate through all children of this datatype.
1128 std::queue<int64> to_visit;
1129 int64 child_id = type_root.GetFirstChildId();
1130 to_visit.push(child_id);
1131 while (!to_visit.empty()) {
1132 child_id = to_visit.front();
1133 to_visit.pop();
1134 if (child_id == kInvalidId)
1135 continue;
1136
1137 WriteNode child(trans);
1138 if (!child.InitByIdLookup(child_id)) {
1139 NOTREACHED();
1140 continue;
1141 }
1142 if (child.GetIsFolder()) {
1143 to_visit.push(child.GetFirstChildId());
1144 }
1145 if (child.GetEntry()->Get(syncable::UNIQUE_SERVER_TAG).empty()) {
1146 // Rewrite the specifics of the node with encrypted data if necessary
1147 // (only rewrite the non-unique folders).
1148 child.ResetFromSpecifics();
1149 }
1150 to_visit.push(child.GetSuccessorId());
1151 }
1152 }
1153
1154 if (routes.count(syncable::PASSWORDS) > 0) {
1155 // Passwords are encrypted with their own legacy scheme.
1156 ReadNode passwords_root(trans);
1157 std::string passwords_tag =
1158 syncable::ModelTypeToRootTag(syncable::PASSWORDS);
1159 // It's possible we'll have the password routing info and not the password
1160 // root if we attempted to SetPassphrase before passwords was enabled.
1161 if (passwords_root.InitByTagLookup(passwords_tag)) {
1162 int64 child_id = passwords_root.GetFirstChildId();
1163 while (child_id != kInvalidId) {
1164 WriteNode child(trans);
1165 if (!child.InitByIdLookup(child_id)) {
1166 NOTREACHED();
1167 return;
1168 }
1169 child.SetPasswordSpecifics(child.GetPasswordSpecifics());
1170 child_id = child.GetSuccessorId();
1171 }
1172 }
1173 }
1174
1175 ObserverList<SyncManager::Observer> temp_obs_list;
1176 CopyObservers(&temp_obs_list);
1177 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1178 OnEncryptionComplete(encrypted_types));
1179 }
1180
1181 SyncManager::~SyncManager() {
1182 delete data_;
1183 }
1184
1185 void SyncManager::AddObserver(Observer* observer) {
1186 data_->AddObserver(observer);
1187 }
1188
1189 void SyncManager::RemoveObserver(Observer* observer) {
1190 data_->RemoveObserver(observer);
1191 }
1192
1193 void SyncManager::RequestEarlyExit() {
1194 data_->RequestEarlyExit();
1195 }
1196
1197 void SyncManager::SyncInternal::RequestEarlyExit() {
1198 if (scheduler()) {
1199 scheduler()->RequestEarlyExit();
1200 }
1201 }
1202
1203 void SyncManager::Shutdown() {
1204 data_->Shutdown();
1205 }
1206
1207 void SyncManager::SyncInternal::Shutdown() {
1208 DCHECK(thread_checker_.CalledOnValidThread());
1209
1210 // Prevent any in-flight method calls from running. Also
1211 // invalidates |weak_handle_this_|.
1212 weak_ptr_factory_.InvalidateWeakPtrs();
1213
1214 // Automatically stops the scheduler.
1215 scheduler_.reset();
1216
1217 SetJsEventHandler(WeakHandle<JsEventHandler>());
1218 RemoveObserver(&js_sync_manager_observer_);
1219
1220 if (sync_notifier_.get()) {
1221 sync_notifier_->RemoveObserver(this);
1222 }
1223 sync_notifier_.reset();
1224
1225 if (connection_manager_.get()) {
1226 connection_manager_->RemoveListener(this);
1227 }
1228 connection_manager_.reset();
1229
1230 net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
1231 observing_ip_address_changes_ = false;
1232
1233 if (dir_manager()) {
1234 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1235 if (lookup.good()) {
1236 lookup->RemoveTransactionObserver(&js_transaction_observer_);
1237 } else {
1238 NOTREACHED();
1239 }
1240 dir_manager()->FinalSaveChangesForAll();
1241 dir_manager()->Close(username_for_share());
1242 }
1243
1244 // Reset the DirectoryManager and UserSettings so they relinquish sqlite
1245 // handles to backing files.
1246 share_.dir_manager.reset();
1247
1248 setup_for_test_mode_ = false;
1249 registrar_ = NULL;
1250
1251 initialized_ = false;
1252
1253 // We reset this here, since only now we know it will not be
1254 // accessed from other threads (since we shut down everything).
1255 weak_handle_this_.Reset();
1256 }
1257
1258 void SyncManager::SyncInternal::OnIPAddressChanged() {
1259 VLOG(1) << "IP address change detected";
1260 if (!observing_ip_address_changes_) {
1261 VLOG(1) << "IP address change dropped.";
1262 return;
1263 }
1264
1265 #if defined (OS_CHROMEOS)
1266 // TODO(tim): This is a hack to intentionally lose a race with flimflam at
1267 // shutdown, so we don't cause shutdown to wait for our http request.
1268 // http://crosbug.com/8429
1269 MessageLoop::current()->PostDelayedTask(
1270 FROM_HERE,
1271 base::Bind(&SyncInternal::OnIPAddressChangedImpl,
1272 weak_ptr_factory_.GetWeakPtr()),
1273 kChromeOSNetworkChangeReactionDelayHackMsec);
1274 #else
1275 OnIPAddressChangedImpl();
1276 #endif // defined(OS_CHROMEOS)
1277 }
1278
1279 void SyncManager::SyncInternal::OnIPAddressChangedImpl() {
1280 // TODO(akalin): CheckServerReachable() can block, which may cause
1281 // jank if we try to shut down sync. Fix this.
1282 connection_manager()->CheckServerReachable();
1283 }
1284
1285 void SyncManager::SyncInternal::OnServerConnectionEvent(
1286 const ServerConnectionEvent& event) {
1287 allstatus_.HandleServerConnectionEvent(event);
1288 if (event.connection_code ==
1289 browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
1290 ObserverList<SyncManager::Observer> temp_obs_list;
1291 CopyObservers(&temp_obs_list);
1292 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1293 OnAuthError(AuthError::None()));
1294 }
1295
1296 if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
1297 observing_ip_address_changes_ = false;
1298 ObserverList<SyncManager::Observer> temp_obs_list;
1299 CopyObservers(&temp_obs_list);
1300 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1301 OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
1302 }
1303
1304 if (event.connection_code ==
1305 browser_sync::HttpResponse::SYNC_SERVER_ERROR) {
1306 ObserverList<SyncManager::Observer> temp_obs_list;
1307 CopyObservers(&temp_obs_list);
1308 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1309 OnAuthError(AuthError(AuthError::CONNECTION_FAILED)));
1310 }
1311 }
1312
1313 void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
1314 const syncable::ModelTypeBitSet& models_with_changes) {
1315 // This notification happens immediately after the transaction mutex is
1316 // released. This allows work to be performed without blocking other threads
1317 // from acquiring a transaction.
1318 if (!HaveObservers())
1319 return;
1320
1321 // Call commit.
1322 for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1323 if (models_with_changes.test(i)) {
1324 ObserverList<SyncManager::Observer> temp_obs_list;
1325 CopyObservers(&temp_obs_list);
1326 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1327 OnChangesComplete(syncable::ModelTypeFromInt(i)));
1328 }
1329 }
1330 }
1331
1332 ModelTypeBitSet SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
1333 syncable::BaseTransaction* trans) {
1334 // This notification happens immediately before a syncable WriteTransaction
1335 // falls out of scope. It happens while the channel mutex is still held,
1336 // and while the transaction mutex is held, so it cannot be re-entrant.
1337 if (!HaveObservers() || ChangeBuffersAreEmpty())
1338 return ModelTypeBitSet();
1339
1340 // This will continue the WriteTransaction using a read only wrapper.
1341 // This is the last chance for read to occur in the WriteTransaction
1342 // that's closing. This special ReadTransaction will not close the
1343 // underlying transaction.
1344 ReadTransaction read_trans(GetUserShare(), trans);
1345
1346 syncable::ModelTypeBitSet models_with_changes;
1347 for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1348 if (change_buffers_[i].IsEmpty())
1349 continue;
1350
1351 vector<ChangeRecord> ordered_changes;
1352 change_buffers_[i].GetAllChangesInTreeOrder(&read_trans, &ordered_changes);
1353 if (!ordered_changes.empty()) {
1354 ObserverList<SyncManager::Observer> temp_obs_list;
1355 CopyObservers(&temp_obs_list);
1356 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1357 OnChangesApplied(syncable::ModelTypeFromInt(i), &read_trans,
1358 &ordered_changes[0], ordered_changes.size()));
1359 models_with_changes.set(i, true);
1360 }
1361 change_buffers_[i].Clear();
1362 }
1363 return models_with_changes;
1364 }
1365
1366 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
1367 const EntryKernelMutationSet& mutations,
1368 syncable::BaseTransaction* trans) {
1369 if (!scheduler()) {
1370 return;
1371 }
1372
1373 // We have been notified about a user action changing a sync model.
1374 LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1375 "CALCULATE_CHANGES called with unapplied old changes.";
1376
1377 // The mutated model type, or UNSPECIFIED if nothing was mutated.
1378 syncable::ModelType mutated_model_type = syncable::UNSPECIFIED;
1379
1380 // Find the first real mutation. We assume that only a single model
1381 // type is mutated per transaction.
1382 for (syncable::EntryKernelMutationSet::const_iterator it =
1383 mutations.begin(); it != mutations.end(); ++it) {
1384 if (!it->mutated.ref(syncable::IS_UNSYNCED)) {
1385 continue;
1386 }
1387
1388 syncable::ModelType model_type =
1389 syncable::GetModelTypeFromSpecifics(it->mutated.ref(SPECIFICS));
1390 if (model_type < syncable::FIRST_REAL_MODEL_TYPE) {
1391 NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
1392 continue;
1393 }
1394
1395 // Found real mutation.
1396 if (mutated_model_type == syncable::UNSPECIFIED) {
1397 mutated_model_type = model_type;
1398 break;
1399 }
1400 }
1401
1402 // Nudge if necessary.
1403 if (mutated_model_type != syncable::UNSPECIFIED) {
1404 if (weak_handle_this_.IsInitialized()) {
1405 weak_handle_this_.Call(FROM_HERE,
1406 &SyncInternal::RequestNudgeForDataType,
1407 FROM_HERE,
1408 mutated_model_type);
1409 } else {
1410 NOTREACHED();
1411 }
1412 }
1413 }
1414
1415 void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
1416 syncable::ModelType type, ChangeReorderBuffer* buffer,
1417 Cryptographer* cryptographer, const syncable::EntryKernel& original,
1418 bool existed_before, bool exists_now) {
1419 // If this is a deletion and the datatype was encrypted, we need to decrypt it
1420 // and attach it to the buffer.
1421 if (!exists_now && existed_before) {
1422 sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
1423 if (type == syncable::PASSWORDS) {
1424 // Passwords must use their own legacy ExtraPasswordChangeRecordData.
1425 scoped_ptr<sync_pb::PasswordSpecificsData> data(
1426 DecryptPasswordSpecifics(original_specifics, cryptographer));
1427 if (!data.get()) {
1428 NOTREACHED();
1429 return;
1430 }
1431 buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
1432 } else if (original_specifics.has_encrypted()) {
1433 // All other datatypes can just create a new unencrypted specifics and
1434 // attach it.
1435 const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
1436 if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
1437 NOTREACHED();
1438 return;
1439 }
1440 }
1441 buffer->SetSpecificsForId(id, original_specifics);
1442 }
1443 }
1444
1445 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
1446 const EntryKernelMutationSet& mutations,
1447 syncable::BaseTransaction* trans) {
1448 // We only expect one notification per sync step, so change_buffers_ should
1449 // contain no pending entries.
1450 LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1451 "CALCULATE_CHANGES called with unapplied old changes.";
1452
1453 Cryptographer* crypto = dir_manager()->GetCryptographer(trans);
1454 for (syncable::EntryKernelMutationSet::const_iterator it =
1455 mutations.begin(); it != mutations.end(); ++it) {
1456 bool existed_before = !it->original.ref(syncable::IS_DEL);
1457 bool exists_now = !it->mutated.ref(syncable::IS_DEL);
1458
1459 // Omit items that aren't associated with a model.
1460 syncable::ModelType type =
1461 syncable::GetModelTypeFromSpecifics(it->mutated.ref(SPECIFICS));
1462 if (type < syncable::FIRST_REAL_MODEL_TYPE)
1463 continue;
1464
1465 int64 id = it->original.ref(syncable::META_HANDLE);
1466 if (exists_now && !existed_before)
1467 change_buffers_[type].PushAddedItem(id);
1468 else if (!exists_now && existed_before)
1469 change_buffers_[type].PushDeletedItem(id);
1470 else if (exists_now && existed_before &&
1471 VisiblePropertiesDiffer(*it, crypto)) {
1472 change_buffers_[type].PushUpdatedItem(
1473 id, VisiblePositionsDiffer(*it));
1474 }
1475
1476 SetExtraChangeRecordData(id, type, &change_buffers_[type], crypto,
1477 it->original, existed_before, exists_now);
1478 }
1479 }
1480
1481 SyncManager::Status SyncManager::SyncInternal::GetStatus() {
1482 return allstatus_.status();
1483 }
1484
1485 void SyncManager::SyncInternal::RequestNudge(
1486 const tracked_objects::Location& location) {
1487 if (scheduler())
1488 scheduler()->ScheduleNudge(
1489 TimeDelta::FromMilliseconds(0), browser_sync::NUDGE_SOURCE_LOCAL,
1490 ModelTypeBitSet(), location);
1491 }
1492
1493 void SyncManager::SyncInternal::RequestNudgeForDataType(
1494 const tracked_objects::Location& nudge_location,
1495 const ModelType& type) {
1496 if (!scheduler()) {
1497 NOTREACHED();
1498 return;
1499 }
1500 base::TimeDelta nudge_delay;
1501 switch (type) {
1502 case syncable::PREFERENCES:
1503 nudge_delay =
1504 TimeDelta::FromMilliseconds(kPreferencesNudgeDelayMilliseconds);
1505 break;
1506 case syncable::SESSIONS:
1507 nudge_delay = scheduler()->sessions_commit_delay();
1508 break;
1509 default:
1510 nudge_delay =
1511 TimeDelta::FromMilliseconds(kDefaultNudgeDelayMilliseconds);
1512 break;
1513 }
1514 syncable::ModelTypeBitSet types;
1515 types.set(type);
1516 scheduler()->ScheduleNudge(nudge_delay,
1517 browser_sync::NUDGE_SOURCE_LOCAL,
1518 types,
1519 nudge_location);
1520 }
1521
1522 void SyncManager::SyncInternal::OnSyncEngineEvent(
1523 const SyncEngineEvent& event) {
1524 DCHECK(thread_checker_.CalledOnValidThread());
1525 if (!HaveObservers()) {
1526 LOG(INFO)
1527 << "OnSyncEngineEvent returning because observers_.size() is zero";
1528 return;
1529 }
1530
1531 // Only send an event if this is due to a cycle ending and this cycle
1532 // concludes a canonical "sync" process; that is, based on what is known
1533 // locally we are "all happy" and up-to-date. There may be new changes on
1534 // the server, but we'll get them on a subsequent sync.
1535 //
1536 // Notifications are sent at the end of every sync cycle, regardless of
1537 // whether we should sync again.
1538 if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
1539 ModelSafeRoutingInfo enabled_types;
1540 registrar_->GetModelSafeRoutingInfo(&enabled_types);
1541 {
1542 // Check to see if we need to notify the frontend that we have newly
1543 // encrypted types or that we require a passphrase.
1544 sync_api::ReadTransaction trans(FROM_HERE, GetUserShare());
1545 Cryptographer* cryptographer = trans.GetCryptographer();
1546 // If we've completed a sync cycle and the cryptographer isn't ready
1547 // yet, prompt the user for a passphrase.
1548 if (cryptographer->has_pending_keys()) {
1549 VLOG(1) << "OnPassPhraseRequired Sent";
1550 ObserverList<SyncManager::Observer> temp_obs_list;
1551 CopyObservers(&temp_obs_list);
1552 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1553 OnPassphraseRequired(sync_api::REASON_DECRYPTION));
1554 } else if (!cryptographer->is_ready() &&
1555 event.snapshot->initial_sync_ended.test(syncable::NIGORI)) {
1556 VLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
1557 << "ready";
1558 ObserverList<SyncManager::Observer> temp_obs_list;
1559 CopyObservers(&temp_obs_list);
1560 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1561 OnPassphraseRequired(sync_api::REASON_ENCRYPTION));
1562 }
1563
1564 allstatus_.SetCryptographerReady(cryptographer->is_ready());
1565 allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
1566 allstatus_.SetEncryptedTypes(cryptographer->GetEncryptedTypes());
1567
1568 // If everything is in order(we have the passphrase) then there is no
1569 // need to inform the listeners. They will just wait for sync
1570 // completion event and if no errors have been raised it means
1571 // encryption was succesful.
1572 }
1573
1574 if (!initialized_) {
1575 LOG(INFO) << "OnSyncCycleCompleted not sent because sync api is not "
1576 << "initialized";
1577 return;
1578 }
1579
1580 if (!event.snapshot->has_more_to_sync) {
1581 VLOG(1) << "OnSyncCycleCompleted sent";
1582 ObserverList<SyncManager::Observer> temp_obs_list;
1583 CopyObservers(&temp_obs_list);
1584 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1585 OnSyncCycleCompleted(event.snapshot));
1586 }
1587
1588 // This is here for tests, which are still using p2p notifications.
1589 //
1590 // TODO(chron): Consider changing this back to track has_more_to_sync
1591 // only notify peers if a successful commit has occurred.
1592 bool is_notifiable_commit =
1593 (event.snapshot->syncer_status.num_successful_commits > 0);
1594 if (is_notifiable_commit) {
1595 allstatus_.IncrementNotifiableCommits();
1596 if (sync_notifier_.get()) {
1597 sync_notifier_->SendNotification();
1598 } else {
1599 VLOG(1) << "Not sending notification: sync_notifier_ is NULL";
1600 }
1601 }
1602 }
1603
1604 if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
1605 ObserverList<SyncManager::Observer> temp_obs_list;
1606 CopyObservers(&temp_obs_list);
1607 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1608 OnStopSyncingPermanently());
1609 return;
1610 }
1611
1612 if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
1613 ObserverList<SyncManager::Observer> temp_obs_list;
1614 CopyObservers(&temp_obs_list);
1615 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1616 OnClearServerDataSucceeded());
1617 return;
1618 }
1619
1620 if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
1621 ObserverList<SyncManager::Observer> temp_obs_list;
1622 CopyObservers(&temp_obs_list);
1623 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1624 OnClearServerDataFailed());
1625 return;
1626 }
1627
1628 if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
1629 ObserverList<SyncManager::Observer> temp_obs_list;
1630 CopyObservers(&temp_obs_list);
1631 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1632 OnUpdatedToken(event.updated_token));
1633 return;
1634 }
1635 }
1636
1637 void SyncManager::SyncInternal::SetJsEventHandler(
1638 const WeakHandle<JsEventHandler>& event_handler) {
1639 js_event_handler_ = event_handler;
1640 js_sync_manager_observer_.SetJsEventHandler(js_event_handler_);
1641 js_transaction_observer_.SetJsEventHandler(js_event_handler_);
1642 }
1643
1644 void SyncManager::SyncInternal::ProcessJsMessage(
1645 const std::string& name, const JsArgList& args,
1646 const WeakHandle<JsReplyHandler>& reply_handler) {
1647 if (!initialized_) {
1648 NOTREACHED();
1649 return;
1650 }
1651
1652 if (!reply_handler.IsInitialized()) {
1653 VLOG(1) << "Uninitialized reply handler; dropping unknown message "
1654 << name << " with args " << args.ToString();
1655 return;
1656 }
1657
1658 JsMessageHandler js_message_handler = js_message_handlers_[name];
1659 if (js_message_handler.is_null()) {
1660 VLOG(1) << "Dropping unknown message " << name
1661 << " with args " << args.ToString();
1662 return;
1663 }
1664
1665 reply_handler.Call(FROM_HERE,
1666 &JsReplyHandler::HandleJsReply,
1667 name, js_message_handler.Run(args));
1668 }
1669
1670 void SyncManager::SyncInternal::BindJsMessageHandler(
1671 const std::string& name,
1672 UnboundJsMessageHandler unbound_message_handler) {
1673 js_message_handlers_[name] =
1674 base::Bind(unbound_message_handler, base::Unretained(this));
1675 }
1676
1677 DictionaryValue* SyncManager::SyncInternal::NotificationInfoToValue(
1678 const NotificationInfoMap& notification_info) {
1679 DictionaryValue* value = new DictionaryValue();
1680
1681 for (NotificationInfoMap::const_iterator it = notification_info.begin();
1682 it != notification_info.end(); ++it) {
1683 const std::string& model_type_str =
1684 syncable::ModelTypeToString(it->first);
1685 value->Set(model_type_str, it->second.ToValue());
1686 }
1687
1688 return value;
1689 }
1690
1691 JsArgList SyncManager::SyncInternal::GetNotificationState(
1692 const JsArgList& args) {
1693 bool notifications_enabled = allstatus_.status().notifications_enabled;
1694 ListValue return_args;
1695 return_args.Append(Value::CreateBooleanValue(notifications_enabled));
1696 return JsArgList(&return_args);
1697 }
1698
1699 JsArgList SyncManager::SyncInternal::GetNotificationInfo(
1700 const JsArgList& args) {
1701 ListValue return_args;
1702 return_args.Append(NotificationInfoToValue(notification_info_map_));
1703 return JsArgList(&return_args);
1704 }
1705
1706 JsArgList SyncManager::SyncInternal::GetRootNodeDetails(
1707 const JsArgList& args) {
1708 ReadTransaction trans(FROM_HERE, GetUserShare());
1709 ReadNode root(&trans);
1710 root.InitByRootLookup();
1711 ListValue return_args;
1712 return_args.Append(root.GetDetailsAsValue());
1713 return JsArgList(&return_args);
1714 }
1715
1716 namespace {
1717
1718 int64 GetId(const ListValue& ids, int i) {
1719 std::string id_str;
1720 if (!ids.GetString(i, &id_str)) {
1721 return kInvalidId;
1722 }
1723 int64 id = kInvalidId;
1724 if (!base::StringToInt64(id_str, &id)) {
1725 return kInvalidId;
1726 }
1727 return id;
1728 }
1729
1730 JsArgList GetNodeInfoById(const JsArgList& args,
1731 UserShare* user_share,
1732 DictionaryValue* (BaseNode::*info_getter)() const) {
1733 CHECK(info_getter);
1734 ListValue return_args;
1735 ListValue* node_summaries = new ListValue();
1736 return_args.Append(node_summaries);
1737 ListValue* id_list = NULL;
1738 ReadTransaction trans(FROM_HERE, user_share);
1739 if (args.Get().GetList(0, &id_list)) {
1740 CHECK(id_list);
1741 for (size_t i = 0; i < id_list->GetSize(); ++i) {
1742 int64 id = GetId(*id_list, i);
1743 if (id == kInvalidId) {
1744 continue;
1745 }
1746 ReadNode node(&trans);
1747 if (!node.InitByIdLookup(id)) {
1748 continue;
1749 }
1750 node_summaries->Append((node.*info_getter)());
1751 }
1752 }
1753 return JsArgList(&return_args);
1754 }
1755
1756 } // namespace
1757
1758 JsArgList SyncManager::SyncInternal::GetNodeSummariesById(
1759 const JsArgList& args) {
1760 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetSummaryAsValue);
1761 }
1762
1763 JsArgList SyncManager::SyncInternal::GetNodeDetailsById(
1764 const JsArgList& args) {
1765 return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetDetailsAsValue);
1766 }
1767
1768 JsArgList SyncManager::SyncInternal::GetChildNodeIds(
1769 const JsArgList& args) {
1770 ListValue return_args;
1771 ListValue* child_ids = new ListValue();
1772 return_args.Append(child_ids);
1773 int64 id = GetId(args.Get(), 0);
1774 if (id != kInvalidId) {
1775 ReadTransaction trans(FROM_HERE, GetUserShare());
1776 syncable::Directory::ChildHandles child_handles;
1777 trans.GetLookup()->GetChildHandlesByHandle(trans.GetWrappedTrans(),
1778 id, &child_handles);
1779 for (syncable::Directory::ChildHandles::const_iterator it =
1780 child_handles.begin(); it != child_handles.end(); ++it) {
1781 child_ids->Append(Value::CreateStringValue(
1782 base::Int64ToString(*it)));
1783 }
1784 }
1785 return JsArgList(&return_args);
1786 }
1787
1788 JsArgList SyncManager::SyncInternal::FindNodesContainingString(
1789 const JsArgList& args) {
1790 std::string query;
1791 ListValue return_args;
1792 if (!args.Get().GetString(0, &query)) {
1793 return_args.Append(new ListValue());
1794 return JsArgList(&return_args);
1795 }
1796
1797 // Convert the query string to lower case to perform case insensitive
1798 // searches.
1799 std::string lowercase_query = query;
1800 StringToLowerASCII(&lowercase_query);
1801
1802 ListValue* result = new ListValue();
1803 return_args.Append(result);
1804
1805 ReadTransaction trans(FROM_HERE, GetUserShare());
1806 std::vector<const syncable::EntryKernel*> entry_kernels;
1807 trans.GetLookup()->GetAllEntryKernels(trans.GetWrappedTrans(),
1808 &entry_kernels);
1809
1810 for (std::vector<const syncable::EntryKernel*>::const_iterator it =
1811 entry_kernels.begin(); it != entry_kernels.end(); ++it) {
1812 if ((*it)->ContainsString(lowercase_query)) {
1813 result->Append(new StringValue(base::Int64ToString(
1814 (*it)->ref(syncable::META_HANDLE))));
1815 }
1816 }
1817
1818 return JsArgList(&return_args);
1819 }
1820
1821 void SyncManager::SyncInternal::OnNotificationStateChange(
1822 bool notifications_enabled) {
1823 VLOG(1) << "P2P: Notifications enabled = "
1824 << (notifications_enabled ? "true" : "false");
1825 allstatus_.SetNotificationsEnabled(notifications_enabled);
1826 if (scheduler()) {
1827 scheduler()->set_notifications_enabled(notifications_enabled);
1828 }
1829 if (js_event_handler_.IsInitialized()) {
1830 DictionaryValue details;
1831 details.Set("enabled", Value::CreateBooleanValue(notifications_enabled));
1832 js_event_handler_.Call(FROM_HERE,
1833 &JsEventHandler::HandleJsEvent,
1834 "onNotificationStateChange",
1835 JsEventDetails(&details));
1836 }
1837 }
1838
1839 void SyncManager::SyncInternal::UpdateNotificationInfo(
1840 const syncable::ModelTypePayloadMap& type_payloads) {
1841 for (syncable::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
1842 it != type_payloads.end(); ++it) {
1843 NotificationInfo* info = &notification_info_map_[it->first];
1844 info->total_count++;
1845 info->payload = it->second;
1846 }
1847 }
1848
1849 void SyncManager::SyncInternal::OnIncomingNotification(
1850 const syncable::ModelTypePayloadMap& type_payloads) {
1851 if (!type_payloads.empty()) {
1852 if (scheduler()) {
1853 scheduler()->ScheduleNudgeWithPayloads(
1854 TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
1855 browser_sync::NUDGE_SOURCE_NOTIFICATION,
1856 type_payloads, FROM_HERE);
1857 }
1858 allstatus_.IncrementNotificationsReceived();
1859 UpdateNotificationInfo(type_payloads);
1860 } else {
1861 LOG(WARNING) << "Sync received notification without any type information.";
1862 }
1863
1864 if (js_event_handler_.IsInitialized()) {
1865 DictionaryValue details;
1866 ListValue* changed_types = new ListValue();
1867 details.Set("changedTypes", changed_types);
1868 for (syncable::ModelTypePayloadMap::const_iterator
1869 it = type_payloads.begin();
1870 it != type_payloads.end(); ++it) {
1871 const std::string& model_type_str =
1872 syncable::ModelTypeToString(it->first);
1873 changed_types->Append(Value::CreateStringValue(model_type_str));
1874 }
1875 js_event_handler_.Call(FROM_HERE,
1876 &JsEventHandler::HandleJsEvent,
1877 "onIncomingNotification",
1878 JsEventDetails(&details));
1879 }
1880 }
1881
1882 void SyncManager::SyncInternal::StoreState(
1883 const std::string& state) {
1884 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1885 if (!lookup.good()) {
1886 LOG(ERROR) << "Could not write notification state";
1887 // TODO(akalin): Propagate result callback all the way to this
1888 // function and call it with "false" to signal failure.
1889 return;
1890 }
1891 if (VLOG_IS_ON(1)) {
1892 std::string encoded_state;
1893 base::Base64Encode(state, &encoded_state);
1894 VLOG(1) << "Writing notification state: " << encoded_state;
1895 }
1896 lookup->SetNotificationState(state);
1897 lookup->SaveChanges();
1898 }
1899
1900 // Note: it is possible that an observer will remove itself after we have made
1901 // a copy, but before the copy is consumed. This could theoretically result
1902 // in accessing a garbage pointer, but can only occur when an about:sync window
1903 // is closed in the middle of a notification.
1904 // See crbug.com/85481.
1905 void SyncManager::SyncInternal::CopyObservers(
1906 ObserverList<SyncManager::Observer>* observers_copy) {
1907 DCHECK_EQ(0U, observers_copy->size());
1908 base::AutoLock lock(observers_lock_);
1909 if (observers_.size() == 0)
1910 return;
1911 ObserverListBase<SyncManager::Observer>::Iterator it(observers_);
1912 SyncManager::Observer* obs;
1913 while ((obs = it.GetNext()) != NULL)
1914 observers_copy->AddObserver(obs);
1915 }
1916
1917 bool SyncManager::SyncInternal::HaveObservers() const {
1918 base::AutoLock lock(observers_lock_);
1919 return observers_.size() > 0;
1920 }
1921
1922 void SyncManager::SyncInternal::AddObserver(
1923 SyncManager::Observer* observer) {
1924 base::AutoLock lock(observers_lock_);
1925 observers_.AddObserver(observer);
1926 }
1927
1928 void SyncManager::SyncInternal::RemoveObserver(
1929 SyncManager::Observer* observer) {
1930 base::AutoLock lock(observers_lock_);
1931 observers_.RemoveObserver(observer);
1932 }
1933
1934 SyncManager::Status::Summary SyncManager::GetStatusSummary() const {
1935 return data_->GetStatus().summary;
1936 }
1937
1938 SyncManager::Status SyncManager::GetDetailedStatus() const {
1939 return data_->GetStatus();
1940 }
1941
1942 SyncManager::SyncInternal* SyncManager::GetImpl() const { return data_; }
1943
1944 void SyncManager::SaveChanges() {
1945 data_->SaveChanges();
1946 }
1947
1948 void SyncManager::SyncInternal::SaveChanges() {
1949 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1950 if (!lookup.good()) {
1951 DCHECK(false) << "ScopedDirLookup creation failed; Unable to SaveChanges";
1952 return;
1953 }
1954 lookup->SaveChanges();
1955 }
1956
1957 UserShare* SyncManager::GetUserShare() const {
1958 return data_->GetUserShare();
1959 }
1960
1961 void SyncManager::RefreshEncryption() {
1962 if (data_->UpdateCryptographerFromNigori())
1963 data_->EncryptDataTypes(syncable::ModelTypeSet());
1964 }
1965
1966 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypes() const {
1967 sync_api::ReadTransaction trans(FROM_HERE, GetUserShare());
1968 return GetEncryptedTypes(&trans);
1969 }
1970
1971 bool SyncManager::HasUnsyncedItems() const {
1972 sync_api::ReadTransaction trans(FROM_HERE, GetUserShare());
1973 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
1974 }
1975
1976 void SyncManager::LogUnsyncedItems(int level) const {
1977 std::vector<int64> unsynced_handles;
1978 sync_api::ReadTransaction trans(FROM_HERE, GetUserShare());
1979 trans.GetWrappedTrans()->directory()->GetUnsyncedMetaHandles(
1980 trans.GetWrappedTrans(), &unsynced_handles);
1981
1982 for (std::vector<int64>::const_iterator it = unsynced_handles.begin();
1983 it != unsynced_handles.end(); ++it) {
1984 ReadNode node(&trans);
1985 if (node.InitByIdLookup(*it)) {
1986 scoped_ptr<DictionaryValue> value(node.GetDetailsAsValue());
1987 std::string info;
1988 base::JSONWriter::Write(value.get(), true, &info);
1989 VLOG(level) << info;
1990 }
1991 }
1992 }
1993
1994 void SyncManager::TriggerOnNotificationStateChangeForTest(
1995 bool notifications_enabled) {
1996 data_->OnNotificationStateChange(notifications_enabled);
1997 }
1998
1999 void SyncManager::TriggerOnIncomingNotificationForTest(
2000 const syncable::ModelTypeBitSet& model_types) {
2001 syncable::ModelTypePayloadMap model_types_with_payloads =
2002 syncable::ModelTypePayloadMapFromBitSet(model_types,
2003 std::string());
2004
2005 data_->OnIncomingNotification(model_types_with_payloads);
2006 }
2007
2008 } // namespace sync_api
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698