• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/syncapi.h"
6 
7 #include <algorithm>
8 #include <bitset>
9 #include <iomanip>
10 #include <list>
11 #include <queue>
12 #include <string>
13 #include <vector>
14 
15 #include "base/base64.h"
16 #include "base/command_line.h"
17 #include "base/logging.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/message_loop.h"
20 #include "base/observer_list.h"
21 #include "base/sha1.h"
22 #include "base/string_number_conversions.h"
23 #include "base/string_util.h"
24 #include "base/synchronization/lock.h"
25 #include "base/task.h"
26 #include "base/time.h"
27 #include "base/utf_string_conversions.h"
28 #include "base/values.h"
29 #include "chrome/browser/sync/engine/all_status.h"
30 #include "chrome/browser/sync/engine/change_reorder_buffer.h"
31 #include "chrome/browser/sync/engine/model_safe_worker.h"
32 #include "chrome/browser/sync/engine/nudge_source.h"
33 #include "chrome/browser/sync/engine/net/server_connection_manager.h"
34 #include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h"
35 #include "chrome/browser/sync/engine/syncer.h"
36 #include "chrome/browser/sync/engine/syncer_thread.h"
37 #include "chrome/browser/sync/engine/http_post_provider_factory.h"
38 #include "chrome/browser/sync/js_arg_list.h"
39 #include "chrome/browser/sync/js_backend.h"
40 #include "chrome/browser/sync/js_event_router.h"
41 #include "chrome/browser/sync/notifier/sync_notifier.h"
42 #include "chrome/browser/sync/notifier/sync_notifier_observer.h"
43 #include "chrome/browser/sync/protocol/app_specifics.pb.h"
44 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
45 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
46 #include "chrome/browser/sync/protocol/extension_specifics.pb.h"
47 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
48 #include "chrome/browser/sync/protocol/preference_specifics.pb.h"
49 #include "chrome/browser/sync/protocol/proto_value_conversions.h"
50 #include "chrome/browser/sync/protocol/service_constants.h"
51 #include "chrome/browser/sync/protocol/session_specifics.pb.h"
52 #include "chrome/browser/sync/protocol/sync.pb.h"
53 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
54 #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
55 #include "chrome/browser/sync/sessions/sync_session.h"
56 #include "chrome/browser/sync/sessions/sync_session_context.h"
57 #include "chrome/browser/sync/syncable/autofill_migration.h"
58 #include "chrome/browser/sync/syncable/directory_change_listener.h"
59 #include "chrome/browser/sync/syncable/directory_manager.h"
60 #include "chrome/browser/sync/syncable/model_type_payload_map.h"
61 #include "chrome/browser/sync/syncable/model_type.h"
62 #include "chrome/browser/sync/syncable/nigori_util.h"
63 #include "chrome/browser/sync/syncable/syncable.h"
64 #include "chrome/browser/sync/util/crypto_helpers.h"
65 #include "chrome/common/chrome_switches.h"
66 #include "chrome/common/deprecated/event_sys.h"
67 #include "chrome/common/net/gaia/gaia_authenticator.h"
68 #include "content/browser/browser_thread.h"
69 #include "net/base/network_change_notifier.h"
70 
71 using base::TimeDelta;
72 using browser_sync::AllStatus;
73 using browser_sync::Cryptographer;
74 using browser_sync::KeyParams;
75 using browser_sync::ModelSafeRoutingInfo;
76 using browser_sync::ModelSafeWorker;
77 using browser_sync::ModelSafeWorkerRegistrar;
78 using browser_sync::ServerConnectionEvent;
79 using browser_sync::ServerConnectionEvent2;
80 using browser_sync::ServerConnectionEventListener;
81 using browser_sync::SyncEngineEvent;
82 using browser_sync::SyncEngineEventListener;
83 using browser_sync::Syncer;
84 using browser_sync::SyncerThread;
85 using browser_sync::kNigoriTag;
86 using browser_sync::sessions::SyncSessionContext;
87 using std::list;
88 using std::hex;
89 using std::string;
90 using std::vector;
91 using syncable::Directory;
92 using syncable::DirectoryManager;
93 using syncable::Entry;
94 using syncable::ModelTypeBitSet;
95 using syncable::OriginalEntries;
96 using syncable::WriterTag;
97 using syncable::SPECIFICS;
98 using sync_pb::AutofillProfileSpecifics;
99 
100 typedef GoogleServiceAuthError AuthError;
101 
102 static const int kThreadExitTimeoutMsec = 60000;
103 static const int kSSLPort = 443;
104 static const int kSyncerThreadDelayMsec = 250;
105 
106 #if defined(OS_CHROMEOS)
107 static const int kChromeOSNetworkChangeReactionDelayHackMsec = 5000;
108 #endif  // OS_CHROMEOS
109 
110 // We manage the lifetime of sync_api::SyncManager::SyncInternal ourselves.
111 DISABLE_RUNNABLE_METHOD_REFCOUNT(sync_api::SyncManager::SyncInternal);
112 
113 namespace sync_api {
114 
115 static const FilePath::CharType kBookmarkSyncUserSettingsDatabase[] =
116     FILE_PATH_LITERAL("BookmarkSyncSettings.sqlite3");
117 static const char kDefaultNameForNewNodes[] = " ";
118 
119 // The list of names which are reserved for use by the server.
120 static const char* kForbiddenServerNames[] = { "", ".", ".." };
121 
122 //////////////////////////////////////////////////////////////////////////
123 // Static helper functions.
124 
125 // Helper function to look up the int64 metahandle of an object given the ID
126 // string.
IdToMetahandle(syncable::BaseTransaction * trans,const syncable::Id & id)127 static int64 IdToMetahandle(syncable::BaseTransaction* trans,
128                             const syncable::Id& id) {
129   syncable::Entry entry(trans, syncable::GET_BY_ID, id);
130   if (!entry.good())
131     return kInvalidId;
132   return entry.Get(syncable::META_HANDLE);
133 }
134 
135 // Checks whether |name| is a server-illegal name followed by zero or more space
136 // characters.  The three server-illegal names are the empty string, dot, and
137 // dot-dot.  Very long names (>255 bytes in UTF-8 Normalization Form C) are
138 // also illegal, but are not considered here.
IsNameServerIllegalAfterTrimming(const std::string & name)139 static bool IsNameServerIllegalAfterTrimming(const std::string& name) {
140   size_t untrimmed_count = name.find_last_not_of(' ') + 1;
141   for (size_t i = 0; i < arraysize(kForbiddenServerNames); ++i) {
142     if (name.compare(0, untrimmed_count, kForbiddenServerNames[i]) == 0)
143       return true;
144   }
145   return false;
146 }
147 
EndsWithSpace(const std::string & string)148 static bool EndsWithSpace(const std::string& string) {
149   return !string.empty() && *string.rbegin() == ' ';
150 }
151 
152 // When taking a name from the syncapi, append a space if it matches the
153 // pattern of a server-illegal name followed by zero or more spaces.
SyncAPINameToServerName(const std::wstring & sync_api_name,std::string * out)154 static void SyncAPINameToServerName(const std::wstring& sync_api_name,
155                                     std::string* out) {
156   *out = WideToUTF8(sync_api_name);
157   if (IsNameServerIllegalAfterTrimming(*out))
158     out->append(" ");
159 }
160 
161 // In the reverse direction, if a server name matches the pattern of a
162 // server-illegal name followed by one or more spaces, remove the trailing
163 // space.
ServerNameToSyncAPIName(const std::string & server_name,std::wstring * out)164 static void ServerNameToSyncAPIName(const std::string& server_name,
165                                     std::wstring* out) {
166   int length_to_copy = server_name.length();
167   if (IsNameServerIllegalAfterTrimming(server_name) &&
168       EndsWithSpace(server_name))
169     --length_to_copy;
170   if (!UTF8ToWide(server_name.c_str(), length_to_copy, out)) {
171     NOTREACHED() << "Could not convert server name from UTF8 to wide";
172   }
173 }
174 
UserShare()175 UserShare::UserShare() {}
176 
~UserShare()177 UserShare::~UserShare() {}
178 
179 ////////////////////////////////////
180 // BaseNode member definitions.
181 
BaseNode()182 BaseNode::BaseNode() {}
183 
~BaseNode()184 BaseNode::~BaseNode() {}
185 
GenerateSyncableHash(syncable::ModelType model_type,const std::string & client_tag)186 std::string BaseNode::GenerateSyncableHash(
187     syncable::ModelType model_type, const std::string& client_tag) {
188   // blank PB with just the extension in it has termination symbol,
189   // handy for delimiter
190   sync_pb::EntitySpecifics serialized_type;
191   syncable::AddDefaultExtensionValue(model_type, &serialized_type);
192   std::string hash_input;
193   serialized_type.AppendToString(&hash_input);
194   hash_input.append(client_tag);
195 
196   std::string encode_output;
197   CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output));
198   return encode_output;
199 }
200 
DecryptPasswordSpecifics(const sync_pb::EntitySpecifics & specifics,Cryptographer * crypto)201 sync_pb::PasswordSpecificsData* DecryptPasswordSpecifics(
202     const sync_pb::EntitySpecifics& specifics, Cryptographer* crypto) {
203   if (!specifics.HasExtension(sync_pb::password))
204     return NULL;
205   const sync_pb::PasswordSpecifics& password_specifics =
206       specifics.GetExtension(sync_pb::password);
207   if (!password_specifics.has_encrypted())
208     return NULL;
209   const sync_pb::EncryptedData& encrypted = password_specifics.encrypted();
210   scoped_ptr<sync_pb::PasswordSpecificsData> data(
211       new sync_pb::PasswordSpecificsData);
212   if (!crypto->Decrypt(encrypted, data.get()))
213     return NULL;
214   return data.release();
215 }
216 
DecryptIfNecessary(Entry * entry)217 bool BaseNode::DecryptIfNecessary(Entry* entry) {
218   if (GetIsFolder()) return true;  // Ignore the top-level datatype folder.
219   const sync_pb::EntitySpecifics& specifics =
220       entry->Get(syncable::SPECIFICS);
221   if (specifics.HasExtension(sync_pb::password)) {
222     // Passwords have their own legacy encryption structure.
223     scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
224         specifics, GetTransaction()->GetCryptographer()));
225     if (!data.get())
226       return false;
227     password_data_.swap(data);
228     return true;
229   }
230 
231   // We assume any node with the encrypted field set has encrypted data.
232   if (!specifics.has_encrypted())
233     return true;
234 
235   const sync_pb::EncryptedData& encrypted =
236       specifics.encrypted();
237   std::string plaintext_data = GetTransaction()->GetCryptographer()->
238       DecryptToString(encrypted);
239   if (plaintext_data.length() == 0)
240     return false;
241   if (!unencrypted_data_.ParseFromString(plaintext_data)) {
242     LOG(ERROR) << "Failed to decrypt encrypted node of type " <<
243       syncable::ModelTypeToString(entry->GetModelType()) << ".";
244     return false;
245   }
246   return true;
247 }
248 
GetUnencryptedSpecifics(const syncable::Entry * entry) const249 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics(
250     const syncable::Entry* entry) const {
251   const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS);
252   if (specifics.has_encrypted()) {
253     DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) !=
254            syncable::UNSPECIFIED);
255     return unencrypted_data_;
256   } else {
257     DCHECK(syncable::GetModelTypeFromSpecifics(unencrypted_data_) ==
258            syncable::UNSPECIFIED);
259     return specifics;
260   }
261 }
262 
GetParentId() const263 int64 BaseNode::GetParentId() const {
264   return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
265                         GetEntry()->Get(syncable::PARENT_ID));
266 }
267 
GetId() const268 int64 BaseNode::GetId() const {
269   return GetEntry()->Get(syncable::META_HANDLE);
270 }
271 
GetModificationTime() const272 int64 BaseNode::GetModificationTime() const {
273   return GetEntry()->Get(syncable::MTIME);
274 }
275 
GetIsFolder() const276 bool BaseNode::GetIsFolder() const {
277   return GetEntry()->Get(syncable::IS_DIR);
278 }
279 
GetTitle() const280 std::wstring BaseNode::GetTitle() const {
281   std::wstring result;
282   ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME), &result);
283   return result;
284 }
285 
GetURL() const286 GURL BaseNode::GetURL() const {
287   return GURL(GetBookmarkSpecifics().url());
288 }
289 
GetPredecessorId() const290 int64 BaseNode::GetPredecessorId() const {
291   syncable::Id id_string = GetEntry()->Get(syncable::PREV_ID);
292   if (id_string.IsRoot())
293     return kInvalidId;
294   return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
295 }
296 
GetSuccessorId() const297 int64 BaseNode::GetSuccessorId() const {
298   syncable::Id id_string = GetEntry()->Get(syncable::NEXT_ID);
299   if (id_string.IsRoot())
300     return kInvalidId;
301   return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
302 }
303 
GetFirstChildId() const304 int64 BaseNode::GetFirstChildId() const {
305   syncable::Directory* dir = GetTransaction()->GetLookup();
306   syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
307   syncable::Id id_string =
308       dir->GetFirstChildId(trans, GetEntry()->Get(syncable::ID));
309   if (id_string.IsRoot())
310     return kInvalidId;
311   return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
312 }
313 
ToValue() const314 DictionaryValue* BaseNode::ToValue() const {
315   DictionaryValue* node_info = new DictionaryValue();
316   node_info->SetString("id", base::Int64ToString(GetId()));
317   // TODO(akalin): Return time in a better format.
318   node_info->SetString("modificationTime",
319                        base::Int64ToString(GetModificationTime()));
320   node_info->SetString("parentId", base::Int64ToString(GetParentId()));
321   node_info->SetBoolean("isFolder", GetIsFolder());
322   // TODO(akalin): Add a std::string accessor for the title.
323   node_info->SetString("title", WideToUTF8(GetTitle()));
324   node_info->Set("type", ModelTypeToValue(GetModelType()));
325   // Specifics are already in the Entry value, so no need to duplicate
326   // it here.
327   node_info->SetString("externalId",
328                        base::Int64ToString(GetExternalId()));
329   node_info->SetString("predecessorId",
330                        base::Int64ToString(GetPredecessorId()));
331   node_info->SetString("successorId",
332                        base::Int64ToString(GetSuccessorId()));
333   node_info->SetString("firstChildId",
334                        base::Int64ToString(GetFirstChildId()));
335   node_info->Set("entry", GetEntry()->ToValue());
336   return node_info;
337 }
338 
GetFaviconBytes(std::vector<unsigned char> * output) const339 void BaseNode::GetFaviconBytes(std::vector<unsigned char>* output) const {
340   if (!output)
341     return;
342   const std::string& favicon = GetBookmarkSpecifics().favicon();
343   output->assign(reinterpret_cast<const unsigned char*>(favicon.data()),
344       reinterpret_cast<const unsigned char*>(favicon.data() +
345                                              favicon.length()));
346 }
347 
GetExternalId() const348 int64 BaseNode::GetExternalId() const {
349   return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
350 }
351 
GetAppSpecifics() const352 const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
353   DCHECK_EQ(syncable::APPS, GetModelType());
354   const sync_pb::EntitySpecifics& unencrypted =
355       GetUnencryptedSpecifics(GetEntry());
356   return unencrypted.GetExtension(sync_pb::app);
357 }
358 
GetAutofillSpecifics() const359 const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
360   DCHECK_EQ(syncable::AUTOFILL, GetModelType());
361   const sync_pb::EntitySpecifics& unencrypted =
362       GetUnencryptedSpecifics(GetEntry());
363   return unencrypted.GetExtension(sync_pb::autofill);
364 }
365 
GetAutofillProfileSpecifics() const366 const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const {
367   DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
368   const sync_pb::EntitySpecifics& unencrypted =
369       GetUnencryptedSpecifics(GetEntry());
370   return unencrypted.GetExtension(sync_pb::autofill_profile);
371 }
372 
GetBookmarkSpecifics() const373 const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
374   DCHECK_EQ(syncable::BOOKMARKS, GetModelType());
375   const sync_pb::EntitySpecifics& unencrypted =
376       GetUnencryptedSpecifics(GetEntry());
377   return unencrypted.GetExtension(sync_pb::bookmark);
378 }
379 
GetNigoriSpecifics() const380 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
381   DCHECK_EQ(syncable::NIGORI, GetModelType());
382   const sync_pb::EntitySpecifics& unencrypted =
383       GetUnencryptedSpecifics(GetEntry());
384   return unencrypted.GetExtension(sync_pb::nigori);
385 }
386 
GetPasswordSpecifics() const387 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
388   DCHECK_EQ(syncable::PASSWORDS, GetModelType());
389   DCHECK(password_data_.get());
390   return *password_data_;
391 }
392 
GetPreferenceSpecifics() const393 const sync_pb::PreferenceSpecifics& BaseNode::GetPreferenceSpecifics() const {
394   DCHECK_EQ(syncable::PREFERENCES, GetModelType());
395   const sync_pb::EntitySpecifics& unencrypted =
396       GetUnencryptedSpecifics(GetEntry());
397   return unencrypted.GetExtension(sync_pb::preference);
398 }
399 
GetThemeSpecifics() const400 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
401   DCHECK_EQ(syncable::THEMES, GetModelType());
402   const sync_pb::EntitySpecifics& unencrypted =
403       GetUnencryptedSpecifics(GetEntry());
404   return unencrypted.GetExtension(sync_pb::theme);
405 }
406 
GetTypedUrlSpecifics() const407 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
408   DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
409   const sync_pb::EntitySpecifics& unencrypted =
410       GetUnencryptedSpecifics(GetEntry());
411   return unencrypted.GetExtension(sync_pb::typed_url);
412 }
413 
GetExtensionSpecifics() const414 const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
415   DCHECK_EQ(syncable::EXTENSIONS, GetModelType());
416   const sync_pb::EntitySpecifics& unencrypted =
417       GetUnencryptedSpecifics(GetEntry());
418   return unencrypted.GetExtension(sync_pb::extension);
419 }
420 
GetSessionSpecifics() const421 const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
422   DCHECK_EQ(syncable::SESSIONS, GetModelType());
423   const sync_pb::EntitySpecifics& unencrypted =
424       GetUnencryptedSpecifics(GetEntry());
425   return unencrypted.GetExtension(sync_pb::session);
426 }
427 
GetModelType() const428 syncable::ModelType BaseNode::GetModelType() const {
429   return GetEntry()->GetModelType();
430 }
431 
432 ////////////////////////////////////
433 // WriteNode member definitions
EncryptIfNecessary(sync_pb::EntitySpecifics * unencrypted)434 void WriteNode::EncryptIfNecessary(sync_pb::EntitySpecifics* unencrypted) {
435   syncable::ModelType type = syncable::GetModelTypeFromSpecifics(*unencrypted);
436   DCHECK_NE(type, syncable::UNSPECIFIED);
437   DCHECK_NE(type, syncable::PASSWORDS);  // Passwords use their own encryption.
438   DCHECK_NE(type, syncable::NIGORI);     // Nigori is encrypted separately.
439 
440   syncable::ModelTypeSet encrypted_types =
441       GetEncryptedDataTypes(GetTransaction()->GetWrappedTrans());
442   if (encrypted_types.count(type) == 0) {
443     // This datatype does not require encryption.
444     return;
445   }
446 
447   if (unencrypted->has_encrypted()) {
448     // This specifics is already encrypted, our work is done.
449     LOG(WARNING) << "Attempted to encrypt an already encrypted entity"
450       << " specifics of type " << syncable::ModelTypeToString(type)
451       << ". Dropping.";
452     return;
453   }
454   sync_pb::EntitySpecifics encrypted;
455   syncable::AddDefaultExtensionValue(type, &encrypted);
456   VLOG(2) << "Encrypted specifics of type " << syncable::ModelTypeToString(type)
457           << " with content: " << unencrypted->SerializeAsString() << "\n";
458   if (!GetTransaction()->GetCryptographer()->Encrypt(
459       *unencrypted,
460       encrypted.mutable_encrypted())) {
461     LOG(ERROR) << "Could not encrypt data for node of type " <<
462       syncable::ModelTypeToString(type);
463     NOTREACHED();
464   }
465   unencrypted->CopyFrom(encrypted);
466 }
467 
SetIsFolder(bool folder)468 void WriteNode::SetIsFolder(bool folder) {
469   if (entry_->Get(syncable::IS_DIR) == folder)
470     return;  // Skip redundant changes.
471 
472   entry_->Put(syncable::IS_DIR, folder);
473   MarkForSyncing();
474 }
475 
SetTitle(const std::wstring & title)476 void WriteNode::SetTitle(const std::wstring& title) {
477   std::string server_legal_name;
478   SyncAPINameToServerName(title, &server_legal_name);
479 
480   string old_name = entry_->Get(syncable::NON_UNIQUE_NAME);
481 
482   if (server_legal_name == old_name)
483     return;  // Skip redundant changes.
484 
485   entry_->Put(syncable::NON_UNIQUE_NAME, server_legal_name);
486   MarkForSyncing();
487 }
488 
SetURL(const GURL & url)489 void WriteNode::SetURL(const GURL& url) {
490   sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
491   new_value.set_url(url.spec());
492   SetBookmarkSpecifics(new_value);
493 }
494 
SetAppSpecifics(const sync_pb::AppSpecifics & new_value)495 void WriteNode::SetAppSpecifics(
496     const sync_pb::AppSpecifics& new_value) {
497   DCHECK_EQ(syncable::APPS, GetModelType());
498   PutAppSpecificsAndMarkForSyncing(new_value);
499 }
500 
SetAutofillSpecifics(const sync_pb::AutofillSpecifics & new_value)501 void WriteNode::SetAutofillSpecifics(
502     const sync_pb::AutofillSpecifics& new_value) {
503   DCHECK_EQ(syncable::AUTOFILL, GetModelType());
504   PutAutofillSpecificsAndMarkForSyncing(new_value);
505 }
506 
PutAutofillSpecificsAndMarkForSyncing(const sync_pb::AutofillSpecifics & new_value)507 void WriteNode::PutAutofillSpecificsAndMarkForSyncing(
508     const sync_pb::AutofillSpecifics& new_value) {
509   sync_pb::EntitySpecifics entity_specifics;
510   entity_specifics.MutableExtension(sync_pb::autofill)->CopyFrom(new_value);
511   EncryptIfNecessary(&entity_specifics);
512   PutSpecificsAndMarkForSyncing(entity_specifics);
513 }
514 
SetAutofillProfileSpecifics(const sync_pb::AutofillProfileSpecifics & new_value)515 void WriteNode::SetAutofillProfileSpecifics(
516     const sync_pb::AutofillProfileSpecifics& new_value) {
517   DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
518   PutAutofillProfileSpecificsAndMarkForSyncing(new_value);
519 }
520 
PutAutofillProfileSpecificsAndMarkForSyncing(const sync_pb::AutofillProfileSpecifics & new_value)521 void WriteNode::PutAutofillProfileSpecificsAndMarkForSyncing(
522     const sync_pb::AutofillProfileSpecifics& new_value) {
523   sync_pb::EntitySpecifics entity_specifics;
524   entity_specifics.MutableExtension(sync_pb::autofill_profile)->CopyFrom(
525       new_value);
526   EncryptIfNecessary(&entity_specifics);
527   PutSpecificsAndMarkForSyncing(entity_specifics);
528 }
529 
SetBookmarkSpecifics(const sync_pb::BookmarkSpecifics & new_value)530 void WriteNode::SetBookmarkSpecifics(
531     const sync_pb::BookmarkSpecifics& new_value) {
532   DCHECK_EQ(syncable::BOOKMARKS, GetModelType());
533   PutBookmarkSpecificsAndMarkForSyncing(new_value);
534 }
535 
PutBookmarkSpecificsAndMarkForSyncing(const sync_pb::BookmarkSpecifics & new_value)536 void WriteNode::PutBookmarkSpecificsAndMarkForSyncing(
537     const sync_pb::BookmarkSpecifics& new_value) {
538   sync_pb::EntitySpecifics entity_specifics;
539   entity_specifics.MutableExtension(sync_pb::bookmark)->CopyFrom(new_value);
540   EncryptIfNecessary(&entity_specifics);
541   PutSpecificsAndMarkForSyncing(entity_specifics);
542 }
543 
SetNigoriSpecifics(const sync_pb::NigoriSpecifics & new_value)544 void WriteNode::SetNigoriSpecifics(
545     const sync_pb::NigoriSpecifics& new_value) {
546   DCHECK_EQ(syncable::NIGORI, GetModelType());
547   PutNigoriSpecificsAndMarkForSyncing(new_value);
548 }
549 
PutNigoriSpecificsAndMarkForSyncing(const sync_pb::NigoriSpecifics & new_value)550 void WriteNode::PutNigoriSpecificsAndMarkForSyncing(
551     const sync_pb::NigoriSpecifics& new_value) {
552   sync_pb::EntitySpecifics entity_specifics;
553   entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value);
554   PutSpecificsAndMarkForSyncing(entity_specifics);
555 }
556 
SetPasswordSpecifics(const sync_pb::PasswordSpecificsData & data)557 void WriteNode::SetPasswordSpecifics(
558     const sync_pb::PasswordSpecificsData& data) {
559   DCHECK_EQ(syncable::PASSWORDS, GetModelType());
560 
561   Cryptographer* cryptographer = GetTransaction()->GetCryptographer();
562 
563   // Idempotency check to prevent unnecessary syncing: if the plaintexts match
564   // and the old ciphertext is encrypted with the most current key, there's
565   // nothing to do here.  Because each encryption is seeded with a different
566   // random value, checking for equivalence post-encryption doesn't suffice.
567   const sync_pb::EncryptedData& old_ciphertext =
568       GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::password).encrypted();
569   scoped_ptr<sync_pb::PasswordSpecificsData> old_plaintext(
570       DecryptPasswordSpecifics(GetEntry()->Get(SPECIFICS), cryptographer));
571   if (old_plaintext.get() &&
572       old_plaintext->SerializeAsString() == data.SerializeAsString() &&
573       cryptographer->CanDecryptUsingDefaultKey(old_ciphertext)) {
574     return;
575   }
576 
577   sync_pb::PasswordSpecifics new_value;
578   if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) {
579     NOTREACHED();
580   }
581   PutPasswordSpecificsAndMarkForSyncing(new_value);
582 }
583 
SetPreferenceSpecifics(const sync_pb::PreferenceSpecifics & new_value)584 void WriteNode::SetPreferenceSpecifics(
585     const sync_pb::PreferenceSpecifics& new_value) {
586   DCHECK_EQ(syncable::PREFERENCES, GetModelType());
587   PutPreferenceSpecificsAndMarkForSyncing(new_value);
588 }
589 
SetThemeSpecifics(const sync_pb::ThemeSpecifics & new_value)590 void WriteNode::SetThemeSpecifics(
591     const sync_pb::ThemeSpecifics& new_value) {
592   DCHECK_EQ(syncable::THEMES, GetModelType());
593   PutThemeSpecificsAndMarkForSyncing(new_value);
594 }
595 
SetSessionSpecifics(const sync_pb::SessionSpecifics & new_value)596 void WriteNode::SetSessionSpecifics(
597     const sync_pb::SessionSpecifics& new_value) {
598   DCHECK_EQ(syncable::SESSIONS, GetModelType());
599   PutSessionSpecificsAndMarkForSyncing(new_value);
600 }
601 
ResetFromSpecifics()602 void WriteNode::ResetFromSpecifics() {
603   sync_pb::EntitySpecifics new_data;
604   new_data.CopyFrom(GetUnencryptedSpecifics(GetEntry()));
605   EncryptIfNecessary(&new_data);
606   PutSpecificsAndMarkForSyncing(new_data);
607 }
608 
PutPasswordSpecificsAndMarkForSyncing(const sync_pb::PasswordSpecifics & new_value)609 void WriteNode::PutPasswordSpecificsAndMarkForSyncing(
610     const sync_pb::PasswordSpecifics& new_value) {
611   sync_pb::EntitySpecifics entity_specifics;
612   entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value);
613   PutSpecificsAndMarkForSyncing(entity_specifics);
614 }
615 
PutPreferenceSpecificsAndMarkForSyncing(const sync_pb::PreferenceSpecifics & new_value)616 void WriteNode::PutPreferenceSpecificsAndMarkForSyncing(
617     const sync_pb::PreferenceSpecifics& new_value) {
618   sync_pb::EntitySpecifics entity_specifics;
619   entity_specifics.MutableExtension(sync_pb::preference)->CopyFrom(new_value);
620   EncryptIfNecessary(&entity_specifics);
621   PutSpecificsAndMarkForSyncing(entity_specifics);
622 }
623 
SetTypedUrlSpecifics(const sync_pb::TypedUrlSpecifics & new_value)624 void WriteNode::SetTypedUrlSpecifics(
625     const sync_pb::TypedUrlSpecifics& new_value) {
626   DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
627   PutTypedUrlSpecificsAndMarkForSyncing(new_value);
628 }
629 
SetExtensionSpecifics(const sync_pb::ExtensionSpecifics & new_value)630 void WriteNode::SetExtensionSpecifics(
631     const sync_pb::ExtensionSpecifics& new_value) {
632   DCHECK_EQ(syncable::EXTENSIONS, GetModelType());
633   PutExtensionSpecificsAndMarkForSyncing(new_value);
634 }
635 
PutAppSpecificsAndMarkForSyncing(const sync_pb::AppSpecifics & new_value)636 void WriteNode::PutAppSpecificsAndMarkForSyncing(
637     const sync_pb::AppSpecifics& new_value) {
638   sync_pb::EntitySpecifics entity_specifics;
639   entity_specifics.MutableExtension(sync_pb::app)->CopyFrom(new_value);
640   EncryptIfNecessary(&entity_specifics);
641   PutSpecificsAndMarkForSyncing(entity_specifics);
642 }
643 
PutThemeSpecificsAndMarkForSyncing(const sync_pb::ThemeSpecifics & new_value)644 void WriteNode::PutThemeSpecificsAndMarkForSyncing(
645     const sync_pb::ThemeSpecifics& new_value) {
646   sync_pb::EntitySpecifics entity_specifics;
647   entity_specifics.MutableExtension(sync_pb::theme)->CopyFrom(new_value);
648   EncryptIfNecessary(&entity_specifics);
649   PutSpecificsAndMarkForSyncing(entity_specifics);
650 }
651 
PutTypedUrlSpecificsAndMarkForSyncing(const sync_pb::TypedUrlSpecifics & new_value)652 void WriteNode::PutTypedUrlSpecificsAndMarkForSyncing(
653     const sync_pb::TypedUrlSpecifics& new_value) {
654   sync_pb::EntitySpecifics entity_specifics;
655   entity_specifics.MutableExtension(sync_pb::typed_url)->CopyFrom(new_value);
656   EncryptIfNecessary(&entity_specifics);
657   PutSpecificsAndMarkForSyncing(entity_specifics);
658 }
659 
PutExtensionSpecificsAndMarkForSyncing(const sync_pb::ExtensionSpecifics & new_value)660 void WriteNode::PutExtensionSpecificsAndMarkForSyncing(
661     const sync_pb::ExtensionSpecifics& new_value) {
662   sync_pb::EntitySpecifics entity_specifics;
663   entity_specifics.MutableExtension(sync_pb::extension)->CopyFrom(new_value);
664   EncryptIfNecessary(&entity_specifics);
665   PutSpecificsAndMarkForSyncing(entity_specifics);
666 }
667 
PutSessionSpecificsAndMarkForSyncing(const sync_pb::SessionSpecifics & new_value)668 void WriteNode::PutSessionSpecificsAndMarkForSyncing(
669     const sync_pb::SessionSpecifics& new_value) {
670   sync_pb::EntitySpecifics entity_specifics;
671   entity_specifics.MutableExtension(sync_pb::session)->CopyFrom(new_value);
672   EncryptIfNecessary(&entity_specifics);
673   PutSpecificsAndMarkForSyncing(entity_specifics);
674 }
675 
PutSpecificsAndMarkForSyncing(const sync_pb::EntitySpecifics & specifics)676 void WriteNode::PutSpecificsAndMarkForSyncing(
677     const sync_pb::EntitySpecifics& specifics) {
678   // Skip redundant changes.
679   if (specifics.SerializeAsString() ==
680       entry_->Get(SPECIFICS).SerializeAsString()) {
681     return;
682   }
683   entry_->Put(SPECIFICS, specifics);
684   MarkForSyncing();
685 }
686 
SetExternalId(int64 id)687 void WriteNode::SetExternalId(int64 id) {
688   if (GetExternalId() != id)
689     entry_->Put(syncable::LOCAL_EXTERNAL_ID, id);
690 }
691 
WriteNode(WriteTransaction * transaction)692 WriteNode::WriteNode(WriteTransaction* transaction)
693     : entry_(NULL), transaction_(transaction) {
694   DCHECK(transaction);
695 }
696 
~WriteNode()697 WriteNode::~WriteNode() {
698   delete entry_;
699 }
700 
701 // Find an existing node matching the ID |id|, and bind this WriteNode to it.
702 // Return true on success.
InitByIdLookup(int64 id)703 bool WriteNode::InitByIdLookup(int64 id) {
704   DCHECK(!entry_) << "Init called twice";
705   DCHECK_NE(id, kInvalidId);
706   entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
707                                       syncable::GET_BY_HANDLE, id);
708   return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
709           DecryptIfNecessary(entry_));
710 }
711 
712 // Find a node by client tag, and bind this WriteNode to it.
713 // Return true if the write node was found, and was not deleted.
714 // Undeleting a deleted node is possible by ClientTag.
InitByClientTagLookup(syncable::ModelType model_type,const std::string & tag)715 bool WriteNode::InitByClientTagLookup(syncable::ModelType model_type,
716                                       const std::string& tag) {
717   DCHECK(!entry_) << "Init called twice";
718   if (tag.empty())
719     return false;
720 
721   const std::string hash = GenerateSyncableHash(model_type, tag);
722 
723   entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
724                                       syncable::GET_BY_CLIENT_TAG, hash);
725   return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
726           DecryptIfNecessary(entry_));
727 }
728 
InitByTagLookup(const std::string & tag)729 bool WriteNode::InitByTagLookup(const std::string& tag) {
730   DCHECK(!entry_) << "Init called twice";
731   if (tag.empty())
732     return false;
733   entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
734                                       syncable::GET_BY_SERVER_TAG, tag);
735   if (!entry_->good())
736     return false;
737   if (entry_->Get(syncable::IS_DEL))
738     return false;
739   syncable::ModelType model_type = GetModelType();
740   DCHECK_EQ(syncable::NIGORI, model_type);
741   return true;
742 }
743 
PutModelType(syncable::ModelType model_type)744 void WriteNode::PutModelType(syncable::ModelType model_type) {
745   // Set an empty specifics of the appropriate datatype.  The presence
746   // of the specific extension will identify the model type.
747   DCHECK(GetModelType() == model_type ||
748          GetModelType() == syncable::UNSPECIFIED);  // Immutable once set.
749 
750   sync_pb::EntitySpecifics specifics;
751   syncable::AddDefaultExtensionValue(model_type, &specifics);
752   PutSpecificsAndMarkForSyncing(specifics);
753   DCHECK_EQ(model_type, GetModelType());
754 }
755 
756 // Create a new node with default properties, and bind this WriteNode to it.
757 // Return true on success.
InitByCreation(syncable::ModelType model_type,const BaseNode & parent,const BaseNode * predecessor)758 bool WriteNode::InitByCreation(syncable::ModelType model_type,
759                                const BaseNode& parent,
760                                const BaseNode* predecessor) {
761   DCHECK(!entry_) << "Init called twice";
762   // |predecessor| must be a child of |parent| or NULL.
763   if (predecessor && predecessor->GetParentId() != parent.GetId()) {
764     DCHECK(false);
765     return false;
766   }
767 
768   syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
769 
770   // Start out with a dummy name.  We expect
771   // the caller to set a meaningful name after creation.
772   string dummy(kDefaultNameForNewNodes);
773 
774   entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
775                                       syncable::CREATE, parent_id, dummy);
776 
777   if (!entry_->good())
778     return false;
779 
780   // Entries are untitled folders by default.
781   entry_->Put(syncable::IS_DIR, true);
782 
783   PutModelType(model_type);
784 
785   // Now set the predecessor, which sets IS_UNSYNCED as necessary.
786   PutPredecessor(predecessor);
787 
788   return true;
789 }
790 
791 // Create a new node with default properties and a client defined unique tag,
792 // and bind this WriteNode to it.
793 // Return true on success. If the tag exists in the database, then
794 // we will attempt to undelete the node.
795 // TODO(chron): Code datatype into hash tag.
796 // TODO(chron): Is model type ever lost?
InitUniqueByCreation(syncable::ModelType model_type,const BaseNode & parent,const std::string & tag)797 bool WriteNode::InitUniqueByCreation(syncable::ModelType model_type,
798                                      const BaseNode& parent,
799                                      const std::string& tag) {
800   DCHECK(!entry_) << "Init called twice";
801 
802   const std::string hash = GenerateSyncableHash(model_type, tag);
803 
804   syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
805 
806   // Start out with a dummy name.  We expect
807   // the caller to set a meaningful name after creation.
808   string dummy(kDefaultNameForNewNodes);
809 
810   // Check if we have this locally and need to undelete it.
811   scoped_ptr<syncable::MutableEntry> existing_entry(
812       new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
813                                  syncable::GET_BY_CLIENT_TAG, hash));
814 
815   if (existing_entry->good()) {
816     if (existing_entry->Get(syncable::IS_DEL)) {
817       // Rules for undelete:
818       // BASE_VERSION: Must keep the same.
819       // ID: Essential to keep the same.
820       // META_HANDLE: Must be the same, so we can't "split" the entry.
821       // IS_DEL: Must be set to false, will cause reindexing.
822       //         This one is weird because IS_DEL is true for "update only"
823       //         items. It should be OK to undelete an update only.
824       // MTIME/CTIME: Seems reasonable to just leave them alone.
825       // IS_UNSYNCED: Must set this to true or face database insurrection.
826       //              We do this below this block.
827       // IS_UNAPPLIED_UPDATE: Either keep it the same or also set BASE_VERSION
828       //                      to SERVER_VERSION. We keep it the same here.
829       // IS_DIR: We'll leave it the same.
830       // SPECIFICS: Reset it.
831 
832       existing_entry->Put(syncable::IS_DEL, false);
833 
834       // Client tags are immutable and must be paired with the ID.
835       // If a server update comes down with an ID and client tag combo,
836       // and it already exists, always overwrite it and store only one copy.
837       // We have to undelete entries because we can't disassociate IDs from
838       // tags and updates.
839 
840       existing_entry->Put(syncable::NON_UNIQUE_NAME, dummy);
841       existing_entry->Put(syncable::PARENT_ID, parent_id);
842       entry_ = existing_entry.release();
843     } else {
844       return false;
845     }
846   } else {
847     entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
848                                         syncable::CREATE, parent_id, dummy);
849     if (!entry_->good()) {
850       return false;
851     }
852 
853     // Only set IS_DIR for new entries. Don't bitflip undeleted ones.
854     entry_->Put(syncable::UNIQUE_CLIENT_TAG, hash);
855   }
856 
857   // We don't support directory and tag combinations.
858   entry_->Put(syncable::IS_DIR, false);
859 
860   // Will clear specifics data.
861   PutModelType(model_type);
862 
863   // Now set the predecessor, which sets IS_UNSYNCED as necessary.
864   PutPredecessor(NULL);
865 
866   return true;
867 }
868 
SetPosition(const BaseNode & new_parent,const BaseNode * predecessor)869 bool WriteNode::SetPosition(const BaseNode& new_parent,
870                             const BaseNode* predecessor) {
871   // |predecessor| must be a child of |new_parent| or NULL.
872   if (predecessor && predecessor->GetParentId() != new_parent.GetId()) {
873     DCHECK(false);
874     return false;
875   }
876 
877   syncable::Id new_parent_id = new_parent.GetEntry()->Get(syncable::ID);
878 
879   // Filter out redundant changes if both the parent and the predecessor match.
880   if (new_parent_id == entry_->Get(syncable::PARENT_ID)) {
881     const syncable::Id& old = entry_->Get(syncable::PREV_ID);
882     if ((!predecessor && old.IsRoot()) ||
883         (predecessor && (old == predecessor->GetEntry()->Get(syncable::ID)))) {
884       return true;
885     }
886   }
887 
888   // Atomically change the parent. This will fail if it would
889   // introduce a cycle in the hierarchy.
890   if (!entry_->Put(syncable::PARENT_ID, new_parent_id))
891     return false;
892 
893   // Now set the predecessor, which sets IS_UNSYNCED as necessary.
894   PutPredecessor(predecessor);
895 
896   return true;
897 }
898 
GetEntry() const899 const syncable::Entry* WriteNode::GetEntry() const {
900   return entry_;
901 }
902 
GetTransaction() const903 const BaseTransaction* WriteNode::GetTransaction() const {
904   return transaction_;
905 }
906 
Remove()907 void WriteNode::Remove() {
908   entry_->Put(syncable::IS_DEL, true);
909   MarkForSyncing();
910 }
911 
PutPredecessor(const BaseNode * predecessor)912 void WriteNode::PutPredecessor(const BaseNode* predecessor) {
913   syncable::Id predecessor_id = predecessor ?
914       predecessor->GetEntry()->Get(syncable::ID) : syncable::Id();
915   entry_->PutPredecessor(predecessor_id);
916   // Mark this entry as unsynced, to wake up the syncer.
917   MarkForSyncing();
918 }
919 
SetFaviconBytes(const vector<unsigned char> & bytes)920 void WriteNode::SetFaviconBytes(const vector<unsigned char>& bytes) {
921   sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
922   new_value.set_favicon(bytes.empty() ? NULL : &bytes[0], bytes.size());
923   SetBookmarkSpecifics(new_value);
924 }
925 
MarkForSyncing()926 void WriteNode::MarkForSyncing() {
927   syncable::MarkForSyncing(entry_);
928 }
929 
930 //////////////////////////////////////////////////////////////////////////
931 // ReadNode member definitions
ReadNode(const BaseTransaction * transaction)932 ReadNode::ReadNode(const BaseTransaction* transaction)
933     : entry_(NULL), transaction_(transaction) {
934   DCHECK(transaction);
935 }
936 
ReadNode()937 ReadNode::ReadNode() {
938   entry_ = NULL;
939   transaction_ = NULL;
940 }
941 
~ReadNode()942 ReadNode::~ReadNode() {
943   delete entry_;
944 }
945 
InitByRootLookup()946 void ReadNode::InitByRootLookup() {
947   DCHECK(!entry_) << "Init called twice";
948   syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
949   entry_ = new syncable::Entry(trans, syncable::GET_BY_ID, trans->root_id());
950   if (!entry_->good())
951     DCHECK(false) << "Could not lookup root node for reading.";
952 }
953 
InitByIdLookup(int64 id)954 bool ReadNode::InitByIdLookup(int64 id) {
955   DCHECK(!entry_) << "Init called twice";
956   DCHECK_NE(id, kInvalidId);
957   syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
958   entry_ = new syncable::Entry(trans, syncable::GET_BY_HANDLE, id);
959   if (!entry_->good())
960     return false;
961   if (entry_->Get(syncable::IS_DEL))
962     return false;
963   syncable::ModelType model_type = GetModelType();
964   LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
965                   model_type == syncable::TOP_LEVEL_FOLDER)
966       << "SyncAPI InitByIdLookup referencing unusual object.";
967   return DecryptIfNecessary(entry_);
968 }
969 
InitByClientTagLookup(syncable::ModelType model_type,const std::string & tag)970 bool ReadNode::InitByClientTagLookup(syncable::ModelType model_type,
971                                      const std::string& tag) {
972   DCHECK(!entry_) << "Init called twice";
973   if (tag.empty())
974     return false;
975 
976   const std::string hash = GenerateSyncableHash(model_type, tag);
977 
978   entry_ = new syncable::Entry(transaction_->GetWrappedTrans(),
979                                syncable::GET_BY_CLIENT_TAG, hash);
980   return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
981           DecryptIfNecessary(entry_));
982 }
983 
GetEntry() const984 const syncable::Entry* ReadNode::GetEntry() const {
985   return entry_;
986 }
987 
GetTransaction() const988 const BaseTransaction* ReadNode::GetTransaction() const {
989   return transaction_;
990 }
991 
InitByTagLookup(const std::string & tag)992 bool ReadNode::InitByTagLookup(const std::string& tag) {
993   DCHECK(!entry_) << "Init called twice";
994   if (tag.empty())
995     return false;
996   syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
997   entry_ = new syncable::Entry(trans, syncable::GET_BY_SERVER_TAG, tag);
998   if (!entry_->good())
999     return false;
1000   if (entry_->Get(syncable::IS_DEL))
1001     return false;
1002   syncable::ModelType model_type = GetModelType();
1003   LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
1004                   model_type == syncable::TOP_LEVEL_FOLDER)
1005       << "SyncAPI InitByTagLookup referencing unusually typed object.";
1006   return DecryptIfNecessary(entry_);
1007 }
1008 
1009 //////////////////////////////////////////////////////////////////////////
1010 // ReadTransaction member definitions
ReadTransaction(UserShare * share)1011 ReadTransaction::ReadTransaction(UserShare* share)
1012     : BaseTransaction(share),
1013       transaction_(NULL),
1014       close_transaction_(true) {
1015   transaction_ = new syncable::ReadTransaction(GetLookup(), __FILE__, __LINE__);
1016 }
1017 
ReadTransaction(UserShare * share,syncable::BaseTransaction * trans)1018 ReadTransaction::ReadTransaction(UserShare* share,
1019                                  syncable::BaseTransaction* trans)
1020     : BaseTransaction(share),
1021       transaction_(trans),
1022       close_transaction_(false) {}
1023 
~ReadTransaction()1024 ReadTransaction::~ReadTransaction() {
1025   if (close_transaction_) {
1026     delete transaction_;
1027   }
1028 }
1029 
GetWrappedTrans() const1030 syncable::BaseTransaction* ReadTransaction::GetWrappedTrans() const {
1031   return transaction_;
1032 }
1033 
1034 //////////////////////////////////////////////////////////////////////////
1035 // WriteTransaction member definitions
WriteTransaction(UserShare * share)1036 WriteTransaction::WriteTransaction(UserShare* share)
1037     : BaseTransaction(share),
1038       transaction_(NULL) {
1039   transaction_ = new syncable::WriteTransaction(GetLookup(), syncable::SYNCAPI,
1040                                                 __FILE__, __LINE__);
1041 }
1042 
~WriteTransaction()1043 WriteTransaction::~WriteTransaction() {
1044   delete transaction_;
1045 }
1046 
GetWrappedTrans() const1047 syncable::BaseTransaction* WriteTransaction::GetWrappedTrans() const {
1048   return transaction_;
1049 }
1050 
ChangeRecord()1051 SyncManager::ChangeRecord::ChangeRecord()
1052     : id(kInvalidId), action(ACTION_ADD) {}
1053 
~ChangeRecord()1054 SyncManager::ChangeRecord::~ChangeRecord() {}
1055 
ToValue(const BaseTransaction * trans) const1056 DictionaryValue* SyncManager::ChangeRecord::ToValue(
1057     const BaseTransaction* trans) const {
1058   DictionaryValue* value = new DictionaryValue();
1059   std::string action_str;
1060   switch (action) {
1061     case ACTION_ADD:
1062       action_str = "Add";
1063       break;
1064     case ACTION_DELETE:
1065       action_str = "Delete";
1066       break;
1067     case ACTION_UPDATE:
1068       action_str = "Update";
1069       break;
1070     default:
1071       NOTREACHED();
1072       action_str = "Unknown";
1073       break;
1074   }
1075   value->SetString("action", action_str);
1076   Value* node_value = NULL;
1077   if (action == ACTION_DELETE) {
1078     DictionaryValue* node_dict = new DictionaryValue();
1079     node_dict->SetString("id", base::Int64ToString(id));
1080     node_dict->Set("specifics",
1081                     browser_sync::EntitySpecificsToValue(specifics));
1082     if (extra.get()) {
1083       node_dict->Set("extra", extra->ToValue());
1084     }
1085     node_value = node_dict;
1086   } else {
1087     ReadNode node(trans);
1088     if (node.InitByIdLookup(id)) {
1089       node_value = node.ToValue();
1090     }
1091   }
1092   if (!node_value) {
1093     NOTREACHED();
1094     node_value = Value::CreateNullValue();
1095   }
1096   value->Set("node", node_value);
1097   return value;
1098 }
1099 
ContainsString(const std::string & lowercase_query) const1100 bool BaseNode::ContainsString(const std::string& lowercase_query) const {
1101   DCHECK(GetEntry());
1102   // TODO(lipalani) - figure out what to do if the node is encrypted.
1103   const sync_pb::EntitySpecifics& specifics = GetEntry()->Get(SPECIFICS);
1104   std::string temp;
1105   // The protobuf serialized string contains the original strings. So
1106   // we will just serialize it and search it.
1107   specifics.SerializeToString(&temp);
1108 
1109   // Now convert to lower case.
1110   StringToLowerASCII(&temp);
1111 
1112   return temp.find(lowercase_query) != std::string::npos;
1113 }
1114 
ExtraPasswordChangeRecordData()1115 SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData() {}
1116 
ExtraPasswordChangeRecordData(const sync_pb::PasswordSpecificsData & data)1117 SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData(
1118     const sync_pb::PasswordSpecificsData& data)
1119     : unencrypted_(data) {
1120 }
1121 
~ExtraPasswordChangeRecordData()1122 SyncManager::ExtraPasswordChangeRecordData::~ExtraPasswordChangeRecordData() {}
1123 
ToValue() const1124 DictionaryValue* SyncManager::ExtraPasswordChangeRecordData::ToValue() const {
1125   return browser_sync::PasswordSpecificsDataToValue(unencrypted_);
1126 }
1127 
1128 const sync_pb::PasswordSpecificsData&
unencrypted() const1129     SyncManager::ExtraPasswordChangeRecordData::unencrypted() const {
1130   return unencrypted_;
1131 }
1132 
1133 namespace {
1134 
1135 struct NotificationInfo {
1136   int total_count;
1137   std::string payload;
1138 
NotificationInfosync_api::__anon53cbd3440111::NotificationInfo1139   NotificationInfo() : total_count(0) {}
1140 
~NotificationInfosync_api::__anon53cbd3440111::NotificationInfo1141   ~NotificationInfo() {}
1142 
1143   // Returned pointer owned by the caller.
ToValuesync_api::__anon53cbd3440111::NotificationInfo1144   DictionaryValue* ToValue() const {
1145     DictionaryValue* value = new DictionaryValue();
1146     value->SetInteger("totalCount", total_count);
1147     value->SetString("payload", payload);
1148     return value;
1149   }
1150 };
1151 
1152 typedef std::map<syncable::ModelType, NotificationInfo> NotificationInfoMap;
1153 
1154 // returned pointer is owned by the caller.
NotificationInfoToValue(const NotificationInfoMap & notification_info)1155 DictionaryValue* NotificationInfoToValue(
1156     const NotificationInfoMap& notification_info) {
1157   DictionaryValue* value = new DictionaryValue();
1158 
1159   for (NotificationInfoMap::const_iterator it = notification_info.begin();
1160       it != notification_info.end(); ++it) {
1161     const std::string& model_type_str =
1162         syncable::ModelTypeToString(it->first);
1163     value->Set(model_type_str, it->second.ToValue());
1164   }
1165 
1166   return value;
1167 }
1168 
1169 }  // namespace
1170 
1171 //////////////////////////////////////////////////////////////////////////
1172 // SyncManager's implementation: SyncManager::SyncInternal
1173 class SyncManager::SyncInternal
1174     : public net::NetworkChangeNotifier::IPAddressObserver,
1175       public sync_notifier::SyncNotifierObserver,
1176       public browser_sync::JsBackend,
1177       public SyncEngineEventListener,
1178       public ServerConnectionEventListener,
1179       public syncable::DirectoryChangeListener {
1180   static const int kDefaultNudgeDelayMilliseconds;
1181   static const int kPreferencesNudgeDelayMilliseconds;
1182  public:
SyncInternal(SyncManager * sync_manager)1183   explicit SyncInternal(SyncManager* sync_manager)
1184       : core_message_loop_(NULL),
1185         parent_router_(NULL),
1186         sync_manager_(sync_manager),
1187         registrar_(NULL),
1188         initialized_(false),
1189         ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
1190     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1191   }
1192 
~SyncInternal()1193   virtual ~SyncInternal() {
1194     CHECK(!core_message_loop_);
1195     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1196   }
1197 
1198   bool Init(const FilePath& database_location,
1199             const std::string& sync_server_and_path,
1200             int port,
1201             bool use_ssl,
1202             HttpPostProviderFactory* post_factory,
1203             ModelSafeWorkerRegistrar* model_safe_worker_registrar,
1204             const char* user_agent,
1205             const SyncCredentials& credentials,
1206             sync_notifier::SyncNotifier* sync_notifier,
1207             const std::string& restored_key_for_bootstrapping,
1208             bool setup_for_test_mode);
1209 
1210   // Sign into sync with given credentials.
1211   // We do not verify the tokens given. After this call, the tokens are set
1212   // and the sync DB is open. True if successful, false if something
1213   // went wrong.
1214   bool SignIn(const SyncCredentials& credentials);
1215 
1216   // Update tokens that we're using in Sync. Email must stay the same.
1217   void UpdateCredentials(const SyncCredentials& credentials);
1218 
1219   // Called when the user disables or enables a sync type.
1220   void UpdateEnabledTypes();
1221 
1222   // Tell the sync engine to start the syncing process.
1223   void StartSyncing();
1224 
1225   // Whether or not the Nigori node is encrypted using an explicit passphrase.
1226   bool IsUsingExplicitPassphrase();
1227 
1228   // Set the datatypes we want to encrypt and encrypt any nodes as necessary.
1229   void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types);
1230 
1231   // Try to set the current passphrase to |passphrase|, and record whether
1232   // it is an explicit passphrase or implicitly using gaia in the Nigori
1233   // node.
1234   void SetPassphrase(const std::string& passphrase, bool is_explicit);
1235 
1236   // Call periodically from a database-safe thread to persist recent changes
1237   // to the syncapi model.
1238   void SaveChanges();
1239 
1240   // DirectoryChangeListener implementation.
1241   // This listener is called upon completion of a syncable transaction, and
1242   // builds the list of sync-engine initiated changes that will be forwarded to
1243   // the SyncManager's Observers.
1244   virtual void HandleTransactionCompleteChangeEvent(
1245       const ModelTypeBitSet& models_with_changes);
1246   virtual ModelTypeBitSet HandleTransactionEndingChangeEvent(
1247       syncable::BaseTransaction* trans);
1248   virtual void HandleCalculateChangesChangeEventFromSyncApi(
1249       const OriginalEntries& originals,
1250       const WriterTag& writer,
1251       syncable::BaseTransaction* trans);
1252   virtual void HandleCalculateChangesChangeEventFromSyncer(
1253       const OriginalEntries& originals,
1254       const WriterTag& writer,
1255       syncable::BaseTransaction* trans);
1256 
1257   // Listens for notifications from the ServerConnectionManager
1258   void HandleServerConnectionEvent(const ServerConnectionEvent& event);
1259 
1260   // Open the directory named with username_for_share
1261   bool OpenDirectory();
1262 
1263   // SyncNotifierObserver implementation.
1264   virtual void OnNotificationStateChange(
1265       bool notifications_enabled);
1266 
1267   virtual void OnIncomingNotification(
1268       const syncable::ModelTypePayloadMap& type_payloads);
1269 
1270   virtual void StoreState(const std::string& cookie);
1271 
1272   void AddObserver(SyncManager::Observer* observer);
1273 
1274   void RemoveObserver(SyncManager::Observer* observer);
1275 
1276   // Accessors for the private members.
dir_manager()1277   DirectoryManager* dir_manager() { return share_.dir_manager.get(); }
connection_manager()1278   SyncAPIServerConnectionManager* connection_manager() {
1279     return connection_manager_.get();
1280   }
syncer_thread()1281   SyncerThread* syncer_thread() { return syncer_thread_.get(); }
GetUserShare()1282   UserShare* GetUserShare() { return &share_; }
1283 
1284   // Return the currently active (validated) username for use with syncable
1285   // types.
username_for_share() const1286   const std::string& username_for_share() const {
1287     return share_.name;
1288   }
1289 
1290   Status GetStatus();
1291 
1292   void RequestNudge(const tracked_objects::Location& nudge_location);
1293 
1294   void RequestNudgeWithDataTypes(const TimeDelta& delay,
1295       browser_sync::NudgeSource source, const ModelTypeBitSet& types,
1296       const tracked_objects::Location& nudge_location);
1297 
1298   // See SyncManager::Shutdown for information.
1299   void Shutdown();
1300 
1301   // Whether we're initialized to the point of being able to accept changes
1302   // (and hence allow transaction creation). See initialized_ for details.
initialized() const1303   bool initialized() const {
1304     base::AutoLock lock(initialized_mutex_);
1305     return initialized_;
1306   }
1307 
1308   // If this is a deletion for a password, sets the legacy
1309   // ExtraPasswordChangeRecordData field of |buffer|. Otherwise sets
1310   // |buffer|'s specifics field to contain the unencrypted data.
1311   void SetExtraChangeRecordData(int64 id,
1312                                 syncable::ModelType type,
1313                                 ChangeReorderBuffer* buffer,
1314                                 Cryptographer* cryptographer,
1315                                 const syncable::EntryKernel& original,
1316                                 bool existed_before,
1317                                 bool exists_now);
1318 
1319   // Called only by our NetworkChangeNotifier.
1320   virtual void OnIPAddressChanged();
1321 
InitialSyncEndedForAllEnabledTypes()1322   bool InitialSyncEndedForAllEnabledTypes() {
1323     syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1324     if (!lookup.good()) {
1325       DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1326       return false;
1327     }
1328 
1329     ModelSafeRoutingInfo enabled_types;
1330     registrar_->GetModelSafeRoutingInfo(&enabled_types);
1331     for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
1332         i != enabled_types.end(); ++i) {
1333       if (!lookup->initial_sync_ended_for_type(i->first))
1334         return false;
1335     }
1336     return true;
1337   }
1338 
GetAutofillMigrationState()1339   syncable::AutofillMigrationState GetAutofillMigrationState() {
1340     syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1341     if (!lookup.good()) {
1342       DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1343       return syncable::NOT_MIGRATED;
1344     }
1345 
1346     return lookup->get_autofill_migration_state();
1347   }
1348 
SetAutofillMigrationState(syncable::AutofillMigrationState state)1349   void SetAutofillMigrationState(syncable::AutofillMigrationState state) {
1350     syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1351     if (!lookup.good()) {
1352       DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1353       return;
1354     }
1355 
1356     return lookup->set_autofill_migration_state(state);
1357   }
1358 
SetAutofillMigrationDebugInfo(syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,const syncable::AutofillMigrationDebugInfo & info)1359   void SetAutofillMigrationDebugInfo(
1360       syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
1361       const syncable::AutofillMigrationDebugInfo& info) {
1362     syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1363     if (!lookup.good()) {
1364       DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1365       return;
1366     }
1367 
1368     return lookup->set_autofill_migration_state_debug_info(
1369         property_to_set, info);
1370   }
1371 
1372   syncable::AutofillMigrationDebugInfo
GetAutofillMigrationDebugInfo()1373       GetAutofillMigrationDebugInfo() {
1374     syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1375     if (!lookup.good()) {
1376       DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1377       syncable::AutofillMigrationDebugInfo null_value = {0};
1378       return null_value;
1379     }
1380     return lookup->get_autofill_migration_debug_info();
1381   }
1382 
1383   // SyncEngineEventListener implementation.
1384   virtual void OnSyncEngineEvent(const SyncEngineEvent& event);
1385 
1386   // ServerConnectionEventListener implementation.
1387   virtual void OnServerConnectionEvent(const ServerConnectionEvent2& event);
1388 
1389   // browser_sync::JsBackend implementation.
1390   virtual void SetParentJsEventRouter(browser_sync::JsEventRouter* router);
1391   virtual void RemoveParentJsEventRouter();
1392   virtual const browser_sync::JsEventRouter* GetParentJsEventRouter() const;
1393   virtual void ProcessMessage(const std::string& name,
1394                               const browser_sync::JsArgList& args,
1395                               const browser_sync::JsEventHandler* sender);
1396 
1397   ListValue* FindNodesContainingString(const std::string& query);
1398 
1399  private:
1400   // Helper to call OnAuthError when no authentication credentials are
1401   // available.
1402   void RaiseAuthNeededEvent();
1403 
1404   // Helper to set initialized_ to true and raise an event to clients to notify
1405   // that initialization is complete and it is safe to send us changes. If
1406   // already initialized, this is a no-op.
1407   void MarkAndNotifyInitializationComplete();
1408 
1409   // Sends notifications to peers.
1410   void SendNotification();
1411 
1412   // Determine if the parents or predecessors differ between the old and new
1413   // versions of an entry stored in |a| and |b|.  Note that a node's index may
1414   // change without its NEXT_ID changing if the node at NEXT_ID also moved (but
1415   // the relative order is unchanged).  To handle such cases, we rely on the
1416   // caller to treat a position update on any sibling as updating the positions
1417   // of all siblings.
VisiblePositionsDiffer(const syncable::EntryKernel & a,const syncable::Entry & b)1418   static bool VisiblePositionsDiffer(const syncable::EntryKernel& a,
1419                                      const syncable::Entry& b) {
1420     // If the datatype isn't one where the browser model cares about position,
1421     // don't bother notifying that data model of position-only changes.
1422     if (!b.ShouldMaintainPosition())
1423       return false;
1424     if (a.ref(syncable::NEXT_ID) != b.Get(syncable::NEXT_ID))
1425       return true;
1426     if (a.ref(syncable::PARENT_ID) != b.Get(syncable::PARENT_ID))
1427       return true;
1428     return false;
1429   }
1430 
1431   // Determine if any of the fields made visible to clients of the Sync API
1432   // differ between the versions of an entry stored in |a| and |b|. A return
1433   // value of false means that it should be OK to ignore this change.
VisiblePropertiesDiffer(const syncable::EntryKernel & a,const syncable::Entry & b,Cryptographer * cryptographer)1434   static bool VisiblePropertiesDiffer(const syncable::EntryKernel& a,
1435                                       const syncable::Entry& b,
1436                                       Cryptographer* cryptographer) {
1437     syncable::ModelType model_type = b.GetModelType();
1438     // Suppress updates to items that aren't tracked by any browser model.
1439     if (model_type == syncable::UNSPECIFIED ||
1440         model_type == syncable::TOP_LEVEL_FOLDER) {
1441       return false;
1442     }
1443     if (a.ref(syncable::NON_UNIQUE_NAME) != b.Get(syncable::NON_UNIQUE_NAME))
1444       return true;
1445     if (a.ref(syncable::IS_DIR) != b.Get(syncable::IS_DIR))
1446       return true;
1447     // Check if data has changed (account for encryption).
1448     std::string a_str, b_str;
1449     if (a.ref(SPECIFICS).has_encrypted()) {
1450       const sync_pb::EncryptedData& encrypted = a.ref(SPECIFICS).encrypted();
1451       a_str = cryptographer->DecryptToString(encrypted);
1452     } else {
1453       a_str = a.ref(SPECIFICS).SerializeAsString();
1454     }
1455     if (b.Get(SPECIFICS).has_encrypted()) {
1456       const sync_pb::EncryptedData& encrypted = b.Get(SPECIFICS).encrypted();
1457       b_str = cryptographer->DecryptToString(encrypted);
1458     } else {
1459       b_str = b.Get(SPECIFICS).SerializeAsString();
1460     }
1461     if (a_str != b_str) {
1462       return true;
1463     }
1464     if (VisiblePositionsDiffer(a, b))
1465       return true;
1466     return false;
1467   }
1468 
ChangeBuffersAreEmpty()1469   bool ChangeBuffersAreEmpty() {
1470     for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1471       if (!change_buffers_[i].IsEmpty())
1472         return false;
1473     }
1474     return true;
1475   }
1476 
CheckServerReachable()1477   void CheckServerReachable() {
1478     if (connection_manager()) {
1479       connection_manager()->CheckServerReachable();
1480     } else {
1481       NOTREACHED() << "Should be valid connection manager!";
1482     }
1483   }
1484 
1485   void ReEncryptEverything(WriteTransaction* trans);
1486 
1487   // Initializes (bootstraps) the Cryptographer if NIGORI has finished
1488   // initial sync so that it can immediately start encrypting / decrypting.
1489   // If the restored key is incompatible with the current version of the NIGORI
1490   // node (which could happen if a restart occurred just after an update to
1491   // NIGORI was downloaded and the user must enter a new passphrase to decrypt)
1492   // then we will raise OnPassphraseRequired and set pending keys for
1493   // decryption.  Otherwise, the cryptographer is made ready (is_ready()).
1494   void BootstrapEncryption(const std::string& restored_key_for_bootstrapping);
1495 
1496   // Called for every notification. This updates the notification statistics
1497   // to be displayed in about:sync.
1498   void UpdateNotificationInfo(
1499       const syncable::ModelTypePayloadMap& type_payloads);
1500 
1501   // Helper for migration to new nigori proto to set
1502   // 'using_explicit_passphrase' in the NigoriSpecifics.
1503   // TODO(tim): Bug 62103.  Remove this after it has been pushed out to dev
1504   // channel users.
1505   void SetUsingExplicitPassphrasePrefForMigration(
1506       WriteTransaction* const trans);
1507 
1508   // Checks for server reachabilty and requests a nudge.
1509   void OnIPAddressChangedImpl();
1510 
1511   // Functions called by ProcessMessage().
1512   browser_sync::JsArgList ProcessGetNodeByIdMessage(
1513       const browser_sync::JsArgList& args);
1514 
1515   browser_sync::JsArgList ProcessFindNodesContainingString(
1516       const browser_sync::JsArgList& args);
1517 
1518   // We couple the DirectoryManager and username together in a UserShare member
1519   // so we can return a handle to share_ to clients of the API for use when
1520   // constructing any transaction type.
1521   UserShare share_;
1522 
1523   MessageLoop* core_message_loop_;
1524 
1525   ObserverList<SyncManager::Observer> observers_;
1526 
1527   browser_sync::JsEventRouter* parent_router_;
1528 
1529   // The ServerConnectionManager used to abstract communication between the
1530   // client (the Syncer) and the sync server.
1531   scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
1532 
1533   // The thread that runs the Syncer. Needs to be explicitly Start()ed.
1534   scoped_ptr<SyncerThread> syncer_thread_;
1535 
1536   // The SyncNotifier which notifies us when updates need to be downloaded.
1537   sync_notifier::SyncNotifier* sync_notifier_;
1538 
1539   // A multi-purpose status watch object that aggregates stats from various
1540   // sync components.
1541   AllStatus allstatus_;
1542 
1543   // Each element of this array is a store of change records produced by
1544   // HandleChangeEvent during the CALCULATE_CHANGES step.  The changes are
1545   // segregated by model type, and are stored here to be processed and
1546   // forwarded to the observer slightly later, at the TRANSACTION_ENDING
1547   // step by HandleTransactionEndingChangeEvent. The list is cleared in the
1548   // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
1549   ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
1550 
1551   // Event listener hookup for the ServerConnectionManager.
1552   scoped_ptr<EventListenerHookup> connection_manager_hookup_;
1553 
1554   // The sync dir_manager to which we belong.
1555   SyncManager* const sync_manager_;
1556 
1557   // The entity that provides us with information about which types to sync.
1558   // The instance is shared between the SyncManager and the Syncer.
1559   ModelSafeWorkerRegistrar* registrar_;
1560 
1561   // Set to true once Init has been called, and we know of an authenticated
1562   // valid) username either from a fresh authentication attempt (as in
1563   // first-use case) or from a previous attempt stored in our UserSettings
1564   // (as in the steady-state), and the syncable::Directory has been opened,
1565   // meaning we are ready to accept changes.  Protected by initialized_mutex_
1566   // as it can get read/set by both the SyncerThread and the AuthWatcherThread.
1567   bool initialized_;
1568   mutable base::Lock initialized_mutex_;
1569 
1570   // True if the SyncManager should be running in test mode (no syncer thread
1571   // actually communicating with the server).
1572   bool setup_for_test_mode_;
1573 
1574   ScopedRunnableMethodFactory<SyncManager::SyncInternal> method_factory_;
1575 
1576   // Map used to store the notification info to be displayed in about:sync page.
1577   // TODO(lipalani) - prefill the map with enabled data types.
1578   NotificationInfoMap notification_info_map_;
1579 };
1580 const int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
1581 const int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
1582 
~Observer()1583 SyncManager::Observer::~Observer() {}
1584 
SyncManager()1585 SyncManager::SyncManager() {
1586   data_ = new SyncInternal(this);
1587 }
1588 
Init(const FilePath & database_location,const char * sync_server_and_path,int sync_server_port,bool use_ssl,HttpPostProviderFactory * post_factory,ModelSafeWorkerRegistrar * registrar,const char * user_agent,const SyncCredentials & credentials,sync_notifier::SyncNotifier * sync_notifier,const std::string & restored_key_for_bootstrapping,bool setup_for_test_mode)1589 bool SyncManager::Init(const FilePath& database_location,
1590                        const char* sync_server_and_path,
1591                        int sync_server_port,
1592                        bool use_ssl,
1593                        HttpPostProviderFactory* post_factory,
1594                        ModelSafeWorkerRegistrar* registrar,
1595                        const char* user_agent,
1596                        const SyncCredentials& credentials,
1597                        sync_notifier::SyncNotifier* sync_notifier,
1598                        const std::string& restored_key_for_bootstrapping,
1599                        bool setup_for_test_mode) {
1600   DCHECK(post_factory);
1601   VLOG(1) << "SyncManager starting Init...";
1602   string server_string(sync_server_and_path);
1603   return data_->Init(database_location,
1604                      server_string,
1605                      sync_server_port,
1606                      use_ssl,
1607                      post_factory,
1608                      registrar,
1609                      user_agent,
1610                      credentials,
1611                      sync_notifier,
1612                      restored_key_for_bootstrapping,
1613                      setup_for_test_mode);
1614 }
1615 
UpdateCredentials(const SyncCredentials & credentials)1616 void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
1617   data_->UpdateCredentials(credentials);
1618 }
1619 
UpdateEnabledTypes()1620 void SyncManager::UpdateEnabledTypes() {
1621   data_->UpdateEnabledTypes();
1622 }
1623 
1624 
InitialSyncEndedForAllEnabledTypes()1625 bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
1626   return data_->InitialSyncEndedForAllEnabledTypes();
1627 }
1628 
StartSyncing()1629 void SyncManager::StartSyncing() {
1630   data_->StartSyncing();
1631 }
1632 
1633 syncable::AutofillMigrationState
GetAutofillMigrationState()1634     SyncManager::GetAutofillMigrationState() {
1635   return data_->GetAutofillMigrationState();
1636 }
1637 
SetAutofillMigrationState(syncable::AutofillMigrationState state)1638 void SyncManager::SetAutofillMigrationState(
1639     syncable::AutofillMigrationState state) {
1640   return data_->SetAutofillMigrationState(state);
1641 }
1642 
1643 syncable::AutofillMigrationDebugInfo
GetAutofillMigrationDebugInfo()1644     SyncManager::GetAutofillMigrationDebugInfo() {
1645   return data_->GetAutofillMigrationDebugInfo();
1646 }
1647 
SetAutofillMigrationDebugInfo(syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,const syncable::AutofillMigrationDebugInfo & info)1648 void SyncManager::SetAutofillMigrationDebugInfo(
1649     syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
1650     const syncable::AutofillMigrationDebugInfo& info) {
1651   return data_->SetAutofillMigrationDebugInfo(property_to_set, info);
1652 }
1653 
SetPassphrase(const std::string & passphrase,bool is_explicit)1654 void SyncManager::SetPassphrase(const std::string& passphrase,
1655      bool is_explicit) {
1656   data_->SetPassphrase(passphrase, is_explicit);
1657 }
1658 
EncryptDataTypes(const syncable::ModelTypeSet & encrypted_types)1659 void SyncManager::EncryptDataTypes(
1660     const syncable::ModelTypeSet& encrypted_types) {
1661   data_->EncryptDataTypes(encrypted_types);
1662 }
1663 
IsUsingExplicitPassphrase()1664 bool SyncManager::IsUsingExplicitPassphrase() {
1665   return data_ && data_->IsUsingExplicitPassphrase();
1666 }
1667 
RequestNudge(const tracked_objects::Location & location)1668 void SyncManager::RequestNudge(const tracked_objects::Location& location) {
1669   data_->RequestNudge(location);
1670 }
1671 
RequestClearServerData()1672 void SyncManager::RequestClearServerData() {
1673   if (data_->syncer_thread())
1674     data_->syncer_thread()->ScheduleClearUserData();
1675 }
1676 
RequestConfig(const syncable::ModelTypeBitSet & types)1677 void SyncManager::RequestConfig(const syncable::ModelTypeBitSet& types) {
1678   if (!data_->syncer_thread())
1679     return;
1680   StartConfigurationMode(NULL);
1681   data_->syncer_thread()->ScheduleConfig(types);
1682 }
1683 
StartConfigurationMode(ModeChangeCallback * callback)1684 void SyncManager::StartConfigurationMode(ModeChangeCallback* callback) {
1685   if (!data_->syncer_thread())
1686     return;
1687   data_->syncer_thread()->Start(
1688       browser_sync::SyncerThread::CONFIGURATION_MODE, callback);
1689 }
1690 
GetAuthenticatedUsername()1691 const std::string& SyncManager::GetAuthenticatedUsername() {
1692   DCHECK(data_);
1693   return data_->username_for_share();
1694 }
1695 
Init(const FilePath & database_location,const std::string & sync_server_and_path,int port,bool use_ssl,HttpPostProviderFactory * post_factory,ModelSafeWorkerRegistrar * model_safe_worker_registrar,const char * user_agent,const SyncCredentials & credentials,sync_notifier::SyncNotifier * sync_notifier,const std::string & restored_key_for_bootstrapping,bool setup_for_test_mode)1696 bool SyncManager::SyncInternal::Init(
1697     const FilePath& database_location,
1698     const std::string& sync_server_and_path,
1699     int port,
1700     bool use_ssl,
1701     HttpPostProviderFactory* post_factory,
1702     ModelSafeWorkerRegistrar* model_safe_worker_registrar,
1703     const char* user_agent,
1704     const SyncCredentials& credentials,
1705     sync_notifier::SyncNotifier* sync_notifier,
1706     const std::string& restored_key_for_bootstrapping,
1707     bool setup_for_test_mode) {
1708 
1709   VLOG(1) << "Starting SyncInternal initialization.";
1710 
1711   core_message_loop_ = MessageLoop::current();
1712   DCHECK(core_message_loop_);
1713   registrar_ = model_safe_worker_registrar;
1714   setup_for_test_mode_ = setup_for_test_mode;
1715 
1716   sync_notifier_ = sync_notifier;
1717   sync_notifier_->AddObserver(this);
1718 
1719   share_.dir_manager.reset(new DirectoryManager(database_location));
1720 
1721   connection_manager_.reset(new SyncAPIServerConnectionManager(
1722       sync_server_and_path, port, use_ssl, user_agent, post_factory));
1723 
1724   net::NetworkChangeNotifier::AddIPAddressObserver(this);
1725 
1726   connection_manager()->AddListener(this);
1727 
1728   // TODO(akalin): CheckServerReachable() can block, which may cause jank if we
1729   // try to shut down sync.  Fix this.
1730   core_message_loop_->PostTask(FROM_HERE,
1731       method_factory_.NewRunnableMethod(&SyncInternal::CheckServerReachable));
1732 
1733   // Test mode does not use a syncer context or syncer thread.
1734   if (!setup_for_test_mode_) {
1735     // Build a SyncSessionContext and store the worker in it.
1736     VLOG(1) << "Sync is bringing up SyncSessionContext.";
1737     std::vector<SyncEngineEventListener*> listeners;
1738     listeners.push_back(&allstatus_);
1739     listeners.push_back(this);
1740     SyncSessionContext* context = new SyncSessionContext(
1741         connection_manager_.get(),
1742         dir_manager(),
1743         model_safe_worker_registrar,
1744         listeners);
1745     context->set_account_name(credentials.email);
1746     // The SyncerThread takes ownership of |context|.
1747     syncer_thread_.reset(new SyncerThread(context, new Syncer()));
1748   }
1749 
1750   bool signed_in = SignIn(credentials);
1751 
1752   if (signed_in && syncer_thread()) {
1753     syncer_thread()->Start(
1754         browser_sync::SyncerThread::CONFIGURATION_MODE, NULL);
1755   }
1756 
1757   // Do this once the directory is opened.
1758   BootstrapEncryption(restored_key_for_bootstrapping);
1759   MarkAndNotifyInitializationComplete();
1760   return signed_in;
1761 }
1762 
BootstrapEncryption(const std::string & restored_key_for_bootstrapping)1763 void SyncManager::SyncInternal::BootstrapEncryption(
1764     const std::string& restored_key_for_bootstrapping) {
1765   syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1766   if (!lookup.good()) {
1767     NOTREACHED();
1768     return;
1769   }
1770 
1771   if (!lookup->initial_sync_ended_for_type(syncable::NIGORI))
1772     return;
1773 
1774   sync_pb::NigoriSpecifics nigori;
1775   {
1776     // Cryptographer should only be accessed while holding a transaction.
1777     ReadTransaction trans(GetUserShare());
1778     Cryptographer* cryptographer = trans.GetCryptographer();
1779     cryptographer->Bootstrap(restored_key_for_bootstrapping);
1780 
1781     ReadNode node(&trans);
1782     if (!node.InitByTagLookup(kNigoriTag)) {
1783       NOTREACHED();
1784       return;
1785     }
1786 
1787     nigori.CopyFrom(node.GetNigoriSpecifics());
1788     if (!nigori.encrypted().blob().empty()) {
1789       if (cryptographer->CanDecrypt(nigori.encrypted())) {
1790         cryptographer->SetKeys(nigori.encrypted());
1791       } else {
1792         cryptographer->SetPendingKeys(nigori.encrypted());
1793         FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1794                           OnPassphraseRequired(true));
1795       }
1796     }
1797   }
1798 
1799   // Refresh list of encrypted datatypes.
1800   syncable::ModelTypeSet encrypted_types =
1801       syncable::GetEncryptedDataTypesFromNigori(nigori);
1802 
1803   // Ensure any datatypes that need encryption are encrypted.
1804   EncryptDataTypes(encrypted_types);
1805 }
1806 
StartSyncing()1807 void SyncManager::SyncInternal::StartSyncing() {
1808   // Start the syncer thread. This won't actually
1809   // result in any syncing until at least the
1810   // DirectoryManager broadcasts the OPENED event,
1811   // and a valid server connection is detected.
1812   if (syncer_thread())  // NULL during certain unittests.
1813     syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
1814 }
1815 
MarkAndNotifyInitializationComplete()1816 void SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
1817   // There is only one real time we need this mutex.  If we get an auth
1818   // success, and before the initial sync ends we get an auth failure.  In this
1819   // case we'll be listening to both the AuthWatcher and Syncer, and it's a race
1820   // between their respective threads to call MarkAndNotify.  We need to make
1821   // sure the observer is notified once and only once.
1822   {
1823     base::AutoLock lock(initialized_mutex_);
1824     if (initialized_)
1825       return;
1826     initialized_ = true;
1827   }
1828 
1829   // Notify that initialization is complete.
1830   FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1831                     OnInitializationComplete());
1832 }
1833 
SendNotification()1834 void SyncManager::SyncInternal::SendNotification() {
1835   DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1836   if (!sync_notifier_) {
1837     VLOG(1) << "Not sending notification: sync_notifier_ is NULL";
1838     return;
1839   }
1840   allstatus_.IncrementNotificationsSent();
1841   sync_notifier_->SendNotification();
1842 }
1843 
OpenDirectory()1844 bool SyncManager::SyncInternal::OpenDirectory() {
1845   DCHECK(!initialized()) << "Should only happen once";
1846 
1847   bool share_opened = dir_manager()->Open(username_for_share());
1848   DCHECK(share_opened);
1849   if (!share_opened) {
1850     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1851                       OnStopSyncingPermanently());
1852 
1853     LOG(ERROR) << "Could not open share for:" << username_for_share();
1854     return false;
1855   }
1856 
1857   // Database has to be initialized for the guid to be available.
1858   syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1859   if (!lookup.good()) {
1860     NOTREACHED();
1861     return false;
1862   }
1863 
1864   connection_manager()->set_client_id(lookup->cache_guid());
1865 
1866   lookup->SetChangeListener(this);
1867   return true;
1868 }
1869 
SignIn(const SyncCredentials & credentials)1870 bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
1871   DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1872   DCHECK(share_.name.empty());
1873   share_.name = credentials.email;
1874 
1875   VLOG(1) << "Signing in user: " << username_for_share();
1876   if (!OpenDirectory())
1877     return false;
1878 
1879   // Retrieve and set the sync notifier state. This should be done
1880   // only after OpenDirectory is called.
1881   syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1882   std::string state;
1883   if (lookup.good()) {
1884     state = lookup->GetAndClearNotificationState();
1885   } else {
1886     LOG(ERROR) << "Could not read notification state";
1887   }
1888   if (VLOG_IS_ON(1)) {
1889     std::string encoded_state;
1890     base::Base64Encode(state, &encoded_state);
1891     VLOG(1) << "Read notification state: " << encoded_state;
1892   }
1893   sync_notifier_->SetState(state);
1894 
1895   UpdateCredentials(credentials);
1896   UpdateEnabledTypes();
1897   return true;
1898 }
1899 
UpdateCredentials(const SyncCredentials & credentials)1900 void SyncManager::SyncInternal::UpdateCredentials(
1901     const SyncCredentials& credentials) {
1902   DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1903   DCHECK_EQ(credentials.email, share_.name);
1904   DCHECK(!credentials.email.empty());
1905   DCHECK(!credentials.sync_token.empty());
1906   connection_manager()->set_auth_token(credentials.sync_token);
1907   sync_notifier_->UpdateCredentials(
1908       credentials.email, credentials.sync_token);
1909   if (!setup_for_test_mode_) {
1910     CheckServerReachable();
1911   }
1912 }
1913 
UpdateEnabledTypes()1914 void SyncManager::SyncInternal::UpdateEnabledTypes() {
1915   DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1916   ModelSafeRoutingInfo routes;
1917   registrar_->GetModelSafeRoutingInfo(&routes);
1918   syncable::ModelTypeSet enabled_types;
1919   for (ModelSafeRoutingInfo::const_iterator it = routes.begin();
1920        it != routes.end(); ++it) {
1921     enabled_types.insert(it->first);
1922   }
1923   sync_notifier_->UpdateEnabledTypes(enabled_types);
1924 }
1925 
RaiseAuthNeededEvent()1926 void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
1927   FOR_EACH_OBSERVER(
1928       SyncManager::Observer, observers_,
1929       OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
1930 }
1931 
SetUsingExplicitPassphrasePrefForMigration(WriteTransaction * const trans)1932 void SyncManager::SyncInternal::SetUsingExplicitPassphrasePrefForMigration(
1933     WriteTransaction* const trans) {
1934   WriteNode node(trans);
1935   if (!node.InitByTagLookup(kNigoriTag)) {
1936     // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1937     NOTREACHED();
1938     return;
1939   }
1940   sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
1941   specifics.set_using_explicit_passphrase(true);
1942   node.SetNigoriSpecifics(specifics);
1943 }
1944 
SetPassphrase(const std::string & passphrase,bool is_explicit)1945 void SyncManager::SyncInternal::SetPassphrase(
1946     const std::string& passphrase, bool is_explicit) {
1947   // All accesses to the cryptographer are protected by a transaction.
1948   WriteTransaction trans(GetUserShare());
1949   Cryptographer* cryptographer = trans.GetCryptographer();
1950   KeyParams params = {"localhost", "dummy", passphrase};
1951 
1952   if (cryptographer->has_pending_keys()) {
1953     if (!cryptographer->DecryptPendingKeys(params)) {
1954       VLOG(1) << "Passphrase failed to decrypt pending keys.";
1955       FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
1956                         OnPassphraseFailed());
1957       return;
1958     }
1959 
1960     // TODO(tim): If this is the first time the user has entered a passphrase
1961     // since the protocol changed to store passphrase preferences in the cloud,
1962     // make sure we update this preference. See bug 62103.
1963     if (is_explicit)
1964       SetUsingExplicitPassphrasePrefForMigration(&trans);
1965 
1966     // Nudge the syncer so that encrypted datatype updates that were waiting for
1967     // this passphrase get applied as soon as possible.
1968     RequestNudge(FROM_HERE);
1969   } else {
1970     VLOG(1) << "No pending keys, adding provided passphrase.";
1971     WriteNode node(&trans);
1972     if (!node.InitByTagLookup(kNigoriTag)) {
1973       // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1974       NOTREACHED();
1975       return;
1976     }
1977 
1978     // Prevent an implicit SetPassphrase request from changing an explicitly
1979     // set passphrase.
1980     if (!is_explicit && node.GetNigoriSpecifics().using_explicit_passphrase())
1981       return;
1982 
1983     cryptographer->AddKey(params);
1984 
1985     // TODO(tim): Bug 58231. It would be nice if SetPassphrase didn't require
1986     // messing with the Nigori node, because we can't call SetPassphrase until
1987     // download conditions are met vs Cryptographer init.  It seems like it's
1988     // safe to defer this work.
1989     sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
1990     specifics.clear_encrypted();
1991     cryptographer->GetKeys(specifics.mutable_encrypted());
1992     specifics.set_using_explicit_passphrase(is_explicit);
1993     node.SetNigoriSpecifics(specifics);
1994     ReEncryptEverything(&trans);
1995   }
1996 
1997   std::string bootstrap_token;
1998   cryptographer->GetBootstrapToken(&bootstrap_token);
1999   FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2000                     OnPassphraseAccepted(bootstrap_token));
2001 }
2002 
IsUsingExplicitPassphrase()2003 bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
2004   ReadTransaction trans(&share_);
2005   ReadNode node(&trans);
2006   if (!node.InitByTagLookup(kNigoriTag)) {
2007     // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
2008     NOTREACHED();
2009     return false;
2010   }
2011 
2012   return node.GetNigoriSpecifics().using_explicit_passphrase();
2013 }
2014 
EncryptDataTypes(const syncable::ModelTypeSet & encrypted_types)2015 void SyncManager::SyncInternal::EncryptDataTypes(
2016     const syncable::ModelTypeSet& encrypted_types) {
2017   VLOG(1) << "Attempting to encrypt datatypes "
2018           << syncable::ModelTypeSetToString(encrypted_types);
2019 
2020   WriteTransaction trans(GetUserShare());
2021   WriteNode node(&trans);
2022   if (!node.InitByTagLookup(kNigoriTag)) {
2023     LOG(ERROR) << "Unable to set encrypted datatypes because Nigori node not "
2024                << "found.";
2025     NOTREACHED();
2026     return;
2027   }
2028 
2029   // Update the Nigori node set of encrypted datatypes so other machines notice.
2030   // Note, we merge the current encrypted types with those requested. Once a
2031   // datatypes is marked as needing encryption, it is never unmarked.
2032   sync_pb::NigoriSpecifics nigori;
2033   nigori.CopyFrom(node.GetNigoriSpecifics());
2034   syncable::ModelTypeSet current_encrypted_types =
2035       syncable::GetEncryptedDataTypesFromNigori(nigori);
2036   syncable::ModelTypeSet newly_encrypted_types;
2037   std::set_union(current_encrypted_types.begin(), current_encrypted_types.end(),
2038                  encrypted_types.begin(), encrypted_types.end(),
2039                  std::inserter(newly_encrypted_types,
2040                                newly_encrypted_types.begin()));
2041   syncable::FillNigoriEncryptedTypes(newly_encrypted_types, &nigori);
2042   node.SetNigoriSpecifics(nigori);
2043 
2044   // TODO(zea): only reencrypt this datatype? ReEncrypting everything is a
2045   // safer approach, and should not impact anything that is already encrypted
2046   // (redundant changes are ignored).
2047   ReEncryptEverything(&trans);
2048   return;
2049 }
2050 
2051 namespace {
2052 
FindChildNodesContainingString(const std::string & lowercase_query,const ReadNode & parent_node,sync_api::ReadTransaction * trans,ListValue * result)2053 void FindChildNodesContainingString(const std::string& lowercase_query,
2054     const ReadNode& parent_node,
2055     sync_api::ReadTransaction* trans,
2056     ListValue* result) {
2057   int64 child_id = parent_node.GetFirstChildId();
2058   while (child_id != kInvalidId) {
2059     ReadNode node(trans);
2060     if (node.InitByIdLookup(child_id)) {
2061       if (node.ContainsString(lowercase_query)) {
2062         result->Append(new StringValue(base::Int64ToString(child_id)));
2063       }
2064       FindChildNodesContainingString(lowercase_query, node, trans, result);
2065       child_id = node.GetSuccessorId();
2066     } else {
2067       LOG(WARNING) << "Lookup of node failed. Id: " << child_id;
2068       return;
2069     }
2070   }
2071 }
2072 }  // namespace
2073 
2074 // Returned pointer owned by the caller.
FindNodesContainingString(const std::string & query)2075 ListValue* SyncManager::SyncInternal::FindNodesContainingString(
2076     const std::string& query) {
2077   // Convert the query string to lower case to perform case insensitive
2078   // searches.
2079   std::string lowercase_query = query;
2080   StringToLowerASCII(&lowercase_query);
2081   ReadTransaction trans(GetUserShare());
2082   ReadNode root(&trans);
2083   root.InitByRootLookup();
2084 
2085   ListValue* result = new ListValue();
2086 
2087   base::Time start_time = base::Time::Now();
2088   FindChildNodesContainingString(lowercase_query, root, &trans, result);
2089   base::Time end_time = base::Time::Now();
2090 
2091   base::TimeDelta delta = end_time - start_time;
2092   VLOG(1) << "Time taken in milliseconds to search " << delta.InMilliseconds();
2093 
2094   return result;
2095 }
2096 
ReEncryptEverything(WriteTransaction * trans)2097 void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
2098   syncable::ModelTypeSet encrypted_types =
2099       GetEncryptedDataTypes(trans->GetWrappedTrans());
2100   ModelSafeRoutingInfo routes;
2101   registrar_->GetModelSafeRoutingInfo(&routes);
2102   std::string tag;
2103   for (syncable::ModelTypeSet::iterator iter = encrypted_types.begin();
2104        iter != encrypted_types.end(); ++iter) {
2105     if (*iter == syncable::PASSWORDS || routes.count(*iter) == 0)
2106       continue;
2107     ReadNode type_root(trans);
2108     tag = syncable::ModelTypeToRootTag(*iter);
2109     if (!type_root.InitByTagLookup(tag)) {
2110       NOTREACHED();
2111       return;
2112     }
2113 
2114     // Iterate through all children of this datatype.
2115     std::queue<int64> to_visit;
2116     int64 child_id = type_root.GetFirstChildId();
2117     to_visit.push(child_id);
2118     while (!to_visit.empty()) {
2119       child_id = to_visit.front();
2120       to_visit.pop();
2121       if (child_id == kInvalidId)
2122         continue;
2123 
2124       WriteNode child(trans);
2125       if (!child.InitByIdLookup(child_id)) {
2126         NOTREACHED();
2127         return;
2128       }
2129       if (child.GetIsFolder()) {
2130         to_visit.push(child.GetFirstChildId());
2131       } else {
2132         // Rewrite the specifics of the node with encrypted data if necessary.
2133         child.ResetFromSpecifics();
2134       }
2135       to_visit.push(child.GetSuccessorId());
2136     }
2137   }
2138 
2139   if (routes.count(syncable::PASSWORDS) > 0) {
2140     // Passwords are encrypted with their own legacy scheme.
2141     encrypted_types.insert(syncable::PASSWORDS);
2142     ReadNode passwords_root(trans);
2143     std::string passwords_tag =
2144         syncable::ModelTypeToRootTag(syncable::PASSWORDS);
2145     if (!passwords_root.InitByTagLookup(passwords_tag)) {
2146       LOG(WARNING) << "No passwords to reencrypt.";
2147       return;
2148     }
2149 
2150     int64 child_id = passwords_root.GetFirstChildId();
2151     while (child_id != kInvalidId) {
2152       WriteNode child(trans);
2153       if (!child.InitByIdLookup(child_id)) {
2154         NOTREACHED();
2155         return;
2156       }
2157       child.SetPasswordSpecifics(child.GetPasswordSpecifics());
2158       child_id = child.GetSuccessorId();
2159     }
2160   }
2161 
2162   FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2163                     OnEncryptionComplete(encrypted_types));
2164 }
2165 
~SyncManager()2166 SyncManager::~SyncManager() {
2167   delete data_;
2168 }
2169 
AddObserver(Observer * observer)2170 void SyncManager::AddObserver(Observer* observer) {
2171   data_->AddObserver(observer);
2172 }
2173 
RemoveObserver(Observer * observer)2174 void SyncManager::RemoveObserver(Observer* observer) {
2175   data_->RemoveObserver(observer);
2176 }
2177 
GetJsBackend()2178 browser_sync::JsBackend* SyncManager::GetJsBackend() {
2179   return data_;
2180 }
2181 
Shutdown()2182 void SyncManager::Shutdown() {
2183   data_->Shutdown();
2184 }
2185 
Shutdown()2186 void SyncManager::SyncInternal::Shutdown() {
2187   method_factory_.RevokeAll();
2188 
2189   if (syncer_thread()) {
2190     syncer_thread()->Stop();
2191     syncer_thread_.reset();
2192   }
2193 
2194   // We NULL out sync_notifer_ so that any pending tasks do not
2195   // trigger further notifications.
2196   // TODO(akalin): NULL the other member variables defensively, too.
2197   if (sync_notifier_) {
2198     sync_notifier_->RemoveObserver(this);
2199   }
2200 
2201   // |this| is about to be destroyed, so we have to ensure any messages
2202   // that were posted to core_thread_ before or during syncer thread shutdown
2203   // are flushed out, else they refer to garbage memory.  SendNotification
2204   // is an example.
2205   // TODO(tim): Remove this monstrosity, perhaps with ObserverListTS once core
2206   // thread is removed. Bug 78190.
2207   {
2208     CHECK(core_message_loop_);
2209     bool old_state = core_message_loop_->NestableTasksAllowed();
2210     core_message_loop_->SetNestableTasksAllowed(true);
2211     core_message_loop_->RunAllPending();
2212     core_message_loop_->SetNestableTasksAllowed(old_state);
2213   }
2214 
2215   net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
2216 
2217   connection_manager_hookup_.reset();
2218 
2219   if (dir_manager()) {
2220     dir_manager()->FinalSaveChangesForAll();
2221     dir_manager()->Close(username_for_share());
2222   }
2223 
2224   // Reset the DirectoryManager and UserSettings so they relinquish sqlite
2225   // handles to backing files.
2226   share_.dir_manager.reset();
2227 
2228   core_message_loop_ = NULL;
2229 }
2230 
OnIPAddressChanged()2231 void SyncManager::SyncInternal::OnIPAddressChanged() {
2232   VLOG(1) << "IP address change detected";
2233 #if defined (OS_CHROMEOS)
2234   // TODO(tim): This is a hack to intentionally lose a race with flimflam at
2235   // shutdown, so we don't cause shutdown to wait for our http request.
2236   // http://crosbug.com/8429
2237   MessageLoop::current()->PostDelayedTask(FROM_HERE,
2238       method_factory_.NewRunnableMethod(&SyncInternal::OnIPAddressChangedImpl),
2239       kChromeOSNetworkChangeReactionDelayHackMsec);
2240 #else
2241   OnIPAddressChangedImpl();
2242 #endif  // defined(OS_CHROMEOS)
2243 }
2244 
OnIPAddressChangedImpl()2245 void SyncManager::SyncInternal::OnIPAddressChangedImpl() {
2246   // TODO(akalin): CheckServerReachable() can block, which may cause
2247   // jank if we try to shut down sync.  Fix this.
2248   connection_manager()->CheckServerReachable();
2249   RequestNudge(FROM_HERE);
2250 }
2251 
OnServerConnectionEvent(const ServerConnectionEvent2 & event)2252 void SyncManager::SyncInternal::OnServerConnectionEvent(
2253     const ServerConnectionEvent2& event) {
2254   ServerConnectionEvent legacy;
2255   legacy.what_happened = ServerConnectionEvent::STATUS_CHANGED;
2256   legacy.connection_code = event.connection_code;
2257   legacy.server_reachable = event.server_reachable;
2258   HandleServerConnectionEvent(legacy);
2259 }
2260 
HandleServerConnectionEvent(const ServerConnectionEvent & event)2261 void SyncManager::SyncInternal::HandleServerConnectionEvent(
2262     const ServerConnectionEvent& event) {
2263   allstatus_.HandleServerConnectionEvent(event);
2264   if (event.what_happened == ServerConnectionEvent::STATUS_CHANGED) {
2265     if (event.connection_code ==
2266         browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
2267       FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2268                         OnAuthError(AuthError::None()));
2269     }
2270 
2271     if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
2272       FOR_EACH_OBSERVER(
2273           SyncManager::Observer, observers_,
2274           OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
2275     }
2276   }
2277 }
2278 
HandleTransactionCompleteChangeEvent(const syncable::ModelTypeBitSet & models_with_changes)2279 void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
2280     const syncable::ModelTypeBitSet& models_with_changes) {
2281   // This notification happens immediately after the transaction mutex is
2282   // released. This allows work to be performed without blocking other threads
2283   // from acquiring a transaction.
2284   if (observers_.size() <= 0)
2285     return;
2286 
2287   // Call commit.
2288   for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
2289     if (models_with_changes.test(i)) {
2290       FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2291                         OnChangesComplete(syncable::ModelTypeFromInt(i)));
2292     }
2293   }
2294 }
2295 
HandleTransactionEndingChangeEvent(syncable::BaseTransaction * trans)2296 ModelTypeBitSet SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
2297     syncable::BaseTransaction* trans) {
2298   // This notification happens immediately before a syncable WriteTransaction
2299   // falls out of scope. It happens while the channel mutex is still held,
2300   // and while the transaction mutex is held, so it cannot be re-entrant.
2301   if (observers_.size() <= 0 || ChangeBuffersAreEmpty())
2302     return ModelTypeBitSet();
2303 
2304   // This will continue the WriteTransaction using a read only wrapper.
2305   // This is the last chance for read to occur in the WriteTransaction
2306   // that's closing. This special ReadTransaction will not close the
2307   // underlying transaction.
2308   ReadTransaction read_trans(GetUserShare(), trans);
2309 
2310   syncable::ModelTypeBitSet models_with_changes;
2311   for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
2312     if (change_buffers_[i].IsEmpty())
2313       continue;
2314 
2315     vector<ChangeRecord> ordered_changes;
2316     change_buffers_[i].GetAllChangesInTreeOrder(&read_trans, &ordered_changes);
2317     if (!ordered_changes.empty()) {
2318       FOR_EACH_OBSERVER(
2319           SyncManager::Observer, observers_,
2320           OnChangesApplied(syncable::ModelTypeFromInt(i), &read_trans,
2321                            &ordered_changes[0], ordered_changes.size()));
2322       models_with_changes.set(i, true);
2323     }
2324     change_buffers_[i].Clear();
2325   }
2326   return models_with_changes;
2327 }
2328 
HandleCalculateChangesChangeEventFromSyncApi(const OriginalEntries & originals,const WriterTag & writer,syncable::BaseTransaction * trans)2329 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
2330     const OriginalEntries& originals,
2331     const WriterTag& writer,
2332     syncable::BaseTransaction* trans) {
2333   // We have been notified about a user action changing a sync model.
2334   DCHECK(writer == syncable::SYNCAPI ||
2335          writer == syncable::UNITTEST);
2336   LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
2337       "CALCULATE_CHANGES called with unapplied old changes.";
2338 
2339   bool exists_unsynced_items = false;
2340   bool only_preference_changes = true;
2341   syncable::ModelTypeBitSet model_types;
2342   for (syncable::OriginalEntries::const_iterator i = originals.begin();
2343        i != originals.end() && !exists_unsynced_items;
2344        ++i) {
2345     int64 id = i->ref(syncable::META_HANDLE);
2346     syncable::Entry e(trans, syncable::GET_BY_HANDLE, id);
2347     DCHECK(e.good());
2348 
2349     syncable::ModelType model_type = e.GetModelType();
2350 
2351     if (e.Get(syncable::IS_UNSYNCED)) {
2352       if (model_type == syncable::TOP_LEVEL_FOLDER ||
2353           model_type == syncable::UNSPECIFIED) {
2354         NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
2355         continue;
2356       }
2357       // Unsynced items will cause us to nudge the the syncer.
2358       exists_unsynced_items = true;
2359 
2360       model_types[model_type] = true;
2361       if (model_type != syncable::PREFERENCES)
2362         only_preference_changes = false;
2363     }
2364   }
2365   if (exists_unsynced_items && syncer_thread()) {
2366     int nudge_delay = only_preference_changes ?
2367         kPreferencesNudgeDelayMilliseconds : kDefaultNudgeDelayMilliseconds;
2368     core_message_loop_->PostTask(FROM_HERE,
2369         NewRunnableMethod(this, &SyncInternal::RequestNudgeWithDataTypes,
2370         TimeDelta::FromMilliseconds(nudge_delay),
2371         browser_sync::NUDGE_SOURCE_LOCAL,
2372         model_types,
2373         FROM_HERE));
2374   }
2375 }
2376 
SetExtraChangeRecordData(int64 id,syncable::ModelType type,ChangeReorderBuffer * buffer,Cryptographer * cryptographer,const syncable::EntryKernel & original,bool existed_before,bool exists_now)2377 void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
2378     syncable::ModelType type, ChangeReorderBuffer* buffer,
2379     Cryptographer* cryptographer, const syncable::EntryKernel& original,
2380     bool existed_before, bool exists_now) {
2381   // If this is a deletion and the datatype was encrypted, we need to decrypt it
2382   // and attach it to the buffer.
2383   if (!exists_now && existed_before) {
2384     sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
2385     if (type == syncable::PASSWORDS) {
2386       // Passwords must use their own legacy ExtraPasswordChangeRecordData.
2387       scoped_ptr<sync_pb::PasswordSpecificsData> data(
2388           DecryptPasswordSpecifics(original_specifics, cryptographer));
2389       if (!data.get()) {
2390         NOTREACHED();
2391         return;
2392       }
2393       buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
2394     } else if (original_specifics.has_encrypted()) {
2395       // All other datatypes can just create a new unencrypted specifics and
2396       // attach it.
2397       const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
2398       if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
2399         NOTREACHED();
2400         return;
2401       }
2402     }
2403     buffer->SetSpecificsForId(id, original_specifics);
2404   }
2405 }
2406 
HandleCalculateChangesChangeEventFromSyncer(const OriginalEntries & originals,const WriterTag & writer,syncable::BaseTransaction * trans)2407 void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
2408     const OriginalEntries& originals,
2409     const WriterTag& writer,
2410     syncable::BaseTransaction* trans) {
2411   // We only expect one notification per sync step, so change_buffers_ should
2412   // contain no pending entries.
2413   DCHECK(writer == syncable::SYNCER ||
2414          writer == syncable::UNITTEST);
2415   LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
2416       "CALCULATE_CHANGES called with unapplied old changes.";
2417 
2418   Cryptographer* crypto = dir_manager()->GetCryptographer(trans);
2419   for (syncable::OriginalEntries::const_iterator i = originals.begin();
2420        i != originals.end(); ++i) {
2421     int64 id = i->ref(syncable::META_HANDLE);
2422     syncable::Entry e(trans, syncable::GET_BY_HANDLE, id);
2423     bool existed_before = !i->ref(syncable::IS_DEL);
2424     bool exists_now = e.good() && !e.Get(syncable::IS_DEL);
2425     DCHECK(e.good());
2426 
2427     // Omit items that aren't associated with a model.
2428     syncable::ModelType type = e.GetModelType();
2429     if (type == syncable::TOP_LEVEL_FOLDER || type == syncable::UNSPECIFIED)
2430       continue;
2431 
2432     if (exists_now && !existed_before)
2433       change_buffers_[type].PushAddedItem(id);
2434     else if (!exists_now && existed_before)
2435       change_buffers_[type].PushDeletedItem(id);
2436     else if (exists_now && existed_before &&
2437              VisiblePropertiesDiffer(*i, e, crypto)) {
2438       change_buffers_[type].PushUpdatedItem(id, VisiblePositionsDiffer(*i, e));
2439     }
2440 
2441     SetExtraChangeRecordData(id, type, &change_buffers_[type], crypto, *i,
2442                              existed_before, exists_now);
2443   }
2444 }
2445 
GetStatus()2446 SyncManager::Status SyncManager::SyncInternal::GetStatus() {
2447   return allstatus_.status();
2448 }
2449 
RequestNudge(const tracked_objects::Location & location)2450 void SyncManager::SyncInternal::RequestNudge(
2451     const tracked_objects::Location& location) {
2452   if (syncer_thread())
2453      syncer_thread()->ScheduleNudge(
2454         TimeDelta::FromMilliseconds(0), browser_sync::NUDGE_SOURCE_LOCAL,
2455         ModelTypeBitSet(), location);
2456 }
2457 
RequestNudgeWithDataTypes(const TimeDelta & delay,browser_sync::NudgeSource source,const ModelTypeBitSet & types,const tracked_objects::Location & nudge_location)2458 void SyncManager::SyncInternal::RequestNudgeWithDataTypes(
2459     const TimeDelta& delay,
2460     browser_sync::NudgeSource source, const ModelTypeBitSet& types,
2461     const tracked_objects::Location& nudge_location) {
2462   if (syncer_thread())
2463      syncer_thread()->ScheduleNudge(delay, source, types, nudge_location);
2464 }
2465 
OnSyncEngineEvent(const SyncEngineEvent & event)2466 void SyncManager::SyncInternal::OnSyncEngineEvent(
2467     const SyncEngineEvent& event) {
2468   if (observers_.size() <= 0)
2469     return;
2470 
2471   // Only send an event if this is due to a cycle ending and this cycle
2472   // concludes a canonical "sync" process; that is, based on what is known
2473   // locally we are "all happy" and up-to-date.  There may be new changes on
2474   // the server, but we'll get them on a subsequent sync.
2475   //
2476   // Notifications are sent at the end of every sync cycle, regardless of
2477   // whether we should sync again.
2478   if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
2479     ModelSafeRoutingInfo enabled_types;
2480     registrar_->GetModelSafeRoutingInfo(&enabled_types);
2481     {
2482       // Check to see if we need to notify the frontend that we have newly
2483       // encrypted types or that we require a passphrase.
2484       sync_api::ReadTransaction trans(GetUserShare());
2485       sync_api::ReadNode node(&trans);
2486       if (!node.InitByTagLookup(kNigoriTag)) {
2487         DCHECK(!event.snapshot->is_share_usable);
2488         return;
2489       }
2490       const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics();
2491       syncable::ModelTypeSet encrypted_types =
2492           syncable::GetEncryptedDataTypesFromNigori(nigori);
2493       // If passwords are enabled, they're automatically considered encrypted.
2494       if (enabled_types.count(syncable::PASSWORDS) > 0)
2495         encrypted_types.insert(syncable::PASSWORDS);
2496       if (!encrypted_types.empty()) {
2497         Cryptographer* cryptographer = trans.GetCryptographer();
2498         if (!cryptographer->is_ready() && !cryptographer->has_pending_keys()) {
2499           if (!nigori.encrypted().blob().empty()) {
2500             DCHECK(!cryptographer->CanDecrypt(nigori.encrypted()));
2501             cryptographer->SetPendingKeys(nigori.encrypted());
2502           }
2503         }
2504 
2505         // If we've completed a sync cycle and the cryptographer isn't ready
2506         // yet, prompt the user for a passphrase.
2507         if (cryptographer->has_pending_keys()) {
2508           FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2509                             OnPassphraseRequired(true));
2510         } else if (!cryptographer->is_ready()) {
2511           FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2512                             OnPassphraseRequired(false));
2513         } else {
2514           FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2515                             OnEncryptionComplete(encrypted_types));
2516         }
2517       }
2518     }
2519 
2520     if (!initialized())
2521       return;
2522 
2523     if (!event.snapshot->has_more_to_sync) {
2524       FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2525                         OnSyncCycleCompleted(event.snapshot));
2526     }
2527 
2528     // This is here for tests, which are still using p2p notifications.
2529     // SendNotification does not do anything if we are using server based
2530     // notifications.
2531     // TODO(chron): Consider changing this back to track has_more_to_sync
2532     // only notify peers if a successful commit has occurred.
2533     bool new_notification =
2534         (event.snapshot->syncer_status.num_successful_commits > 0);
2535     if (new_notification) {
2536       core_message_loop_->PostTask(
2537           FROM_HERE,
2538           NewRunnableMethod(
2539               this,
2540               &SyncManager::SyncInternal::SendNotification));
2541     }
2542   }
2543 
2544   if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
2545     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2546                       OnStopSyncingPermanently());
2547     return;
2548   }
2549 
2550   if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
2551     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2552                       OnClearServerDataSucceeded());
2553     return;
2554   }
2555 
2556   if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
2557     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2558                       OnClearServerDataFailed());
2559     return;
2560   }
2561 
2562   if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
2563     FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
2564                       OnUpdatedToken(event.updated_token));
2565     return;
2566   }
2567 }
2568 
SetParentJsEventRouter(browser_sync::JsEventRouter * router)2569 void SyncManager::SyncInternal::SetParentJsEventRouter(
2570     browser_sync::JsEventRouter* router) {
2571   DCHECK(router);
2572   parent_router_ = router;
2573 }
2574 
RemoveParentJsEventRouter()2575 void SyncManager::SyncInternal::RemoveParentJsEventRouter() {
2576   parent_router_ = NULL;
2577 }
2578 
2579 const browser_sync::JsEventRouter*
GetParentJsEventRouter() const2580     SyncManager::SyncInternal::GetParentJsEventRouter() const {
2581   return parent_router_;
2582 }
2583 
2584 namespace {
2585 
LogNoRouter(const std::string & name,const browser_sync::JsArgList & args)2586 void LogNoRouter(const std::string& name,
2587                  const browser_sync::JsArgList& args) {
2588   VLOG(1) << "No parent router; not replying to message " << name
2589           << " with args " << args.ToString();
2590 }
2591 
2592 }  // namespace
2593 
ProcessMessage(const std::string & name,const browser_sync::JsArgList & args,const browser_sync::JsEventHandler * sender)2594 void SyncManager::SyncInternal::ProcessMessage(
2595     const std::string& name, const browser_sync::JsArgList& args,
2596     const browser_sync::JsEventHandler* sender) {
2597   DCHECK(initialized_);
2598   if (name == "getNotificationState") {
2599     if (!parent_router_) {
2600       LogNoRouter(name, args);
2601       return;
2602     }
2603     bool notifications_enabled = allstatus_.status().notifications_enabled;
2604     ListValue return_args;
2605     return_args.Append(Value::CreateBooleanValue(notifications_enabled));
2606     parent_router_->RouteJsEvent(
2607         "onGetNotificationStateFinished",
2608         browser_sync::JsArgList(return_args), sender);
2609   } else if (name == "getNotificationInfo") {
2610     if (!parent_router_) {
2611       LogNoRouter(name, args);
2612       return;
2613     }
2614 
2615     ListValue return_args;
2616     return_args.Append(NotificationInfoToValue(notification_info_map_));
2617     parent_router_->RouteJsEvent("onGetNotificationInfoFinished",
2618         browser_sync::JsArgList(return_args), sender);
2619   } else if (name == "getRootNode") {
2620     if (!parent_router_) {
2621       LogNoRouter(name, args);
2622       return;
2623     }
2624     ReadTransaction trans(GetUserShare());
2625     ReadNode root(&trans);
2626     root.InitByRootLookup();
2627     ListValue return_args;
2628     return_args.Append(root.ToValue());
2629     parent_router_->RouteJsEvent(
2630         "onGetRootNodeFinished",
2631         browser_sync::JsArgList(return_args), sender);
2632   } else if (name == "getNodeById") {
2633     if (!parent_router_) {
2634       LogNoRouter(name, args);
2635       return;
2636     }
2637     parent_router_->RouteJsEvent(
2638         "onGetNodeByIdFinished", ProcessGetNodeByIdMessage(args), sender);
2639   } else if (name == "findNodesContainingString") {
2640     if (!parent_router_) {
2641       LogNoRouter(name, args);
2642       return;
2643     }
2644     parent_router_->RouteJsEvent(
2645         "onFindNodesContainingStringFinished",
2646         ProcessFindNodesContainingString(args), sender);
2647   } else {
2648     VLOG(1) << "Dropping unknown message " << name
2649               << " with args " << args.ToString();
2650   }
2651 }
2652 
ProcessGetNodeByIdMessage(const browser_sync::JsArgList & args)2653 browser_sync::JsArgList SyncManager::SyncInternal::ProcessGetNodeByIdMessage(
2654     const browser_sync::JsArgList& args) {
2655   ListValue null_return_args_list;
2656   null_return_args_list.Append(Value::CreateNullValue());
2657   browser_sync::JsArgList null_return_args(null_return_args_list);
2658   std::string id_str;
2659   if (!args.Get().GetString(0, &id_str)) {
2660     return null_return_args;
2661   }
2662   int64 id;
2663   if (!base::StringToInt64(id_str, &id)) {
2664     return null_return_args;
2665   }
2666   if (id == kInvalidId) {
2667     return null_return_args;
2668   }
2669   ReadTransaction trans(GetUserShare());
2670   ReadNode node(&trans);
2671   if (!node.InitByIdLookup(id)) {
2672     return null_return_args;
2673   }
2674   ListValue return_args;
2675   return_args.Append(node.ToValue());
2676   return browser_sync::JsArgList(return_args);
2677 }
2678 
2679 browser_sync::JsArgList SyncManager::SyncInternal::
ProcessFindNodesContainingString(const browser_sync::JsArgList & args)2680     ProcessFindNodesContainingString(
2681     const browser_sync::JsArgList& args) {
2682   std::string query;
2683   ListValue return_args;
2684   if (!args.Get().GetString(0, &query)) {
2685     return_args.Append(new ListValue());
2686     return browser_sync::JsArgList(return_args);
2687   }
2688 
2689   ListValue* result = FindNodesContainingString(query);
2690   return_args.Append(result);
2691   return browser_sync::JsArgList(return_args);
2692 }
2693 
OnNotificationStateChange(bool notifications_enabled)2694 void SyncManager::SyncInternal::OnNotificationStateChange(
2695     bool notifications_enabled) {
2696   VLOG(1) << "P2P: Notifications enabled = "
2697           << (notifications_enabled ? "true" : "false");
2698   allstatus_.SetNotificationsEnabled(notifications_enabled);
2699   if (syncer_thread()) {
2700     syncer_thread()->set_notifications_enabled(notifications_enabled);
2701   }
2702   if (parent_router_) {
2703     ListValue args;
2704     args.Append(Value::CreateBooleanValue(notifications_enabled));
2705     // TODO(akalin): Tidy up grammar in event names.
2706     parent_router_->RouteJsEvent("onSyncNotificationStateChange",
2707                                  browser_sync::JsArgList(args), NULL);
2708   }
2709 }
2710 
UpdateNotificationInfo(const syncable::ModelTypePayloadMap & type_payloads)2711 void SyncManager::SyncInternal::UpdateNotificationInfo(
2712     const syncable::ModelTypePayloadMap& type_payloads) {
2713   for (syncable::ModelTypePayloadMap::const_iterator it = type_payloads.begin();
2714        it != type_payloads.end(); ++it) {
2715     NotificationInfo* info = &notification_info_map_[it->first];
2716     info->total_count++;
2717     info->payload = it->second;
2718   }
2719 }
2720 
OnIncomingNotification(const syncable::ModelTypePayloadMap & type_payloads)2721 void SyncManager::SyncInternal::OnIncomingNotification(
2722     const syncable::ModelTypePayloadMap& type_payloads) {
2723   if (!type_payloads.empty()) {
2724     if (syncer_thread()) {
2725       syncer_thread()->ScheduleNudgeWithPayloads(
2726           TimeDelta::FromMilliseconds(kSyncerThreadDelayMsec),
2727           browser_sync::NUDGE_SOURCE_NOTIFICATION,
2728           type_payloads, FROM_HERE);
2729     }
2730     allstatus_.IncrementNotificationsReceived();
2731     UpdateNotificationInfo(type_payloads);
2732   } else {
2733     LOG(WARNING) << "Sync received notification without any type information.";
2734   }
2735 
2736   if (parent_router_) {
2737     ListValue args;
2738     ListValue* changed_types = new ListValue();
2739     args.Append(changed_types);
2740     for (syncable::ModelTypePayloadMap::const_iterator
2741              it = type_payloads.begin();
2742          it != type_payloads.end(); ++it) {
2743       const std::string& model_type_str =
2744           syncable::ModelTypeToString(it->first);
2745       changed_types->Append(Value::CreateStringValue(model_type_str));
2746     }
2747     parent_router_->RouteJsEvent("onSyncIncomingNotification",
2748                                  browser_sync::JsArgList(args), NULL);
2749   }
2750 }
2751 
StoreState(const std::string & state)2752 void SyncManager::SyncInternal::StoreState(
2753     const std::string& state) {
2754   syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2755   if (!lookup.good()) {
2756     LOG(ERROR) << "Could not write notification state";
2757     // TODO(akalin): Propagate result callback all the way to this
2758     // function and call it with "false" to signal failure.
2759     return;
2760   }
2761   if (VLOG_IS_ON(1)) {
2762     std::string encoded_state;
2763     base::Base64Encode(state, &encoded_state);
2764     VLOG(1) << "Writing notification state: " << encoded_state;
2765   }
2766   lookup->SetNotificationState(state);
2767   lookup->SaveChanges();
2768 }
2769 
AddObserver(SyncManager::Observer * observer)2770 void SyncManager::SyncInternal::AddObserver(
2771     SyncManager::Observer* observer) {
2772   observers_.AddObserver(observer);
2773 }
2774 
RemoveObserver(SyncManager::Observer * observer)2775 void SyncManager::SyncInternal::RemoveObserver(
2776     SyncManager::Observer* observer) {
2777   observers_.RemoveObserver(observer);
2778 }
2779 
GetStatusSummary() const2780 SyncManager::Status::Summary SyncManager::GetStatusSummary() const {
2781   return data_->GetStatus().summary;
2782 }
2783 
GetDetailedStatus() const2784 SyncManager::Status SyncManager::GetDetailedStatus() const {
2785   return data_->GetStatus();
2786 }
2787 
GetImpl() const2788 SyncManager::SyncInternal* SyncManager::GetImpl() const { return data_; }
2789 
SaveChanges()2790 void SyncManager::SaveChanges() {
2791   data_->SaveChanges();
2792 }
2793 
SaveChanges()2794 void SyncManager::SyncInternal::SaveChanges() {
2795   syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2796   if (!lookup.good()) {
2797     DCHECK(false) << "ScopedDirLookup creation failed; Unable to SaveChanges";
2798     return;
2799   }
2800   lookup->SaveChanges();
2801 }
2802 
2803 //////////////////////////////////////////////////////////////////////////
2804 // BaseTransaction member definitions
BaseTransaction(UserShare * share)2805 BaseTransaction::BaseTransaction(UserShare* share)
2806     : lookup_(NULL) {
2807   DCHECK(share && share->dir_manager.get());
2808   lookup_ = new syncable::ScopedDirLookup(share->dir_manager.get(),
2809                                           share->name);
2810   cryptographer_ = share->dir_manager->GetCryptographer(this);
2811   if (!(lookup_->good()))
2812     DCHECK(false) << "ScopedDirLookup failed on valid DirManager.";
2813 }
~BaseTransaction()2814 BaseTransaction::~BaseTransaction() {
2815   delete lookup_;
2816 }
2817 
GetUserShare() const2818 UserShare* SyncManager::GetUserShare() const {
2819   DCHECK(data_->initialized()) << "GetUserShare requires initialization!";
2820   return data_->GetUserShare();
2821 }
2822 
HasUnsyncedItems() const2823 bool SyncManager::HasUnsyncedItems() const {
2824   sync_api::ReadTransaction trans(GetUserShare());
2825   return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
2826 }
2827 
TriggerOnNotificationStateChangeForTest(bool notifications_enabled)2828 void SyncManager::TriggerOnNotificationStateChangeForTest(
2829     bool notifications_enabled) {
2830   data_->OnNotificationStateChange(notifications_enabled);
2831 }
2832 
TriggerOnIncomingNotificationForTest(const syncable::ModelTypeBitSet & model_types)2833 void SyncManager::TriggerOnIncomingNotificationForTest(
2834     const syncable::ModelTypeBitSet& model_types) {
2835   syncable::ModelTypePayloadMap model_types_with_payloads =
2836       syncable::ModelTypePayloadMapFromBitSet(model_types,
2837           std::string());
2838 
2839   data_->OnIncomingNotification(model_types_with_payloads);
2840 }
2841 
2842 }  // namespace sync_api
2843