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
71using base::TimeDelta;
72using browser_sync::AllStatus;
73using browser_sync::Cryptographer;
74using browser_sync::KeyParams;
75using browser_sync::ModelSafeRoutingInfo;
76using browser_sync::ModelSafeWorker;
77using browser_sync::ModelSafeWorkerRegistrar;
78using browser_sync::ServerConnectionEvent;
79using browser_sync::ServerConnectionEvent2;
80using browser_sync::ServerConnectionEventListener;
81using browser_sync::SyncEngineEvent;
82using browser_sync::SyncEngineEventListener;
83using browser_sync::Syncer;
84using browser_sync::SyncerThread;
85using browser_sync::kNigoriTag;
86using browser_sync::sessions::SyncSessionContext;
87using std::list;
88using std::hex;
89using std::string;
90using std::vector;
91using syncable::Directory;
92using syncable::DirectoryManager;
93using syncable::Entry;
94using syncable::ModelTypeBitSet;
95using syncable::OriginalEntries;
96using syncable::WriterTag;
97using syncable::SPECIFICS;
98using sync_pb::AutofillProfileSpecifics;
99
100typedef GoogleServiceAuthError AuthError;
101
102static const int kThreadExitTimeoutMsec = 60000;
103static const int kSSLPort = 443;
104static const int kSyncerThreadDelayMsec = 250;
105
106#if defined(OS_CHROMEOS)
107static const int kChromeOSNetworkChangeReactionDelayHackMsec = 5000;
108#endif  // OS_CHROMEOS
109
110// We manage the lifetime of sync_api::SyncManager::SyncInternal ourselves.
111DISABLE_RUNNABLE_METHOD_REFCOUNT(sync_api::SyncManager::SyncInternal);
112
113namespace sync_api {
114
115static const FilePath::CharType kBookmarkSyncUserSettingsDatabase[] =
116    FILE_PATH_LITERAL("BookmarkSyncSettings.sqlite3");
117static const char kDefaultNameForNewNodes[] = " ";
118
119// The list of names which are reserved for use by the server.
120static 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.
127static 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.
139static 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
148static 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.
154static 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.
164static 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
175UserShare::UserShare() {}
176
177UserShare::~UserShare() {}
178
179////////////////////////////////////
180// BaseNode member definitions.
181
182BaseNode::BaseNode() {}
183
184BaseNode::~BaseNode() {}
185
186std::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
201sync_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
217bool 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
249const 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
263int64 BaseNode::GetParentId() const {
264  return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
265                        GetEntry()->Get(syncable::PARENT_ID));
266}
267
268int64 BaseNode::GetId() const {
269  return GetEntry()->Get(syncable::META_HANDLE);
270}
271
272int64 BaseNode::GetModificationTime() const {
273  return GetEntry()->Get(syncable::MTIME);
274}
275
276bool BaseNode::GetIsFolder() const {
277  return GetEntry()->Get(syncable::IS_DIR);
278}
279
280std::wstring BaseNode::GetTitle() const {
281  std::wstring result;
282  ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME), &result);
283  return result;
284}
285
286GURL BaseNode::GetURL() const {
287  return GURL(GetBookmarkSpecifics().url());
288}
289
290int64 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
297int64 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
304int64 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
314DictionaryValue* 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
339void 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
348int64 BaseNode::GetExternalId() const {
349  return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
350}
351
352const 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
359const 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
366const 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
373const 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
380const 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
387const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
388  DCHECK_EQ(syncable::PASSWORDS, GetModelType());
389  DCHECK(password_data_.get());
390  return *password_data_;
391}
392
393const 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
400const 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
407const 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
414const 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
421const 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
428syncable::ModelType BaseNode::GetModelType() const {
429  return GetEntry()->GetModelType();
430}
431
432////////////////////////////////////
433// WriteNode member definitions
434void 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
468void 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
476void 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
489void 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
495void WriteNode::SetAppSpecifics(
496    const sync_pb::AppSpecifics& new_value) {
497  DCHECK_EQ(syncable::APPS, GetModelType());
498  PutAppSpecificsAndMarkForSyncing(new_value);
499}
500
501void WriteNode::SetAutofillSpecifics(
502    const sync_pb::AutofillSpecifics& new_value) {
503  DCHECK_EQ(syncable::AUTOFILL, GetModelType());
504  PutAutofillSpecificsAndMarkForSyncing(new_value);
505}
506
507void 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
515void WriteNode::SetAutofillProfileSpecifics(
516    const sync_pb::AutofillProfileSpecifics& new_value) {
517  DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
518  PutAutofillProfileSpecificsAndMarkForSyncing(new_value);
519}
520
521void 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
530void WriteNode::SetBookmarkSpecifics(
531    const sync_pb::BookmarkSpecifics& new_value) {
532  DCHECK_EQ(syncable::BOOKMARKS, GetModelType());
533  PutBookmarkSpecificsAndMarkForSyncing(new_value);
534}
535
536void 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
544void WriteNode::SetNigoriSpecifics(
545    const sync_pb::NigoriSpecifics& new_value) {
546  DCHECK_EQ(syncable::NIGORI, GetModelType());
547  PutNigoriSpecificsAndMarkForSyncing(new_value);
548}
549
550void 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
557void 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
584void WriteNode::SetPreferenceSpecifics(
585    const sync_pb::PreferenceSpecifics& new_value) {
586  DCHECK_EQ(syncable::PREFERENCES, GetModelType());
587  PutPreferenceSpecificsAndMarkForSyncing(new_value);
588}
589
590void WriteNode::SetThemeSpecifics(
591    const sync_pb::ThemeSpecifics& new_value) {
592  DCHECK_EQ(syncable::THEMES, GetModelType());
593  PutThemeSpecificsAndMarkForSyncing(new_value);
594}
595
596void WriteNode::SetSessionSpecifics(
597    const sync_pb::SessionSpecifics& new_value) {
598  DCHECK_EQ(syncable::SESSIONS, GetModelType());
599  PutSessionSpecificsAndMarkForSyncing(new_value);
600}
601
602void WriteNode::ResetFromSpecifics() {
603  sync_pb::EntitySpecifics new_data;
604  new_data.CopyFrom(GetUnencryptedSpecifics(GetEntry()));
605  EncryptIfNecessary(&new_data);
606  PutSpecificsAndMarkForSyncing(new_data);
607}
608
609void 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
616void 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
624void WriteNode::SetTypedUrlSpecifics(
625    const sync_pb::TypedUrlSpecifics& new_value) {
626  DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
627  PutTypedUrlSpecificsAndMarkForSyncing(new_value);
628}
629
630void WriteNode::SetExtensionSpecifics(
631    const sync_pb::ExtensionSpecifics& new_value) {
632  DCHECK_EQ(syncable::EXTENSIONS, GetModelType());
633  PutExtensionSpecificsAndMarkForSyncing(new_value);
634}
635
636void 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
644void 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
652void 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
660void 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
668void 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
676void 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
687void WriteNode::SetExternalId(int64 id) {
688  if (GetExternalId() != id)
689    entry_->Put(syncable::LOCAL_EXTERNAL_ID, id);
690}
691
692WriteNode::WriteNode(WriteTransaction* transaction)
693    : entry_(NULL), transaction_(transaction) {
694  DCHECK(transaction);
695}
696
697WriteNode::~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.
703bool 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.
715bool 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
729bool 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
744void 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.
758bool 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?
797bool 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
869bool 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
899const syncable::Entry* WriteNode::GetEntry() const {
900  return entry_;
901}
902
903const BaseTransaction* WriteNode::GetTransaction() const {
904  return transaction_;
905}
906
907void WriteNode::Remove() {
908  entry_->Put(syncable::IS_DEL, true);
909  MarkForSyncing();
910}
911
912void 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
920void 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
926void WriteNode::MarkForSyncing() {
927  syncable::MarkForSyncing(entry_);
928}
929
930//////////////////////////////////////////////////////////////////////////
931// ReadNode member definitions
932ReadNode::ReadNode(const BaseTransaction* transaction)
933    : entry_(NULL), transaction_(transaction) {
934  DCHECK(transaction);
935}
936
937ReadNode::ReadNode() {
938  entry_ = NULL;
939  transaction_ = NULL;
940}
941
942ReadNode::~ReadNode() {
943  delete entry_;
944}
945
946void 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
954bool 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
970bool 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
984const syncable::Entry* ReadNode::GetEntry() const {
985  return entry_;
986}
987
988const BaseTransaction* ReadNode::GetTransaction() const {
989  return transaction_;
990}
991
992bool 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
1011ReadTransaction::ReadTransaction(UserShare* share)
1012    : BaseTransaction(share),
1013      transaction_(NULL),
1014      close_transaction_(true) {
1015  transaction_ = new syncable::ReadTransaction(GetLookup(), __FILE__, __LINE__);
1016}
1017
1018ReadTransaction::ReadTransaction(UserShare* share,
1019                                 syncable::BaseTransaction* trans)
1020    : BaseTransaction(share),
1021      transaction_(trans),
1022      close_transaction_(false) {}
1023
1024ReadTransaction::~ReadTransaction() {
1025  if (close_transaction_) {
1026    delete transaction_;
1027  }
1028}
1029
1030syncable::BaseTransaction* ReadTransaction::GetWrappedTrans() const {
1031  return transaction_;
1032}
1033
1034//////////////////////////////////////////////////////////////////////////
1035// WriteTransaction member definitions
1036WriteTransaction::WriteTransaction(UserShare* share)
1037    : BaseTransaction(share),
1038      transaction_(NULL) {
1039  transaction_ = new syncable::WriteTransaction(GetLookup(), syncable::SYNCAPI,
1040                                                __FILE__, __LINE__);
1041}
1042
1043WriteTransaction::~WriteTransaction() {
1044  delete transaction_;
1045}
1046
1047syncable::BaseTransaction* WriteTransaction::GetWrappedTrans() const {
1048  return transaction_;
1049}
1050
1051SyncManager::ChangeRecord::ChangeRecord()
1052    : id(kInvalidId), action(ACTION_ADD) {}
1053
1054SyncManager::ChangeRecord::~ChangeRecord() {}
1055
1056DictionaryValue* 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
1100bool 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
1115SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData() {}
1116
1117SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData(
1118    const sync_pb::PasswordSpecificsData& data)
1119    : unencrypted_(data) {
1120}
1121
1122SyncManager::ExtraPasswordChangeRecordData::~ExtraPasswordChangeRecordData() {}
1123
1124DictionaryValue* SyncManager::ExtraPasswordChangeRecordData::ToValue() const {
1125  return browser_sync::PasswordSpecificsDataToValue(unencrypted_);
1126}
1127
1128const sync_pb::PasswordSpecificsData&
1129    SyncManager::ExtraPasswordChangeRecordData::unencrypted() const {
1130  return unencrypted_;
1131}
1132
1133namespace {
1134
1135struct NotificationInfo {
1136  int total_count;
1137  std::string payload;
1138
1139  NotificationInfo() : total_count(0) {}
1140
1141  ~NotificationInfo() {}
1142
1143  // Returned pointer owned by the caller.
1144  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
1152typedef std::map<syncable::ModelType, NotificationInfo> NotificationInfoMap;
1153
1154// returned pointer is owned by the caller.
1155DictionaryValue* 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
1173class 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:
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
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.
1277  DirectoryManager* dir_manager() { return share_.dir_manager.get(); }
1278  SyncAPIServerConnectionManager* connection_manager() {
1279    return connection_manager_.get();
1280  }
1281  SyncerThread* syncer_thread() { return syncer_thread_.get(); }
1282  UserShare* GetUserShare() { return &share_; }
1283
1284  // Return the currently active (validated) username for use with syncable
1285  // types.
1286  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.
1303  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
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
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
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
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
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.
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.
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
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
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};
1580const int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
1581const int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
1582
1583SyncManager::Observer::~Observer() {}
1584
1585SyncManager::SyncManager() {
1586  data_ = new SyncInternal(this);
1587}
1588
1589bool 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
1616void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
1617  data_->UpdateCredentials(credentials);
1618}
1619
1620void SyncManager::UpdateEnabledTypes() {
1621  data_->UpdateEnabledTypes();
1622}
1623
1624
1625bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
1626  return data_->InitialSyncEndedForAllEnabledTypes();
1627}
1628
1629void SyncManager::StartSyncing() {
1630  data_->StartSyncing();
1631}
1632
1633syncable::AutofillMigrationState
1634    SyncManager::GetAutofillMigrationState() {
1635  return data_->GetAutofillMigrationState();
1636}
1637
1638void SyncManager::SetAutofillMigrationState(
1639    syncable::AutofillMigrationState state) {
1640  return data_->SetAutofillMigrationState(state);
1641}
1642
1643syncable::AutofillMigrationDebugInfo
1644    SyncManager::GetAutofillMigrationDebugInfo() {
1645  return data_->GetAutofillMigrationDebugInfo();
1646}
1647
1648void SyncManager::SetAutofillMigrationDebugInfo(
1649    syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
1650    const syncable::AutofillMigrationDebugInfo& info) {
1651  return data_->SetAutofillMigrationDebugInfo(property_to_set, info);
1652}
1653
1654void SyncManager::SetPassphrase(const std::string& passphrase,
1655     bool is_explicit) {
1656  data_->SetPassphrase(passphrase, is_explicit);
1657}
1658
1659void SyncManager::EncryptDataTypes(
1660    const syncable::ModelTypeSet& encrypted_types) {
1661  data_->EncryptDataTypes(encrypted_types);
1662}
1663
1664bool SyncManager::IsUsingExplicitPassphrase() {
1665  return data_ && data_->IsUsingExplicitPassphrase();
1666}
1667
1668void SyncManager::RequestNudge(const tracked_objects::Location& location) {
1669  data_->RequestNudge(location);
1670}
1671
1672void SyncManager::RequestClearServerData() {
1673  if (data_->syncer_thread())
1674    data_->syncer_thread()->ScheduleClearUserData();
1675}
1676
1677void SyncManager::RequestConfig(const syncable::ModelTypeBitSet& types) {
1678  if (!data_->syncer_thread())
1679    return;
1680  StartConfigurationMode(NULL);
1681  data_->syncer_thread()->ScheduleConfig(types);
1682}
1683
1684void 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
1691const std::string& SyncManager::GetAuthenticatedUsername() {
1692  DCHECK(data_);
1693  return data_->username_for_share();
1694}
1695
1696bool 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
1763void 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
1807void 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
1816void 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
1834void 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
1844bool 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
1870bool 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
1900void 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
1914void 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
1926void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
1927  FOR_EACH_OBSERVER(
1928      SyncManager::Observer, observers_,
1929      OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
1930}
1931
1932void 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
1945void 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
2003bool 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
2015void 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
2051namespace {
2052
2053void 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.
2075ListValue* 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
2097void 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
2166SyncManager::~SyncManager() {
2167  delete data_;
2168}
2169
2170void SyncManager::AddObserver(Observer* observer) {
2171  data_->AddObserver(observer);
2172}
2173
2174void SyncManager::RemoveObserver(Observer* observer) {
2175  data_->RemoveObserver(observer);
2176}
2177
2178browser_sync::JsBackend* SyncManager::GetJsBackend() {
2179  return data_;
2180}
2181
2182void SyncManager::Shutdown() {
2183  data_->Shutdown();
2184}
2185
2186void 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
2231void 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
2245void 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
2252void 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
2261void 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
2279void 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
2296ModelTypeBitSet 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
2329void 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
2377void 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
2407void 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
2446SyncManager::Status SyncManager::SyncInternal::GetStatus() {
2447  return allstatus_.status();
2448}
2449
2450void 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
2458void 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
2466void 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
2569void SyncManager::SyncInternal::SetParentJsEventRouter(
2570    browser_sync::JsEventRouter* router) {
2571  DCHECK(router);
2572  parent_router_ = router;
2573}
2574
2575void SyncManager::SyncInternal::RemoveParentJsEventRouter() {
2576  parent_router_ = NULL;
2577}
2578
2579const browser_sync::JsEventRouter*
2580    SyncManager::SyncInternal::GetParentJsEventRouter() const {
2581  return parent_router_;
2582}
2583
2584namespace {
2585
2586void 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
2594void 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
2653browser_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
2679browser_sync::JsArgList SyncManager::SyncInternal::
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
2694void 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
2711void 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
2721void 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
2752void 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
2770void SyncManager::SyncInternal::AddObserver(
2771    SyncManager::Observer* observer) {
2772  observers_.AddObserver(observer);
2773}
2774
2775void SyncManager::SyncInternal::RemoveObserver(
2776    SyncManager::Observer* observer) {
2777  observers_.RemoveObserver(observer);
2778}
2779
2780SyncManager::Status::Summary SyncManager::GetStatusSummary() const {
2781  return data_->GetStatus().summary;
2782}
2783
2784SyncManager::Status SyncManager::GetDetailedStatus() const {
2785  return data_->GetStatus();
2786}
2787
2788SyncManager::SyncInternal* SyncManager::GetImpl() const { return data_; }
2789
2790void SyncManager::SaveChanges() {
2791  data_->SaveChanges();
2792}
2793
2794void 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
2805BaseTransaction::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}
2814BaseTransaction::~BaseTransaction() {
2815  delete lookup_;
2816}
2817
2818UserShare* SyncManager::GetUserShare() const {
2819  DCHECK(data_->initialized()) << "GetUserShare requires initialization!";
2820  return data_->GetUserShare();
2821}
2822
2823bool SyncManager::HasUnsyncedItems() const {
2824  sync_api::ReadTransaction trans(GetUserShare());
2825  return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
2826}
2827
2828void SyncManager::TriggerOnNotificationStateChangeForTest(
2829    bool notifications_enabled) {
2830  data_->OnNotificationStateChange(notifications_enabled);
2831}
2832
2833void 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