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

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

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

Powered by Google App Engine
This is Rietveld 408576698