syncapi.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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 <bitset>
8#include <iomanip>
9#include <list>
10#include <string>
11#include <vector>
12
13#include "base/base64.h"
14#include "base/lock.h"
15#include "base/logging.h"
16#include "base/message_loop.h"
17#include "base/platform_thread.h"
18#include "base/scoped_ptr.h"
19#include "base/sha1.h"
20#include "base/string_util.h"
21#include "base/task.h"
22#include "base/utf_string_conversions.h"
23#include "chrome/browser/browser_thread.h"
24#include "chrome/browser/sync/sync_constants.h"
25#include "chrome/browser/sync/engine/all_status.h"
26#include "chrome/browser/sync/engine/change_reorder_buffer.h"
27#include "chrome/browser/sync/engine/model_safe_worker.h"
28#include "chrome/browser/sync/engine/net/server_connection_manager.h"
29#include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h"
30#include "chrome/browser/sync/engine/syncer.h"
31#include "chrome/browser/sync/engine/syncer_thread.h"
32#include "chrome/browser/sync/notifier/server_notifier_thread.h"
33#include "chrome/browser/sync/notifier/state_writer.h"
34#include "chrome/browser/sync/protocol/app_specifics.pb.h"
35#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
36#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
37#include "chrome/browser/sync/protocol/extension_specifics.pb.h"
38#include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
39#include "chrome/browser/sync/protocol/preference_specifics.pb.h"
40#include "chrome/browser/sync/protocol/session_specifics.pb.h"
41#include "chrome/browser/sync/protocol/service_constants.h"
42#include "chrome/browser/sync/protocol/sync.pb.h"
43#include "chrome/browser/sync/protocol/theme_specifics.pb.h"
44#include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
45#include "chrome/browser/sync/sessions/sync_session_context.h"
46#include "chrome/browser/sync/syncable/autofill_migration.h"
47#include "chrome/browser/sync/syncable/directory_manager.h"
48#include "chrome/browser/sync/syncable/syncable.h"
49#include "chrome/browser/sync/util/crypto_helpers.h"
50#include "chrome/common/chrome_switches.h"
51#include "chrome/common/deprecated/event_sys.h"
52#include "chrome/common/net/gaia/gaia_authenticator.h"
53#include "jingle/notifier/listener/mediator_thread_impl.h"
54#include "jingle/notifier/listener/notification_constants.h"
55#include "jingle/notifier/listener/talk_mediator.h"
56#include "jingle/notifier/listener/talk_mediator_impl.h"
57#include "net/base/network_change_notifier.h"
58
59using browser_sync::AllStatus;
60using browser_sync::Cryptographer;
61using browser_sync::KeyParams;
62using browser_sync::ModelSafeRoutingInfo;
63using browser_sync::ModelSafeWorker;
64using browser_sync::ModelSafeWorkerRegistrar;
65using browser_sync::ServerConnectionEvent;
66using browser_sync::SyncEngineEvent;
67using browser_sync::SyncEngineEventListener;
68using browser_sync::Syncer;
69using browser_sync::SyncerThread;
70using browser_sync::kNigoriTag;
71using browser_sync::sessions::SyncSessionContext;
72using notifier::TalkMediator;
73using notifier::TalkMediatorImpl;
74using std::list;
75using std::hex;
76using std::string;
77using std::vector;
78using syncable::Directory;
79using syncable::DirectoryManager;
80using syncable::Entry;
81using syncable::SPECIFICS;
82using sync_pb::AutofillProfileSpecifics;
83
84typedef GoogleServiceAuthError AuthError;
85
86static const int kThreadExitTimeoutMsec = 60000;
87static const int kSSLPort = 443;
88
89#if defined(OS_CHROMEOS)
90static const int kChromeOSNetworkChangeReactionDelayHackMsec = 5000;
91#endif  // OS_CHROMEOS
92
93// We manage the lifetime of sync_api::SyncManager::SyncInternal ourselves.
94DISABLE_RUNNABLE_METHOD_REFCOUNT(sync_api::SyncManager::SyncInternal);
95
96namespace sync_api {
97
98static const FilePath::CharType kBookmarkSyncUserSettingsDatabase[] =
99    FILE_PATH_LITERAL("BookmarkSyncSettings.sqlite3");
100static const char kDefaultNameForNewNodes[] = " ";
101
102// The list of names which are reserved for use by the server.
103static const char* kForbiddenServerNames[] = { "", ".", ".." };
104
105//////////////////////////////////////////////////////////////////////////
106// Static helper functions.
107
108// Helper function to look up the int64 metahandle of an object given the ID
109// string.
110static int64 IdToMetahandle(syncable::BaseTransaction* trans,
111                            const syncable::Id& id) {
112  syncable::Entry entry(trans, syncable::GET_BY_ID, id);
113  if (!entry.good())
114    return kInvalidId;
115  return entry.Get(syncable::META_HANDLE);
116}
117
118// Checks whether |name| is a server-illegal name followed by zero or more space
119// characters.  The three server-illegal names are the empty string, dot, and
120// dot-dot.  Very long names (>255 bytes in UTF-8 Normalization Form C) are
121// also illegal, but are not considered here.
122static bool IsNameServerIllegalAfterTrimming(const std::string& name) {
123  size_t untrimmed_count = name.find_last_not_of(' ') + 1;
124  for (size_t i = 0; i < arraysize(kForbiddenServerNames); ++i) {
125    if (name.compare(0, untrimmed_count, kForbiddenServerNames[i]) == 0)
126      return true;
127  }
128  return false;
129}
130
131static bool EndsWithSpace(const std::string& string) {
132  return !string.empty() && *string.rbegin() == ' ';
133}
134
135// When taking a name from the syncapi, append a space if it matches the
136// pattern of a server-illegal name followed by zero or more spaces.
137static void SyncAPINameToServerName(const std::wstring& sync_api_name,
138                                    std::string* out) {
139  *out = WideToUTF8(sync_api_name);
140  if (IsNameServerIllegalAfterTrimming(*out))
141    out->append(" ");
142}
143
144// In the reverse direction, if a server name matches the pattern of a
145// server-illegal name followed by one or more spaces, remove the trailing
146// space.
147static void ServerNameToSyncAPIName(const std::string& server_name,
148                                    std::wstring* out) {
149  int length_to_copy = server_name.length();
150  if (IsNameServerIllegalAfterTrimming(server_name) &&
151      EndsWithSpace(server_name))
152    --length_to_copy;
153  if (!UTF8ToWide(server_name.c_str(), length_to_copy, out)) {
154    NOTREACHED() << "Could not convert server name from UTF8 to wide";
155  }
156}
157
158UserShare::UserShare() {}
159
160UserShare::~UserShare() {}
161
162////////////////////////////////////
163// BaseNode member definitions.
164
165BaseNode::BaseNode() {}
166
167BaseNode::~BaseNode() {}
168
169std::string BaseNode::GenerateSyncableHash(
170    syncable::ModelType model_type, const std::string& client_tag) {
171  // blank PB with just the extension in it has termination symbol,
172  // handy for delimiter
173  sync_pb::EntitySpecifics serialized_type;
174  syncable::AddDefaultExtensionValue(model_type, &serialized_type);
175  std::string hash_input;
176  serialized_type.AppendToString(&hash_input);
177  hash_input.append(client_tag);
178
179  std::string encode_output;
180  CHECK(base::Base64Encode(base::SHA1HashString(hash_input), &encode_output));
181  return encode_output;
182}
183
184sync_pb::PasswordSpecificsData* DecryptPasswordSpecifics(
185    const sync_pb::EntitySpecifics& specifics, Cryptographer* crypto) {
186  if (!specifics.HasExtension(sync_pb::password))
187    return NULL;
188  const sync_pb::EncryptedData& encrypted =
189      specifics.GetExtension(sync_pb::password).encrypted();
190  scoped_ptr<sync_pb::PasswordSpecificsData> data(
191      new sync_pb::PasswordSpecificsData);
192  if (!crypto->Decrypt(encrypted, data.get()))
193    return NULL;
194  return data.release();
195}
196
197bool BaseNode::DecryptIfNecessary(Entry* entry) {
198  if (GetIsFolder()) return true;  // Ignore the top-level password folder.
199  const sync_pb::EntitySpecifics& specifics =
200      entry->Get(syncable::SPECIFICS);
201  if (specifics.HasExtension(sync_pb::password)) {
202    scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
203        specifics, GetTransaction()->GetCryptographer()));
204    if (!data.get())
205      return false;
206    password_data_.swap(data);
207  }
208  return true;
209}
210
211int64 BaseNode::GetParentId() const {
212  return IdToMetahandle(GetTransaction()->GetWrappedTrans(),
213                        GetEntry()->Get(syncable::PARENT_ID));
214}
215
216int64 BaseNode::GetId() const {
217  return GetEntry()->Get(syncable::META_HANDLE);
218}
219
220bool BaseNode::GetIsFolder() const {
221  return GetEntry()->Get(syncable::IS_DIR);
222}
223
224std::wstring BaseNode::GetTitle() const {
225  std::wstring result;
226  ServerNameToSyncAPIName(GetEntry()->Get(syncable::NON_UNIQUE_NAME), &result);
227  return result;
228}
229
230GURL BaseNode::GetURL() const {
231  return GURL(GetBookmarkSpecifics().url());
232}
233
234int64 BaseNode::GetPredecessorId() const {
235  syncable::Id id_string = GetEntry()->Get(syncable::PREV_ID);
236  if (id_string.IsRoot())
237    return kInvalidId;
238  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
239}
240
241int64 BaseNode::GetSuccessorId() const {
242  syncable::Id id_string = GetEntry()->Get(syncable::NEXT_ID);
243  if (id_string.IsRoot())
244    return kInvalidId;
245  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
246}
247
248int64 BaseNode::GetFirstChildId() const {
249  syncable::Directory* dir = GetTransaction()->GetLookup();
250  syncable::BaseTransaction* trans = GetTransaction()->GetWrappedTrans();
251  syncable::Id id_string =
252      dir->GetFirstChildId(trans, GetEntry()->Get(syncable::ID));
253  if (id_string.IsRoot())
254    return kInvalidId;
255  return IdToMetahandle(GetTransaction()->GetWrappedTrans(), id_string);
256}
257
258void BaseNode::GetFaviconBytes(std::vector<unsigned char>* output) const {
259  if (!output)
260    return;
261  const std::string& favicon = GetBookmarkSpecifics().favicon();
262  output->assign(reinterpret_cast<const unsigned char*>(favicon.data()),
263      reinterpret_cast<const unsigned char*>(favicon.data() +
264                                             favicon.length()));
265}
266
267int64 BaseNode::GetExternalId() const {
268  return GetEntry()->Get(syncable::LOCAL_EXTERNAL_ID);
269}
270
271const sync_pb::AppSpecifics& BaseNode::GetAppSpecifics() const {
272  DCHECK(GetModelType() == syncable::APPS);
273  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::app);
274}
275
276const sync_pb::AutofillSpecifics& BaseNode::GetAutofillSpecifics() const {
277  DCHECK(GetModelType() == syncable::AUTOFILL);
278  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::autofill);
279}
280
281const AutofillProfileSpecifics& BaseNode::GetAutofillProfileSpecifics() const {
282  DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
283  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::autofill_profile);
284}
285
286const sync_pb::BookmarkSpecifics& BaseNode::GetBookmarkSpecifics() const {
287  DCHECK(GetModelType() == syncable::BOOKMARKS);
288  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::bookmark);
289}
290
291const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
292  DCHECK(GetModelType() == syncable::NIGORI);
293  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::nigori);
294}
295
296const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
297  DCHECK(GetModelType() == syncable::PASSWORDS);
298  DCHECK(password_data_.get());
299  return *password_data_;
300}
301
302const sync_pb::PreferenceSpecifics& BaseNode::GetPreferenceSpecifics() const {
303  DCHECK(GetModelType() == syncable::PREFERENCES);
304  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::preference);
305}
306
307const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
308  DCHECK(GetModelType() == syncable::THEMES);
309  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::theme);
310}
311
312const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
313  DCHECK(GetModelType() == syncable::TYPED_URLS);
314  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::typed_url);
315}
316
317const sync_pb::ExtensionSpecifics& BaseNode::GetExtensionSpecifics() const {
318  DCHECK(GetModelType() == syncable::EXTENSIONS);
319  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::extension);
320}
321
322const sync_pb::SessionSpecifics& BaseNode::GetSessionSpecifics() const {
323  DCHECK(GetModelType() == syncable::SESSIONS);
324  return GetEntry()->Get(SPECIFICS).GetExtension(sync_pb::session);
325}
326
327syncable::ModelType BaseNode::GetModelType() const {
328  return GetEntry()->GetModelType();
329}
330
331////////////////////////////////////
332// WriteNode member definitions
333void WriteNode::SetIsFolder(bool folder) {
334  if (entry_->Get(syncable::IS_DIR) == folder)
335    return;  // Skip redundant changes.
336
337  entry_->Put(syncable::IS_DIR, folder);
338  MarkForSyncing();
339}
340
341void WriteNode::SetTitle(const std::wstring& title) {
342  std::string server_legal_name;
343  SyncAPINameToServerName(title, &server_legal_name);
344
345  string old_name = entry_->Get(syncable::NON_UNIQUE_NAME);
346
347  if (server_legal_name == old_name)
348    return;  // Skip redundant changes.
349
350  entry_->Put(syncable::NON_UNIQUE_NAME, server_legal_name);
351  MarkForSyncing();
352}
353
354void WriteNode::SetURL(const GURL& url) {
355  sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
356  new_value.set_url(url.spec());
357  SetBookmarkSpecifics(new_value);
358}
359
360void WriteNode::SetAppSpecifics(
361    const sync_pb::AppSpecifics& new_value) {
362  DCHECK(GetModelType() == syncable::APPS);
363  PutAppSpecificsAndMarkForSyncing(new_value);
364}
365
366void WriteNode::SetAutofillSpecifics(
367    const sync_pb::AutofillSpecifics& new_value) {
368  DCHECK(GetModelType() == syncable::AUTOFILL);
369  PutAutofillSpecificsAndMarkForSyncing(new_value);
370}
371
372void WriteNode::PutAutofillSpecificsAndMarkForSyncing(
373    const sync_pb::AutofillSpecifics& new_value) {
374  sync_pb::EntitySpecifics entity_specifics;
375  entity_specifics.MutableExtension(sync_pb::autofill)->CopyFrom(new_value);
376  PutSpecificsAndMarkForSyncing(entity_specifics);
377}
378
379void WriteNode::SetAutofillProfileSpecifics(
380    const sync_pb::AutofillProfileSpecifics& new_value) {
381  DCHECK_EQ(GetModelType(), syncable::AUTOFILL_PROFILE);
382  PutAutofillProfileSpecificsAndMarkForSyncing(new_value);
383}
384
385void WriteNode::PutAutofillProfileSpecificsAndMarkForSyncing(
386    const sync_pb::AutofillProfileSpecifics& new_value) {
387  sync_pb::EntitySpecifics entity_specifics;
388  entity_specifics.MutableExtension(sync_pb::autofill_profile)->CopyFrom(
389      new_value);
390  PutSpecificsAndMarkForSyncing(entity_specifics);
391}
392
393void WriteNode::SetBookmarkSpecifics(
394    const sync_pb::BookmarkSpecifics& new_value) {
395  DCHECK(GetModelType() == syncable::BOOKMARKS);
396  PutBookmarkSpecificsAndMarkForSyncing(new_value);
397}
398
399void WriteNode::PutBookmarkSpecificsAndMarkForSyncing(
400    const sync_pb::BookmarkSpecifics& new_value) {
401  sync_pb::EntitySpecifics entity_specifics;
402  entity_specifics.MutableExtension(sync_pb::bookmark)->CopyFrom(new_value);
403  PutSpecificsAndMarkForSyncing(entity_specifics);
404}
405
406void WriteNode::SetNigoriSpecifics(
407    const sync_pb::NigoriSpecifics& new_value) {
408  DCHECK(GetModelType() == syncable::NIGORI);
409  PutNigoriSpecificsAndMarkForSyncing(new_value);
410}
411
412void WriteNode::PutNigoriSpecificsAndMarkForSyncing(
413    const sync_pb::NigoriSpecifics& new_value) {
414  sync_pb::EntitySpecifics entity_specifics;
415  entity_specifics.MutableExtension(sync_pb::nigori)->CopyFrom(new_value);
416  PutSpecificsAndMarkForSyncing(entity_specifics);
417}
418
419void WriteNode::SetPasswordSpecifics(
420    const sync_pb::PasswordSpecificsData& data) {
421  DCHECK(GetModelType() == syncable::PASSWORDS);
422
423  sync_pb::PasswordSpecifics new_value;
424  if (!GetTransaction()->GetCryptographer()->Encrypt(
425      data,
426      new_value.mutable_encrypted())) {
427    NOTREACHED();
428  }
429
430  PutPasswordSpecificsAndMarkForSyncing(new_value);
431}
432
433void WriteNode::SetPreferenceSpecifics(
434    const sync_pb::PreferenceSpecifics& new_value) {
435  DCHECK(GetModelType() == syncable::PREFERENCES);
436  PutPreferenceSpecificsAndMarkForSyncing(new_value);
437}
438
439void WriteNode::SetThemeSpecifics(
440    const sync_pb::ThemeSpecifics& new_value) {
441  DCHECK(GetModelType() == syncable::THEMES);
442  PutThemeSpecificsAndMarkForSyncing(new_value);
443}
444
445void WriteNode::SetSessionSpecifics(
446    const sync_pb::SessionSpecifics& new_value) {
447  DCHECK(GetModelType() == syncable::SESSIONS);
448  PutSessionSpecificsAndMarkForSyncing(new_value);
449}
450
451
452void WriteNode::PutPasswordSpecificsAndMarkForSyncing(
453    const sync_pb::PasswordSpecifics& new_value) {
454  sync_pb::EntitySpecifics entity_specifics;
455  entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value);
456  PutSpecificsAndMarkForSyncing(entity_specifics);
457}
458
459void WriteNode::PutPreferenceSpecificsAndMarkForSyncing(
460    const sync_pb::PreferenceSpecifics& new_value) {
461  sync_pb::EntitySpecifics entity_specifics;
462  entity_specifics.MutableExtension(sync_pb::preference)->CopyFrom(new_value);
463  PutSpecificsAndMarkForSyncing(entity_specifics);
464}
465
466void WriteNode::SetTypedUrlSpecifics(
467    const sync_pb::TypedUrlSpecifics& new_value) {
468  DCHECK(GetModelType() == syncable::TYPED_URLS);
469  PutTypedUrlSpecificsAndMarkForSyncing(new_value);
470}
471
472void WriteNode::SetExtensionSpecifics(
473    const sync_pb::ExtensionSpecifics& new_value) {
474  DCHECK(GetModelType() == syncable::EXTENSIONS);
475  PutExtensionSpecificsAndMarkForSyncing(new_value);
476}
477
478void WriteNode::PutAppSpecificsAndMarkForSyncing(
479    const sync_pb::AppSpecifics& new_value) {
480  sync_pb::EntitySpecifics entity_specifics;
481  entity_specifics.MutableExtension(sync_pb::app)->CopyFrom(new_value);
482  PutSpecificsAndMarkForSyncing(entity_specifics);
483}
484
485void WriteNode::PutThemeSpecificsAndMarkForSyncing(
486    const sync_pb::ThemeSpecifics& new_value) {
487  sync_pb::EntitySpecifics entity_specifics;
488  entity_specifics.MutableExtension(sync_pb::theme)->CopyFrom(new_value);
489  PutSpecificsAndMarkForSyncing(entity_specifics);
490}
491
492void WriteNode::PutTypedUrlSpecificsAndMarkForSyncing(
493    const sync_pb::TypedUrlSpecifics& new_value) {
494  sync_pb::EntitySpecifics entity_specifics;
495  entity_specifics.MutableExtension(sync_pb::typed_url)->CopyFrom(new_value);
496  PutSpecificsAndMarkForSyncing(entity_specifics);
497}
498
499void WriteNode::PutExtensionSpecificsAndMarkForSyncing(
500    const sync_pb::ExtensionSpecifics& new_value) {
501  sync_pb::EntitySpecifics entity_specifics;
502  entity_specifics.MutableExtension(sync_pb::extension)->CopyFrom(new_value);
503  PutSpecificsAndMarkForSyncing(entity_specifics);
504}
505
506
507void WriteNode::PutSessionSpecificsAndMarkForSyncing(
508    const sync_pb::SessionSpecifics& new_value) {
509  sync_pb::EntitySpecifics entity_specifics;
510  entity_specifics.MutableExtension(sync_pb::session)->CopyFrom(new_value);
511  PutSpecificsAndMarkForSyncing(entity_specifics);
512}
513
514
515void WriteNode::PutSpecificsAndMarkForSyncing(
516    const sync_pb::EntitySpecifics& specifics) {
517  // Skip redundant changes.
518  if (specifics.SerializeAsString() ==
519      entry_->Get(SPECIFICS).SerializeAsString()) {
520    return;
521  }
522  entry_->Put(SPECIFICS, specifics);
523  MarkForSyncing();
524}
525
526void WriteNode::SetExternalId(int64 id) {
527  if (GetExternalId() != id)
528    entry_->Put(syncable::LOCAL_EXTERNAL_ID, id);
529}
530
531WriteNode::WriteNode(WriteTransaction* transaction)
532    : entry_(NULL), transaction_(transaction) {
533  DCHECK(transaction);
534}
535
536WriteNode::~WriteNode() {
537  delete entry_;
538}
539
540// Find an existing node matching the ID |id|, and bind this WriteNode to it.
541// Return true on success.
542bool WriteNode::InitByIdLookup(int64 id) {
543  DCHECK(!entry_) << "Init called twice";
544  DCHECK_NE(id, kInvalidId);
545  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
546                                      syncable::GET_BY_HANDLE, id);
547  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
548          DecryptIfNecessary(entry_));
549}
550
551// Find a node by client tag, and bind this WriteNode to it.
552// Return true if the write node was found, and was not deleted.
553// Undeleting a deleted node is possible by ClientTag.
554bool WriteNode::InitByClientTagLookup(syncable::ModelType model_type,
555                                      const std::string& tag) {
556  DCHECK(!entry_) << "Init called twice";
557  if (tag.empty())
558    return false;
559
560  const std::string hash = GenerateSyncableHash(model_type, tag);
561
562  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
563                                      syncable::GET_BY_CLIENT_TAG, hash);
564  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
565          DecryptIfNecessary(entry_));
566}
567
568bool WriteNode::InitByTagLookup(const std::string& tag) {
569  DCHECK(!entry_) << "Init called twice";
570  if (tag.empty())
571    return false;
572  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
573                                      syncable::GET_BY_SERVER_TAG, tag);
574  if (!entry_->good())
575    return false;
576  if (entry_->Get(syncable::IS_DEL))
577    return false;
578  syncable::ModelType model_type = GetModelType();
579  DCHECK(model_type == syncable::NIGORI);
580  return true;
581}
582
583void WriteNode::PutModelType(syncable::ModelType model_type) {
584  // Set an empty specifics of the appropriate datatype.  The presence
585  // of the specific extension will identify the model type.
586  DCHECK(GetModelType() == model_type ||
587         GetModelType() == syncable::UNSPECIFIED);  // Immutable once set.
588
589  sync_pb::EntitySpecifics specifics;
590  syncable::AddDefaultExtensionValue(model_type, &specifics);
591  PutSpecificsAndMarkForSyncing(specifics);
592  DCHECK(GetModelType() == model_type);
593}
594
595// Create a new node with default properties, and bind this WriteNode to it.
596// Return true on success.
597bool WriteNode::InitByCreation(syncable::ModelType model_type,
598                               const BaseNode& parent,
599                               const BaseNode* predecessor) {
600  DCHECK(!entry_) << "Init called twice";
601  // |predecessor| must be a child of |parent| or NULL.
602  if (predecessor && predecessor->GetParentId() != parent.GetId()) {
603    DCHECK(false);
604    return false;
605  }
606
607  syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
608
609  // Start out with a dummy name.  We expect
610  // the caller to set a meaningful name after creation.
611  string dummy(kDefaultNameForNewNodes);
612
613  entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
614                                      syncable::CREATE, parent_id, dummy);
615
616  if (!entry_->good())
617    return false;
618
619  // Entries are untitled folders by default.
620  entry_->Put(syncable::IS_DIR, true);
621
622  PutModelType(model_type);
623
624  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
625  PutPredecessor(predecessor);
626
627  return true;
628}
629
630// Create a new node with default properties and a client defined unique tag,
631// and bind this WriteNode to it.
632// Return true on success. If the tag exists in the database, then
633// we will attempt to undelete the node.
634// TODO(chron): Code datatype into hash tag.
635// TODO(chron): Is model type ever lost?
636bool WriteNode::InitUniqueByCreation(syncable::ModelType model_type,
637                                     const BaseNode& parent,
638                                     const std::string& tag) {
639  DCHECK(!entry_) << "Init called twice";
640
641  const std::string hash = GenerateSyncableHash(model_type, tag);
642
643  syncable::Id parent_id = parent.GetEntry()->Get(syncable::ID);
644
645  // Start out with a dummy name.  We expect
646  // the caller to set a meaningful name after creation.
647  string dummy(kDefaultNameForNewNodes);
648
649  // Check if we have this locally and need to undelete it.
650  scoped_ptr<syncable::MutableEntry> existing_entry(
651      new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
652                                 syncable::GET_BY_CLIENT_TAG, hash));
653
654  if (existing_entry->good()) {
655    if (existing_entry->Get(syncable::IS_DEL)) {
656      // Rules for undelete:
657      // BASE_VERSION: Must keep the same.
658      // ID: Essential to keep the same.
659      // META_HANDLE: Must be the same, so we can't "split" the entry.
660      // IS_DEL: Must be set to false, will cause reindexing.
661      //         This one is weird because IS_DEL is true for "update only"
662      //         items. It should be OK to undelete an update only.
663      // MTIME/CTIME: Seems reasonable to just leave them alone.
664      // IS_UNSYNCED: Must set this to true or face database insurrection.
665      //              We do this below this block.
666      // IS_UNAPPLIED_UPDATE: Either keep it the same or also set BASE_VERSION
667      //                      to SERVER_VERSION. We keep it the same here.
668      // IS_DIR: We'll leave it the same.
669      // SPECIFICS: Reset it.
670
671      existing_entry->Put(syncable::IS_DEL, false);
672
673      // Client tags are immutable and must be paired with the ID.
674      // If a server update comes down with an ID and client tag combo,
675      // and it already exists, always overwrite it and store only one copy.
676      // We have to undelete entries because we can't disassociate IDs from
677      // tags and updates.
678
679      existing_entry->Put(syncable::NON_UNIQUE_NAME, dummy);
680      existing_entry->Put(syncable::PARENT_ID, parent_id);
681      entry_ = existing_entry.release();
682    } else {
683      return false;
684    }
685  } else {
686    entry_ = new syncable::MutableEntry(transaction_->GetWrappedWriteTrans(),
687                                        syncable::CREATE, parent_id, dummy);
688    if (!entry_->good()) {
689      return false;
690    }
691
692    // Only set IS_DIR for new entries. Don't bitflip undeleted ones.
693    entry_->Put(syncable::UNIQUE_CLIENT_TAG, hash);
694  }
695
696  // We don't support directory and tag combinations.
697  entry_->Put(syncable::IS_DIR, false);
698
699  // Will clear specifics data.
700  PutModelType(model_type);
701
702  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
703  PutPredecessor(NULL);
704
705  return true;
706}
707
708bool WriteNode::SetPosition(const BaseNode& new_parent,
709                            const BaseNode* predecessor) {
710  // |predecessor| must be a child of |new_parent| or NULL.
711  if (predecessor && predecessor->GetParentId() != new_parent.GetId()) {
712    DCHECK(false);
713    return false;
714  }
715
716  syncable::Id new_parent_id = new_parent.GetEntry()->Get(syncable::ID);
717
718  // Filter out redundant changes if both the parent and the predecessor match.
719  if (new_parent_id == entry_->Get(syncable::PARENT_ID)) {
720    const syncable::Id& old = entry_->Get(syncable::PREV_ID);
721    if ((!predecessor && old.IsRoot()) ||
722        (predecessor && (old == predecessor->GetEntry()->Get(syncable::ID)))) {
723      return true;
724    }
725  }
726
727  // Atomically change the parent. This will fail if it would
728  // introduce a cycle in the hierarchy.
729  if (!entry_->Put(syncable::PARENT_ID, new_parent_id))
730    return false;
731
732  // Now set the predecessor, which sets IS_UNSYNCED as necessary.
733  PutPredecessor(predecessor);
734
735  return true;
736}
737
738const syncable::Entry* WriteNode::GetEntry() const {
739  return entry_;
740}
741
742const BaseTransaction* WriteNode::GetTransaction() const {
743  return transaction_;
744}
745
746void WriteNode::Remove() {
747  entry_->Put(syncable::IS_DEL, true);
748  MarkForSyncing();
749}
750
751void WriteNode::PutPredecessor(const BaseNode* predecessor) {
752  syncable::Id predecessor_id = predecessor ?
753      predecessor->GetEntry()->Get(syncable::ID) : syncable::Id();
754  entry_->PutPredecessor(predecessor_id);
755  // Mark this entry as unsynced, to wake up the syncer.
756  MarkForSyncing();
757}
758
759void WriteNode::SetFaviconBytes(const vector<unsigned char>& bytes) {
760  sync_pb::BookmarkSpecifics new_value = GetBookmarkSpecifics();
761  new_value.set_favicon(bytes.empty() ? NULL : &bytes[0], bytes.size());
762  SetBookmarkSpecifics(new_value);
763}
764
765void WriteNode::MarkForSyncing() {
766  syncable::MarkForSyncing(entry_);
767}
768
769//////////////////////////////////////////////////////////////////////////
770// ReadNode member definitions
771ReadNode::ReadNode(const BaseTransaction* transaction)
772    : entry_(NULL), transaction_(transaction) {
773  DCHECK(transaction);
774}
775
776ReadNode::ReadNode() {
777  entry_ = NULL;
778  transaction_ = NULL;
779}
780
781ReadNode::~ReadNode() {
782  delete entry_;
783}
784
785void ReadNode::InitByRootLookup() {
786  DCHECK(!entry_) << "Init called twice";
787  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
788  entry_ = new syncable::Entry(trans, syncable::GET_BY_ID, trans->root_id());
789  if (!entry_->good())
790    DCHECK(false) << "Could not lookup root node for reading.";
791}
792
793bool ReadNode::InitByIdLookup(int64 id) {
794  DCHECK(!entry_) << "Init called twice";
795  DCHECK_NE(id, kInvalidId);
796  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
797  entry_ = new syncable::Entry(trans, syncable::GET_BY_HANDLE, id);
798  if (!entry_->good())
799    return false;
800  if (entry_->Get(syncable::IS_DEL))
801    return false;
802  syncable::ModelType model_type = GetModelType();
803  LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
804                  model_type == syncable::TOP_LEVEL_FOLDER)
805      << "SyncAPI InitByIdLookup referencing unusual object.";
806  return DecryptIfNecessary(entry_);
807}
808
809bool ReadNode::InitByClientTagLookup(syncable::ModelType model_type,
810                                     const std::string& tag) {
811  DCHECK(!entry_) << "Init called twice";
812  if (tag.empty())
813    return false;
814
815  const std::string hash = GenerateSyncableHash(model_type, tag);
816
817  entry_ = new syncable::Entry(transaction_->GetWrappedTrans(),
818                               syncable::GET_BY_CLIENT_TAG, hash);
819  return (entry_->good() && !entry_->Get(syncable::IS_DEL) &&
820          DecryptIfNecessary(entry_));
821}
822
823const syncable::Entry* ReadNode::GetEntry() const {
824  return entry_;
825}
826
827const BaseTransaction* ReadNode::GetTransaction() const {
828  return transaction_;
829}
830
831bool ReadNode::InitByTagLookup(const std::string& tag) {
832  DCHECK(!entry_) << "Init called twice";
833  if (tag.empty())
834    return false;
835  syncable::BaseTransaction* trans = transaction_->GetWrappedTrans();
836  entry_ = new syncable::Entry(trans, syncable::GET_BY_SERVER_TAG, tag);
837  if (!entry_->good())
838    return false;
839  if (entry_->Get(syncable::IS_DEL))
840    return false;
841  syncable::ModelType model_type = GetModelType();
842  LOG_IF(WARNING, model_type == syncable::UNSPECIFIED ||
843                  model_type == syncable::TOP_LEVEL_FOLDER)
844      << "SyncAPI InitByTagLookup referencing unusually typed object.";
845  return DecryptIfNecessary(entry_);
846}
847
848//////////////////////////////////////////////////////////////////////////
849// ReadTransaction member definitions
850ReadTransaction::ReadTransaction(UserShare* share)
851    : BaseTransaction(share),
852      transaction_(NULL),
853      close_transaction_(true) {
854  transaction_ = new syncable::ReadTransaction(GetLookup(), __FILE__, __LINE__);
855}
856
857ReadTransaction::ReadTransaction(UserShare* share,
858                                 syncable::BaseTransaction* trans)
859    : BaseTransaction(share),
860      transaction_(trans),
861      close_transaction_(false) {}
862
863ReadTransaction::~ReadTransaction() {
864  if (close_transaction_) {
865    delete transaction_;
866  }
867}
868
869syncable::BaseTransaction* ReadTransaction::GetWrappedTrans() const {
870  return transaction_;
871}
872
873//////////////////////////////////////////////////////////////////////////
874// WriteTransaction member definitions
875WriteTransaction::WriteTransaction(UserShare* share)
876    : BaseTransaction(share),
877      transaction_(NULL) {
878  transaction_ = new syncable::WriteTransaction(GetLookup(), syncable::SYNCAPI,
879                                                __FILE__, __LINE__);
880}
881
882WriteTransaction::~WriteTransaction() {
883  delete transaction_;
884}
885
886syncable::BaseTransaction* WriteTransaction::GetWrappedTrans() const {
887  return transaction_;
888}
889
890// A GaiaAuthenticator that uses HttpPostProviders instead of CURL.
891class BridgedGaiaAuthenticator : public gaia::GaiaAuthenticator {
892 public:
893  BridgedGaiaAuthenticator(const string& user_agent, const string& service_id,
894                           const string& gaia_url,
895                           HttpPostProviderFactory* factory)
896      : GaiaAuthenticator(user_agent, service_id, gaia_url),
897        gaia_source_(user_agent), post_factory_(factory) {
898  }
899
900  virtual ~BridgedGaiaAuthenticator() {
901  }
902
903  virtual bool Post(const GURL& url, const string& post_body,
904                    unsigned long* response_code, string* response_body) {
905    string connection_url = "https://";
906    connection_url += url.host();
907    connection_url += url.path();
908    HttpPostProviderInterface* http = post_factory_->Create();
909    http->SetUserAgent(gaia_source_.c_str());
910    // SSL is on 443 for Gaia Posts always.
911    http->SetURL(connection_url.c_str(), kSSLPort);
912    http->SetPostPayload("application/x-www-form-urlencoded",
913                         post_body.length(), post_body.c_str());
914
915    int os_error_code = 0;
916    int int_response_code = 0;
917    if (!http->MakeSynchronousPost(&os_error_code, &int_response_code)) {
918      VLOG(1) << "Http POST failed, error returns: " << os_error_code;
919      return false;
920    }
921    *response_code = static_cast<int>(int_response_code);
922    response_body->assign(http->GetResponseContent(),
923                          http->GetResponseContentLength());
924    post_factory_->Destroy(http);
925    return true;
926  }
927
928  virtual int GetBackoffDelaySeconds(int current_backoff_delay) {
929    return SyncerThread::GetRecommendedDelaySeconds(current_backoff_delay);
930  }
931 private:
932  const std::string gaia_source_;
933  scoped_ptr<HttpPostProviderFactory> post_factory_;
934  DISALLOW_COPY_AND_ASSIGN(BridgedGaiaAuthenticator);
935};
936
937SyncManager::ChangeRecord::ChangeRecord()
938    : id(kInvalidId), action(ACTION_ADD) {}
939
940SyncManager::ChangeRecord::~ChangeRecord() {}
941
942SyncManager::ExtraPasswordChangeRecordData::ExtraPasswordChangeRecordData(
943    const sync_pb::PasswordSpecificsData& data)
944    : unencrypted_(data) {
945}
946
947SyncManager::ExtraPasswordChangeRecordData::~ExtraPasswordChangeRecordData() {}
948
949//////////////////////////////////////////////////////////////////////////
950// SyncManager's implementation: SyncManager::SyncInternal
951class SyncManager::SyncInternal
952    : public net::NetworkChangeNotifier::Observer,
953      public TalkMediator::Delegate,
954      public sync_notifier::StateWriter,
955      public browser_sync::ChannelEventHandler<syncable::DirectoryChangeEvent>,
956      public SyncEngineEventListener {
957  static const int kDefaultNudgeDelayMilliseconds;
958  static const int kPreferencesNudgeDelayMilliseconds;
959 public:
960  explicit SyncInternal(SyncManager* sync_manager)
961      : core_message_loop_(NULL),
962        observer_(NULL),
963        sync_manager_(sync_manager),
964        registrar_(NULL),
965        notification_pending_(false),
966        initialized_(false),
967        ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
968    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
969  }
970
971  virtual ~SyncInternal() {
972    DCHECK(!core_message_loop_);
973    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
974  }
975
976  bool Init(const FilePath& database_location,
977            const std::string& sync_server_and_path,
978            int port,
979            bool use_ssl,
980            HttpPostProviderFactory* post_factory,
981            ModelSafeWorkerRegistrar* model_safe_worker_registrar,
982            const char* user_agent,
983            const SyncCredentials& credentials,
984            const notifier::NotifierOptions& notifier_options,
985            const std::string& restored_key_for_bootstrapping,
986            bool setup_for_test_mode);
987
988  // Sign into sync with given credentials.
989  // We do not verify the tokens given. After this call, the tokens are set
990  // and the sync DB is open. True if successful, false if something
991  // went wrong.
992  bool SignIn(const SyncCredentials& credentials);
993
994  // Update tokens that we're using in Sync. Email must stay the same.
995  void UpdateCredentials(const SyncCredentials& credentials);
996
997  // Tell the sync engine to start the syncing process.
998  void StartSyncing();
999
1000  // Whether or not the Nigori node is encrypted using an explicit passphrase.
1001  bool IsUsingExplicitPassphrase();
1002
1003  // Try to set the current passphrase to |passphrase|, and record whether
1004  // it is an explicit passphrase or implicitly using gaia in the Nigori
1005  // node.
1006  void SetPassphrase(const std::string& passphrase, bool is_explicit);
1007
1008  // Call periodically from a database-safe thread to persist recent changes
1009  // to the syncapi model.
1010  void SaveChanges();
1011
1012  // This listener is called upon completion of a syncable transaction, and
1013  // builds the list of sync-engine initiated changes that will be forwarded to
1014  // the SyncManager's Observers.
1015  virtual void HandleChannelEvent(const syncable::DirectoryChangeEvent& event);
1016  void HandleTransactionCompleteChangeEvent(
1017      const syncable::DirectoryChangeEvent& event);
1018  void HandleTransactionEndingChangeEvent(
1019      const syncable::DirectoryChangeEvent& event);
1020  void HandleCalculateChangesChangeEventFromSyncApi(
1021      const syncable::DirectoryChangeEvent& event);
1022  void HandleCalculateChangesChangeEventFromSyncer(
1023      const syncable::DirectoryChangeEvent& event);
1024
1025  // Listens for notifications from the ServerConnectionManager
1026  void HandleServerConnectionEvent(const ServerConnectionEvent& event);
1027
1028  // Open the directory named with username_for_share
1029  bool OpenDirectory();
1030
1031  // Login to the talk mediator with the given credentials.
1032  void TalkMediatorLogin(
1033      const std::string& email, const std::string& token);
1034
1035  // TalkMediator::Delegate implementation.
1036  virtual void OnNotificationStateChange(
1037      bool notifications_enabled);
1038
1039  virtual void OnIncomingNotification(
1040      const IncomingNotificationData& notification_data);
1041
1042  virtual void OnOutgoingNotification();
1043
1044  // sync_notifier::StateWriter implementation.
1045  virtual void WriteState(const std::string& state);
1046
1047  // Accessors for the private members.
1048  DirectoryManager* dir_manager() { return share_.dir_manager.get(); }
1049  SyncAPIServerConnectionManager* connection_manager() {
1050    return connection_manager_.get();
1051  }
1052  SyncerThread* syncer_thread() { return syncer_thread_.get(); }
1053  TalkMediator* talk_mediator() { return talk_mediator_.get(); }
1054  void set_observer(SyncManager::Observer* observer) { observer_ = observer; }
1055  UserShare* GetUserShare() { return &share_; }
1056
1057  // Return the currently active (validated) username for use with syncable
1058  // types.
1059  const std::string& username_for_share() const {
1060    return share_.name;
1061  }
1062
1063  // Note about SyncManager::Status implementation: Status is a trimmed
1064  // down AllStatus::Status, augmented with authentication failure information
1065  // gathered from the internal AuthWatcher. The sync UI itself hooks up to
1066  // various sources like the AuthWatcher individually, but with syncapi we try
1067  // to keep everything status-related in one place. This means we have to
1068  // privately manage state about authentication failures, and whenever the
1069  // status or status summary is requested we aggregate this state with
1070  // AllStatus::Status information.
1071  Status ComputeAggregatedStatus();
1072  Status::Summary ComputeAggregatedStatusSummary();
1073
1074  // See SyncManager::Shutdown for information.
1075  void Shutdown();
1076
1077  // Whether we're initialized to the point of being able to accept changes
1078  // (and hence allow transaction creation). See initialized_ for details.
1079  bool initialized() const {
1080    AutoLock lock(initialized_mutex_);
1081    return initialized_;
1082  }
1083
1084  void SetExtraChangeRecordData(int64 id,
1085                                syncable::ModelType type,
1086                                ChangeReorderBuffer* buffer,
1087                                Cryptographer* cryptographer,
1088                                const syncable::EntryKernel& original,
1089                                bool existed_before,
1090                                bool exists_now);
1091
1092  // Called only by our NetworkChangeNotifier.
1093  virtual void OnIPAddressChanged();
1094
1095  bool InitialSyncEndedForAllEnabledTypes() {
1096    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1097    if (!lookup.good()) {
1098      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1099      return false;
1100    }
1101
1102    ModelSafeRoutingInfo enabled_types;
1103    registrar_->GetModelSafeRoutingInfo(&enabled_types);
1104    for (ModelSafeRoutingInfo::const_iterator i = enabled_types.begin();
1105        i != enabled_types.end(); ++i) {
1106      if (!lookup->initial_sync_ended_for_type(i->first))
1107        return false;
1108    }
1109    return true;
1110  }
1111
1112  syncable::AutofillMigrationState GetAutofillMigrationState() {
1113    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1114    if (!lookup.good()) {
1115      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1116      return syncable::NOT_MIGRATED;
1117    }
1118
1119    return lookup->get_autofill_migration_state();
1120  }
1121
1122  void SetAutofillMigrationState(syncable::AutofillMigrationState state) {
1123    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1124    if (!lookup.good()) {
1125      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1126      return;
1127    }
1128
1129    return lookup->set_autofill_migration_state(state);
1130  }
1131
1132  void SetAutofillMigrationDebugInfo(
1133      syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
1134      const syncable::AutofillMigrationDebugInfo& info) {
1135    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1136    if (!lookup.good()) {
1137      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1138      return;
1139    }
1140
1141    return lookup->set_autofill_migration_state_debug_info(
1142        property_to_set, info);
1143  }
1144
1145  syncable::AutofillMigrationDebugInfo
1146      GetAutofillMigrationDebugInfo() {
1147    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1148    if (!lookup.good()) {
1149      DCHECK(false) << "ScopedDirLookup failed when checking initial sync";
1150      syncable::AutofillMigrationDebugInfo null_value = {0};
1151      return null_value;
1152    }
1153    return lookup->get_autofill_migration_debug_info();
1154  }
1155
1156  // SyncEngineEventListener implementation.
1157  virtual void OnSyncEngineEvent(const SyncEngineEvent& event);
1158 private:
1159  // Helper to handle the details of initializing the TalkMediator.
1160  // Must be called only after OpenDirectory() is called.
1161  void InitializeTalkMediator();
1162
1163  // Helper to call OnAuthError when no authentication credentials are
1164  // available.
1165  void RaiseAuthNeededEvent();
1166
1167  // Helper to set initialized_ to true and raise an event to clients to notify
1168  // that initialization is complete and it is safe to send us changes. If
1169  // already initialized, this is a no-op.
1170  void MarkAndNotifyInitializationComplete();
1171
1172  // If there's a pending notification to be sent, either from the
1173  // new_pending_notification flag or a previous unsuccessfully sent
1174  // notification, tries to send a notification.
1175  void SendPendingXMPPNotification(bool new_pending_notification);
1176
1177  // Determine if the parents or predecessors differ between the old and new
1178  // versions of an entry stored in |a| and |b|.  Note that a node's index may
1179  // change without its NEXT_ID changing if the node at NEXT_ID also moved (but
1180  // the relative order is unchanged).  To handle such cases, we rely on the
1181  // caller to treat a position update on any sibling as updating the positions
1182  // of all siblings.
1183  static bool VisiblePositionsDiffer(const syncable::EntryKernel& a,
1184                                     const syncable::Entry& b) {
1185    // If the datatype isn't one where the browser model cares about position,
1186    // don't bother notifying that data model of position-only changes.
1187    if (!b.ShouldMaintainPosition())
1188      return false;
1189    if (a.ref(syncable::NEXT_ID) != b.Get(syncable::NEXT_ID))
1190      return true;
1191    if (a.ref(syncable::PARENT_ID) != b.Get(syncable::PARENT_ID))
1192      return true;
1193    return false;
1194  }
1195
1196  // Determine if any of the fields made visible to clients of the Sync API
1197  // differ between the versions of an entry stored in |a| and |b|. A return
1198  // value of false means that it should be OK to ignore this change.
1199  static bool VisiblePropertiesDiffer(const syncable::EntryKernel& a,
1200                                      const syncable::Entry& b) {
1201    syncable::ModelType model_type = b.GetModelType();
1202    // Suppress updates to items that aren't tracked by any browser model.
1203    if (model_type == syncable::UNSPECIFIED ||
1204        model_type == syncable::TOP_LEVEL_FOLDER) {
1205      return false;
1206    }
1207    if (a.ref(syncable::NON_UNIQUE_NAME) != b.Get(syncable::NON_UNIQUE_NAME))
1208      return true;
1209    if (a.ref(syncable::IS_DIR) != b.Get(syncable::IS_DIR))
1210      return true;
1211    if (a.ref(SPECIFICS).SerializeAsString() !=
1212        b.Get(SPECIFICS).SerializeAsString()) {
1213      return true;
1214    }
1215    if (VisiblePositionsDiffer(a, b))
1216      return true;
1217    return false;
1218  }
1219
1220  bool ChangeBuffersAreEmpty() {
1221    for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1222      if (!change_buffers_[i].IsEmpty())
1223        return false;
1224    }
1225    return true;
1226  }
1227
1228  void CheckServerReachable() {
1229    if (connection_manager()) {
1230      connection_manager()->CheckServerReachable();
1231    } else {
1232      NOTREACHED() << "Should be valid connection manager!";
1233    }
1234  }
1235
1236  void ReEncryptEverything(WriteTransaction* trans);
1237
1238  // Initializes (bootstraps) the Cryptographer if NIGORI has finished
1239  // initial sync so that it can immediately start encrypting / decrypting.
1240  // If the restored key is incompatible with the current version of the NIGORI
1241  // node (which could happen if a restart occurred just after an update to
1242  // NIGORI was downloaded and the user must enter a new passphrase to decrypt)
1243  // then we will raise OnPassphraseRequired and set pending keys for
1244  // decryption.  Otherwise, the cryptographer is made ready (is_ready()).
1245  void BootstrapEncryption(const std::string& restored_key_for_bootstrapping);
1246
1247  // Helper for migration to new nigori proto to set
1248  // 'using_explicit_passphrase' in the NigoriSpecifics.
1249  // TODO(tim): Bug 62103.  Remove this after it has been pushed out to dev
1250  // channel users.
1251  void SetUsingExplicitPassphrasePrefForMigration();
1252
1253  // Checks for server reachabilty and requests a nudge.
1254  void OnIPAddressChangedImpl();
1255
1256  // We couple the DirectoryManager and username together in a UserShare member
1257  // so we can return a handle to share_ to clients of the API for use when
1258  // constructing any transaction type.
1259  UserShare share_;
1260
1261  MessageLoop* core_message_loop_;
1262
1263  // Observer registered via SetObserver/RemoveObserver.
1264  // WARNING: This can be NULL!
1265  SyncManager::Observer* observer_;
1266
1267  // The ServerConnectionManager used to abstract communication between the
1268  // client (the Syncer) and the sync server.
1269  scoped_ptr<SyncAPIServerConnectionManager> connection_manager_;
1270
1271  // The thread that runs the Syncer. Needs to be explicitly Start()ed.
1272  scoped_refptr<SyncerThread> syncer_thread_;
1273
1274  // Notification (xmpp) handler.
1275  scoped_ptr<TalkMediator> talk_mediator_;
1276
1277  // A multi-purpose status watch object that aggregates stats from various
1278  // sync components.
1279  AllStatus allstatus_;
1280
1281  // Each element of this array is a store of change records produced by
1282  // HandleChangeEvent during the CALCULATE_CHANGES step.  The changes are
1283  // segregated by model type, and are stored here to be processed and
1284  // forwarded to the observer slightly later, at the TRANSACTION_ENDING
1285  // step by HandleTransactionEndingChangeEvent. The list is cleared in the
1286  // TRANSACTION_COMPLETE step by HandleTransactionCompleteChangeEvent.
1287  ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
1288
1289  // Bit vector keeping track of which models need to have their
1290  // OnChangesComplete observer set.
1291  //
1292  // Set by HandleTransactionEndingChangeEvent, cleared in
1293  // HandleTransactionCompleteChangeEvent.
1294  std::bitset<syncable::MODEL_TYPE_COUNT> model_has_change_;
1295
1296  // The event listener hookup that is registered for HandleChangeEvent.
1297  scoped_ptr<browser_sync::ChannelHookup<syncable::DirectoryChangeEvent> >
1298      dir_change_hookup_;
1299
1300  // Event listener hookup for the ServerConnectionManager.
1301  scoped_ptr<EventListenerHookup> connection_manager_hookup_;
1302
1303  // The sync dir_manager to which we belong.
1304  SyncManager* const sync_manager_;
1305
1306  // The entity that provides us with information about which types to sync.
1307  // The instance is shared between the SyncManager and the Syncer.
1308  ModelSafeWorkerRegistrar* registrar_;
1309
1310  // True if the next SyncCycle should notify peers of an update.
1311  bool notification_pending_;
1312
1313  // Set to true once Init has been called, and we know of an authenticated
1314  // valid) username either from a fresh authentication attempt (as in
1315  // first-use case) or from a previous attempt stored in our UserSettings
1316  // (as in the steady-state), and the syncable::Directory has been opened,
1317  // meaning we are ready to accept changes.  Protected by initialized_mutex_
1318  // as it can get read/set by both the SyncerThread and the AuthWatcherThread.
1319  bool initialized_;
1320  mutable Lock initialized_mutex_;
1321
1322  notifier::NotifierOptions notifier_options_;
1323
1324  // True if the SyncManager should be running in test mode (no syncer thread
1325  // actually communicating with the server).
1326  bool setup_for_test_mode_;
1327
1328  ScopedRunnableMethodFactory<SyncManager::SyncInternal> method_factory_;
1329};
1330const int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
1331const int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
1332
1333SyncManager::SyncManager() {
1334  data_ = new SyncInternal(this);
1335}
1336
1337bool SyncManager::Init(const FilePath& database_location,
1338                       const char* sync_server_and_path,
1339                       int sync_server_port,
1340                       bool use_ssl,
1341                       HttpPostProviderFactory* post_factory,
1342                       ModelSafeWorkerRegistrar* registrar,
1343                       const char* user_agent,
1344                       const SyncCredentials& credentials,
1345                       const notifier::NotifierOptions& notifier_options,
1346                       const std::string& restored_key_for_bootstrapping,
1347                       bool setup_for_test_mode) {
1348  DCHECK(post_factory);
1349  VLOG(1) << "SyncManager starting Init...";
1350  string server_string(sync_server_and_path);
1351  return data_->Init(database_location,
1352                     server_string,
1353                     sync_server_port,
1354                     use_ssl,
1355                     post_factory,
1356                     registrar,
1357                     user_agent,
1358                     credentials,
1359                     notifier_options,
1360                     restored_key_for_bootstrapping,
1361                     setup_for_test_mode);
1362}
1363
1364void SyncManager::UpdateCredentials(const SyncCredentials& credentials) {
1365  data_->UpdateCredentials(credentials);
1366}
1367
1368
1369bool SyncManager::InitialSyncEndedForAllEnabledTypes() {
1370  return data_->InitialSyncEndedForAllEnabledTypes();
1371}
1372
1373void SyncManager::StartSyncing() {
1374  data_->StartSyncing();
1375}
1376
1377syncable::AutofillMigrationState
1378    SyncManager::GetAutofillMigrationState() {
1379  return data_->GetAutofillMigrationState();
1380}
1381
1382void SyncManager::SetAutofillMigrationState(
1383    syncable::AutofillMigrationState state) {
1384  return data_->SetAutofillMigrationState(state);
1385}
1386
1387syncable::AutofillMigrationDebugInfo
1388    SyncManager::GetAutofillMigrationDebugInfo() {
1389  return data_->GetAutofillMigrationDebugInfo();
1390}
1391
1392void SyncManager::SetAutofillMigrationDebugInfo(
1393    syncable::AutofillMigrationDebugInfo::PropertyToSet property_to_set,
1394    const syncable::AutofillMigrationDebugInfo& info) {
1395  return data_->SetAutofillMigrationDebugInfo(property_to_set, info);
1396}
1397
1398void SyncManager::SetPassphrase(const std::string& passphrase,
1399     bool is_explicit) {
1400  data_->SetPassphrase(passphrase, is_explicit);
1401}
1402
1403bool SyncManager::IsUsingExplicitPassphrase() {
1404  return data_ && data_->IsUsingExplicitPassphrase();
1405}
1406
1407bool SyncManager::RequestPause() {
1408  if (data_->syncer_thread())
1409    return data_->syncer_thread()->RequestPause();
1410  return false;
1411}
1412
1413bool SyncManager::RequestResume() {
1414  if (data_->syncer_thread())
1415    return data_->syncer_thread()->RequestResume();
1416  return false;
1417}
1418
1419void SyncManager::RequestNudge() {
1420  if (data_->syncer_thread())
1421    data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kLocal);
1422}
1423
1424void SyncManager::RequestClearServerData() {
1425  if (data_->syncer_thread())
1426    data_->syncer_thread()->NudgeSyncer(0, SyncerThread::kClearPrivateData);
1427}
1428
1429const std::string& SyncManager::GetAuthenticatedUsername() {
1430  DCHECK(data_);
1431  return data_->username_for_share();
1432}
1433
1434bool SyncManager::SyncInternal::Init(
1435    const FilePath& database_location,
1436    const std::string& sync_server_and_path,
1437    int port,
1438    bool use_ssl,
1439    HttpPostProviderFactory* post_factory,
1440    ModelSafeWorkerRegistrar* model_safe_worker_registrar,
1441    const char* user_agent,
1442    const SyncCredentials& credentials,
1443    const notifier::NotifierOptions& notifier_options,
1444    const std::string& restored_key_for_bootstrapping,
1445    bool setup_for_test_mode) {
1446
1447  VLOG(1) << "Starting SyncInternal initialization.";
1448
1449  core_message_loop_ = MessageLoop::current();
1450  DCHECK(core_message_loop_);
1451  notifier_options_ = notifier_options;
1452  registrar_ = model_safe_worker_registrar;
1453  setup_for_test_mode_ = setup_for_test_mode;
1454
1455  share_.dir_manager.reset(new DirectoryManager(database_location));
1456
1457  connection_manager_.reset(new SyncAPIServerConnectionManager(
1458      sync_server_and_path, port, use_ssl, user_agent, post_factory));
1459
1460  connection_manager_hookup_.reset(
1461      NewEventListenerHookup(connection_manager()->channel(), this,
1462          &SyncManager::SyncInternal::HandleServerConnectionEvent));
1463
1464  net::NetworkChangeNotifier::AddObserver(this);
1465  // TODO(akalin): CheckServerReachable() can block, which may cause jank if we
1466  // try to shut down sync.  Fix this.
1467  core_message_loop_->PostTask(FROM_HERE,
1468      method_factory_.NewRunnableMethod(&SyncInternal::CheckServerReachable));
1469
1470  // Test mode does not use a syncer context or syncer thread.
1471  if (!setup_for_test_mode) {
1472    // Build a SyncSessionContext and store the worker in it.
1473    VLOG(1) << "Sync is bringing up SyncSessionContext.";
1474    std::vector<SyncEngineEventListener*> listeners;
1475    listeners.push_back(&allstatus_);
1476    listeners.push_back(this);
1477    SyncSessionContext* context = new SyncSessionContext(
1478        connection_manager_.get(),
1479        dir_manager(),
1480        model_safe_worker_registrar,
1481        listeners);
1482
1483    // The SyncerThread takes ownership of |context|.
1484    syncer_thread_ = new SyncerThread(context);
1485  }
1486
1487  bool signed_in = SignIn(credentials);
1488
1489  // Do this once the directory is opened.
1490  BootstrapEncryption(restored_key_for_bootstrapping);
1491  return signed_in;
1492}
1493
1494void SyncManager::SyncInternal::BootstrapEncryption(
1495    const std::string& restored_key_for_bootstrapping) {
1496  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1497  if (!lookup.good()) {
1498    NOTREACHED();
1499    return;
1500  }
1501
1502  if (!lookup->initial_sync_ended_for_type(syncable::NIGORI))
1503    return;
1504
1505  Cryptographer* cryptographer = share_.dir_manager->cryptographer();
1506  cryptographer->Bootstrap(restored_key_for_bootstrapping);
1507
1508  ReadTransaction trans(GetUserShare());
1509  ReadNode node(&trans);
1510  if (!node.InitByTagLookup(kNigoriTag)) {
1511    NOTREACHED();
1512    return;
1513  }
1514
1515  const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics();
1516  if (!nigori.encrypted().blob().empty()) {
1517    if (cryptographer->CanDecrypt(nigori.encrypted())) {
1518      cryptographer->SetKeys(nigori.encrypted());
1519    } else {
1520      cryptographer->SetPendingKeys(nigori.encrypted());
1521      observer_->OnPassphraseRequired(true);
1522    }
1523  }
1524}
1525
1526void SyncManager::SyncInternal::StartSyncing() {
1527  if (syncer_thread())  // NULL during certain unittests.
1528    syncer_thread()->Start();  // Start the syncer thread. This won't actually
1529                               // result in any syncing until at least the
1530                               // DirectoryManager broadcasts the OPENED event,
1531                               // and a valid server connection is detected.
1532}
1533
1534void SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
1535  // There is only one real time we need this mutex.  If we get an auth
1536  // success, and before the initial sync ends we get an auth failure.  In this
1537  // case we'll be listening to both the AuthWatcher and Syncer, and it's a race
1538  // between their respective threads to call MarkAndNotify.  We need to make
1539  // sure the observer is notified once and only once.
1540  {
1541    AutoLock lock(initialized_mutex_);
1542    if (initialized_)
1543      return;
1544    initialized_ = true;
1545  }
1546
1547  // Notify that initialization is complete.
1548  if (observer_)
1549    observer_->OnInitializationComplete();
1550}
1551
1552void SyncManager::SyncInternal::SendPendingXMPPNotification(
1553    bool new_pending_notification) {
1554  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1555  DCHECK_NE(notifier_options_.notification_method,
1556            notifier::NOTIFICATION_SERVER);
1557  notification_pending_ = notification_pending_ || new_pending_notification;
1558  if (!notification_pending_) {
1559    VLOG(1) << "Not sending notification: no pending notification";
1560    return;
1561  }
1562  if (!talk_mediator_.get()) {
1563    VLOG(1) << "Not sending notification: shutting down (talk_mediator_ is "
1564               "NULL)";
1565    return;
1566  }
1567  VLOG(1) << "Sending XMPP notification...";
1568  OutgoingNotificationData notification_data;
1569  notification_data.service_id = browser_sync::kSyncServiceId;
1570  notification_data.service_url = browser_sync::kSyncServiceUrl;
1571  notification_data.send_content = true;
1572  notification_data.priority = browser_sync::kSyncPriority;
1573  notification_data.write_to_cache_only = true;
1574  notification_data.service_specific_data =
1575      browser_sync::kSyncServiceSpecificData;
1576  notification_data.require_subscription = true;
1577  bool success = talk_mediator_->SendNotification(notification_data);
1578  if (success) {
1579    notification_pending_ = false;
1580    VLOG(1) << "Sent XMPP notification";
1581  } else {
1582    VLOG(1) << "Could not send XMPP notification";
1583  }
1584}
1585
1586bool SyncManager::SyncInternal::OpenDirectory() {
1587  DCHECK(!initialized()) << "Should only happen once";
1588
1589  bool share_opened = dir_manager()->Open(username_for_share());
1590  DCHECK(share_opened);
1591  if (!share_opened) {
1592    if (observer_)
1593      observer_->OnStopSyncingPermanently();
1594
1595    LOG(ERROR) << "Could not open share for:" << username_for_share();
1596    return false;
1597  }
1598
1599  // Database has to be initialized for the guid to be available.
1600  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1601  if (!lookup.good()) {
1602    NOTREACHED();
1603    return false;
1604  }
1605
1606  connection_manager()->set_client_id(lookup->cache_guid());
1607
1608  if (syncer_thread())
1609    syncer_thread()->CreateSyncer(username_for_share());
1610
1611  MarkAndNotifyInitializationComplete();
1612  dir_change_hookup_.reset(lookup->AddChangeObserver(this));
1613  return true;
1614}
1615
1616bool SyncManager::SyncInternal::SignIn(const SyncCredentials& credentials) {
1617  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1618  DCHECK(share_.name.empty());
1619  share_.name = credentials.email;
1620
1621  VLOG(1) << "Signing in user: " << username_for_share();
1622  if (!OpenDirectory())
1623    return false;
1624
1625  UpdateCredentials(credentials);
1626  return true;
1627}
1628
1629void SyncManager::SyncInternal::UpdateCredentials(
1630    const SyncCredentials& credentials) {
1631  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
1632  DCHECK(share_.name == credentials.email);
1633  connection_manager()->set_auth_token(credentials.sync_token);
1634  TalkMediatorLogin(credentials.email, credentials.sync_token);
1635  CheckServerReachable();
1636  sync_manager_->RequestNudge();
1637}
1638
1639void SyncManager::SyncInternal::InitializeTalkMediator() {
1640  if (notifier_options_.notification_method ==
1641      notifier::NOTIFICATION_SERVER) {
1642    syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1643    std::string state;
1644    if (lookup.good())
1645      state = lookup->GetAndClearNotificationState();
1646    else
1647      LOG(ERROR) << "Could not read notification state";
1648    if (VLOG_IS_ON(1)) {
1649      std::string encoded_state;
1650      base::Base64Encode(state, &encoded_state);
1651      VLOG(1) << "Read notification state: " << encoded_state;
1652    }
1653    sync_notifier::ServerNotifierThread* server_notifier_thread =
1654        new sync_notifier::ServerNotifierThread(
1655            notifier_options_, state, this);
1656    talk_mediator_.reset(
1657        new TalkMediatorImpl(server_notifier_thread,
1658                             notifier_options_.invalidate_xmpp_login,
1659                             notifier_options_.allow_insecure_connection));
1660  } else {
1661    notifier::MediatorThread* mediator_thread =
1662        new notifier::MediatorThreadImpl(notifier_options_);
1663    talk_mediator_.reset(
1664        new TalkMediatorImpl(mediator_thread,
1665                             notifier_options_.invalidate_xmpp_login,
1666                             notifier_options_.allow_insecure_connection));
1667    talk_mediator_->AddSubscribedServiceUrl(browser_sync::kSyncServiceUrl);
1668  }
1669  talk_mediator_->SetDelegate(this);
1670}
1671
1672void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
1673  if (observer_) {
1674    observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS));
1675  }
1676}
1677
1678void SyncManager::SyncInternal::SetUsingExplicitPassphrasePrefForMigration() {
1679  WriteTransaction trans(&share_);
1680  WriteNode node(&trans);
1681  if (!node.InitByTagLookup(kNigoriTag)) {
1682    // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1683    NOTREACHED();
1684    return;
1685  }
1686  sync_pb::NigoriSpecifics specifics(node.GetNigoriSpecifics());
1687  specifics.set_using_explicit_passphrase(true);
1688  node.SetNigoriSpecifics(specifics);
1689}
1690
1691void SyncManager::SyncInternal::SetPassphrase(
1692    const std::string& passphrase, bool is_explicit) {
1693  Cryptographer* cryptographer = dir_manager()->cryptographer();
1694  KeyParams params = {"localhost", "dummy", passphrase};
1695  if (cryptographer->has_pending_keys()) {
1696    if (!cryptographer->DecryptPendingKeys(params)) {
1697      observer_->OnPassphraseRequired(true);
1698      return;
1699    }
1700
1701    // TODO(tim): If this is the first time the user has entered a passphrase
1702    // since the protocol changed to store passphrase preferences in the cloud,
1703    // make sure we update this preference. See bug 62103.
1704    if (is_explicit)
1705      SetUsingExplicitPassphrasePrefForMigration();
1706
1707    // Nudge the syncer so that passwords updates that were waiting for this
1708    // passphrase get applied as soon as possible.
1709    sync_manager_->RequestNudge();
1710  } else {
1711    WriteTransaction trans(GetUserShare());
1712    WriteNode node(&trans);
1713    if (!node.InitByTagLookup(kNigoriTag)) {
1714      // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1715      NOTREACHED();
1716      return;
1717    }
1718
1719    // Prevent an implicit SetPassphrase request from changing an explicitly
1720    // set passphrase.
1721    if (!is_explicit && node.GetNigoriSpecifics().using_explicit_passphrase())
1722      return;
1723
1724    cryptographer->AddKey(params);
1725
1726    // TODO(tim): Bug 58231. It would be nice if SetPassphrase didn't require
1727    // messing with the Nigori node, because we can't call SetPassphrase until
1728    // download conditions are met vs Cryptographer init.  It seems like it's
1729    // safe to defer this work.
1730    sync_pb::NigoriSpecifics specifics;
1731    cryptographer->GetKeys(specifics.mutable_encrypted());
1732    specifics.set_using_explicit_passphrase(is_explicit);
1733    node.SetNigoriSpecifics(specifics);
1734    ReEncryptEverything(&trans);
1735  }
1736
1737  std::string bootstrap_token;
1738  cryptographer->GetBootstrapToken(&bootstrap_token);
1739  observer_->OnPassphraseAccepted(bootstrap_token);
1740}
1741
1742bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
1743  ReadTransaction trans(&share_);
1744  ReadNode node(&trans);
1745  if (!node.InitByTagLookup(kNigoriTag)) {
1746    // TODO(albertb): Plumb an UnrecoverableError all the way back to the PSS.
1747    NOTREACHED();
1748    return false;
1749  }
1750
1751  return node.GetNigoriSpecifics().using_explicit_passphrase();
1752}
1753
1754void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
1755  // TODO(tim): bug 59242.  We shouldn't lookup by data type and instead use
1756  // a protocol flag or existence of an EncryptedData message, but for now,
1757  // encryption is on if-and-only-if the type is passwords, and we haven't
1758  // ironed out the protocol for generic encryption.
1759  static const char* passwords_tag = "google_chrome_passwords";
1760  ReadNode passwords_root(trans);
1761  if (!passwords_root.InitByTagLookup(passwords_tag)) {
1762    LOG(WARNING) << "No passwords to reencrypt.";
1763    return;
1764  }
1765
1766  int64 child_id = passwords_root.GetFirstChildId();
1767  while (child_id != kInvalidId) {
1768    WriteNode child(trans);
1769    if (!child.InitByIdLookup(child_id)) {
1770      NOTREACHED();
1771      return;
1772    }
1773    child.SetPasswordSpecifics(child.GetPasswordSpecifics());
1774    child_id = child.GetSuccessorId();
1775  }
1776}
1777
1778SyncManager::~SyncManager() {
1779  delete data_;
1780}
1781
1782void SyncManager::SetObserver(Observer* observer) {
1783  data_->set_observer(observer);
1784}
1785
1786void SyncManager::RemoveObserver() {
1787  data_->set_observer(NULL);
1788}
1789
1790void SyncManager::Shutdown() {
1791  data_->Shutdown();
1792}
1793
1794void SyncManager::SyncInternal::Shutdown() {
1795  method_factory_.RevokeAll();
1796
1797  // We NULL out talk_mediator_ so that any tasks pumped below do not
1798  // trigger further XMPP actions.
1799  //
1800  // TODO(akalin): NULL the other member variables defensively, too.
1801  scoped_ptr<TalkMediator> talk_mediator(talk_mediator_.release());
1802
1803  if (syncer_thread()) {
1804    if (!syncer_thread()->Stop(kThreadExitTimeoutMsec)) {
1805      LOG(FATAL) << "Unable to stop the syncer, it won't be happy...";
1806    }
1807    syncer_thread_ = NULL;
1808  }
1809
1810  // Shutdown the xmpp buzz connection.
1811  if (talk_mediator.get()) {
1812    VLOG(1) << "P2P: Mediator logout started.";
1813    talk_mediator->Logout();
1814    VLOG(1) << "P2P: Mediator logout completed.";
1815    talk_mediator.reset();
1816    VLOG(1) << "P2P: Mediator destroyed.";
1817  }
1818
1819  // Pump any messages the auth watcher, syncer thread, or talk
1820  // mediator posted before they shut down. (See OnSyncEngineEvent(),
1821  // and HandleTalkMediatorEvent() for the
1822  // events that may be posted.)
1823  {
1824    CHECK(core_message_loop_);
1825    bool old_state = core_message_loop_->NestableTasksAllowed();
1826    core_message_loop_->SetNestableTasksAllowed(true);
1827    core_message_loop_->RunAllPending();
1828    core_message_loop_->SetNestableTasksAllowed(old_state);
1829  }
1830
1831  net::NetworkChangeNotifier::RemoveObserver(this);
1832
1833  connection_manager_hookup_.reset();
1834
1835  if (dir_manager()) {
1836    dir_manager()->FinalSaveChangesForAll();
1837    dir_manager()->Close(username_for_share());
1838  }
1839
1840  // Reset the DirectoryManager and UserSettings so they relinquish sqlite
1841  // handles to backing files.
1842  share_.dir_manager.reset();
1843
1844  // We don't want to process any more events.
1845  dir_change_hookup_.reset();
1846
1847  core_message_loop_ = NULL;
1848}
1849
1850void SyncManager::SyncInternal::OnIPAddressChanged() {
1851  VLOG(1) << "IP address change detected";
1852#if defined (OS_CHROMEOS)
1853  // TODO(tim): This is a hack to intentionally lose a race with flimflam at
1854  // shutdown, so we don't cause shutdown to wait for our http request.
1855  // http://crosbug.com/8429
1856  MessageLoop::current()->PostDelayedTask(FROM_HERE,
1857      method_factory_.NewRunnableMethod(&SyncInternal::OnIPAddressChangedImpl),
1858      kChromeOSNetworkChangeReactionDelayHackMsec);
1859#else
1860  OnIPAddressChangedImpl();
1861#endif  // defined(OS_CHROMEOS)
1862}
1863
1864void SyncManager::SyncInternal::OnIPAddressChangedImpl() {
1865  // TODO(akalin): CheckServerReachable() can block, which may cause
1866  // jank if we try to shut down sync.  Fix this.
1867  connection_manager()->CheckServerReachable();
1868  sync_manager_->RequestNudge();
1869}
1870
1871// Listen to model changes, filter out ones initiated by the sync API, and
1872// saves the rest (hopefully just backend Syncer changes resulting from
1873// ApplyUpdates) to data_->changelist.
1874void SyncManager::SyncInternal::HandleChannelEvent(
1875    const syncable::DirectoryChangeEvent& event) {
1876  if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_COMPLETE) {
1877    // Safe to perform slow I/O operations now, go ahead and commit.
1878    HandleTransactionCompleteChangeEvent(event);
1879    return;
1880  } else if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_ENDING) {
1881    HandleTransactionEndingChangeEvent(event);
1882    return;
1883  } else if (event.todo == syncable::DirectoryChangeEvent::CALCULATE_CHANGES) {
1884    if (event.writer == syncable::SYNCAPI) {
1885      HandleCalculateChangesChangeEventFromSyncApi(event);
1886      return;
1887    }
1888    HandleCalculateChangesChangeEventFromSyncer(event);
1889    return;
1890  } else if (event.todo == syncable::DirectoryChangeEvent::SHUTDOWN) {
1891    dir_change_hookup_.reset();
1892  }
1893}
1894
1895void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
1896    const syncable::DirectoryChangeEvent& event) {
1897  // This notification happens immediately after the channel mutex is released
1898  // This allows work to be performed without holding the WriteTransaction lock
1899  // but before the transaction is finished.
1900  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::TRANSACTION_COMPLETE);
1901  if (!observer_)
1902    return;
1903
1904  // Call commit
1905  for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1906    if (model_has_change_.test(i)) {
1907      observer_->OnChangesComplete(syncable::ModelTypeFromInt(i));
1908      model_has_change_.reset(i);
1909    }
1910  }
1911}
1912
1913void SyncManager::SyncInternal::HandleServerConnectionEvent(
1914    const ServerConnectionEvent& event) {
1915  allstatus_.HandleServerConnectionEvent(event);
1916  if (event.what_happened == ServerConnectionEvent::STATUS_CHANGED) {
1917    if (event.connection_code ==
1918        browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
1919      if (observer_) {
1920        observer_->OnAuthError(AuthError::None());
1921      }
1922    }
1923
1924    if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
1925      if (observer_) {
1926        observer_->OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS));
1927      }
1928    }
1929  }
1930}
1931
1932void SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
1933    const syncable::DirectoryChangeEvent& event) {
1934  // This notification happens immediately before a syncable WriteTransaction
1935  // falls out of scope. It happens while the channel mutex is still held,
1936  // and while the transaction mutex is held, so it cannot be re-entrant.
1937  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::TRANSACTION_ENDING);
1938  if (!observer_ || ChangeBuffersAreEmpty())
1939    return;
1940
1941  // This will continue the WriteTransaction using a read only wrapper.
1942  // This is the last chance for read to occur in the WriteTransaction
1943  // that's closing. This special ReadTransaction will not close the
1944  // underlying transaction.
1945  ReadTransaction trans(GetUserShare(), event.trans);
1946
1947  for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
1948    if (change_buffers_[i].IsEmpty())
1949      continue;
1950
1951    vector<ChangeRecord> ordered_changes;
1952    change_buffers_[i].GetAllChangesInTreeOrder(&trans, &ordered_changes);
1953    if (!ordered_changes.empty()) {
1954      observer_->OnChangesApplied(syncable::ModelTypeFromInt(i), &trans,
1955                                  &ordered_changes[0], ordered_changes.size());
1956      model_has_change_.set(i, true);
1957    }
1958    change_buffers_[i].Clear();
1959  }
1960}
1961
1962void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncApi(
1963    const syncable::DirectoryChangeEvent& event) {
1964  // We have been notified about a user action changing the bookmark model.
1965  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::CALCULATE_CHANGES);
1966  DCHECK(event.writer == syncable::SYNCAPI ||
1967         event.writer == syncable::UNITTEST);
1968  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
1969      "CALCULATE_CHANGES called with unapplied old changes.";
1970
1971  bool exists_unsynced_items = false;
1972  bool only_preference_changes = true;
1973  syncable::ModelTypeBitSet model_types;
1974  for (syncable::OriginalEntries::const_iterator i = event.originals->begin();
1975       i != event.originals->end() && !exists_unsynced_items;
1976       ++i) {
1977    int64 id = i->ref(syncable::META_HANDLE);
1978    syncable::Entry e(event.trans, syncable::GET_BY_HANDLE, id);
1979    DCHECK(e.good());
1980
1981    syncable::ModelType model_type = e.GetModelType();
1982
1983    if (e.Get(syncable::IS_UNSYNCED)) {
1984      if (model_type == syncable::TOP_LEVEL_FOLDER ||
1985          model_type == syncable::UNSPECIFIED) {
1986        NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
1987        continue;
1988      }
1989      // Unsynced items will cause us to nudge the the syncer.
1990      exists_unsynced_items = true;
1991
1992      model_types[model_type] = true;
1993      if (model_type != syncable::PREFERENCES)
1994        only_preference_changes = false;
1995    }
1996  }
1997  if (exists_unsynced_items && syncer_thread()) {
1998    int nudge_delay = only_preference_changes ?
1999        kPreferencesNudgeDelayMilliseconds : kDefaultNudgeDelayMilliseconds;
2000    syncer_thread()->NudgeSyncerWithDataTypes(
2001        nudge_delay,
2002        SyncerThread::kLocal,
2003        model_types);
2004  }
2005}
2006
2007void SyncManager::SyncInternal::SetExtraChangeRecordData(int64 id,
2008    syncable::ModelType type, ChangeReorderBuffer* buffer,
2009    Cryptographer* cryptographer, const syncable::EntryKernel& original,
2010    bool existed_before, bool exists_now) {
2011  // If this is a deletion, attach the entity specifics as extra data
2012  // so that the delete can be processed.
2013  if (!exists_now && existed_before) {
2014    buffer->SetSpecificsForId(id, original.ref(SPECIFICS));
2015    if (type == syncable::PASSWORDS) {
2016      // Need to dig a bit deeper as passwords are encrypted.
2017      scoped_ptr<sync_pb::PasswordSpecificsData> data(
2018          DecryptPasswordSpecifics(original.ref(SPECIFICS), cryptographer));
2019      if (!data.get()) {
2020        NOTREACHED();
2021        return;
2022      }
2023      buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
2024    }
2025  }
2026}
2027
2028void SyncManager::SyncInternal::HandleCalculateChangesChangeEventFromSyncer(
2029    const syncable::DirectoryChangeEvent& event) {
2030  // We only expect one notification per sync step, so change_buffers_ should
2031  // contain no pending entries.
2032  DCHECK_EQ(event.todo, syncable::DirectoryChangeEvent::CALCULATE_CHANGES);
2033  DCHECK(event.writer == syncable::SYNCER ||
2034         event.writer == syncable::UNITTEST);
2035  LOG_IF(WARNING, !ChangeBuffersAreEmpty()) <<
2036      "CALCULATE_CHANGES called with unapplied old changes.";
2037
2038  for (syncable::OriginalEntries::const_iterator i = event.originals->begin();
2039       i != event.originals->end(); ++i) {
2040    int64 id = i->ref(syncable::META_HANDLE);
2041    syncable::Entry e(event.trans, syncable::GET_BY_HANDLE, id);
2042    bool existed_before = !i->ref(syncable::IS_DEL);
2043    bool exists_now = e.good() && !e.Get(syncable::IS_DEL);
2044    DCHECK(e.good());
2045
2046    // Omit items that aren't associated with a model.
2047    syncable::ModelType type = e.GetModelType();
2048    if (type == syncable::TOP_LEVEL_FOLDER || type == syncable::UNSPECIFIED)
2049      continue;
2050
2051    if (exists_now && !existed_before)
2052      change_buffers_[type].PushAddedItem(id);
2053    else if (!exists_now && existed_before)
2054      change_buffers_[type].PushDeletedItem(id);
2055    else if (exists_now && existed_before && VisiblePropertiesDiffer(*i, e))
2056      change_buffers_[type].PushUpdatedItem(id, VisiblePositionsDiffer(*i, e));
2057
2058    SetExtraChangeRecordData(id, type, &change_buffers_[type],
2059                             dir_manager()->cryptographer(), *i,
2060                             existed_before, exists_now);
2061  }
2062}
2063
2064SyncManager::Status::Summary
2065SyncManager::SyncInternal::ComputeAggregatedStatusSummary() {
2066  switch (allstatus_.status().icon) {
2067    case AllStatus::OFFLINE:
2068      return Status::OFFLINE;
2069    case AllStatus::OFFLINE_UNSYNCED:
2070      return Status::OFFLINE_UNSYNCED;
2071    case AllStatus::SYNCING:
2072      return Status::SYNCING;
2073    case AllStatus::READY:
2074      return Status::READY;
2075    case AllStatus::CONFLICT:
2076      return Status::CONFLICT;
2077    case AllStatus::OFFLINE_UNUSABLE:
2078      return Status::OFFLINE_UNUSABLE;
2079    default:
2080      return Status::INVALID;
2081  }
2082}
2083
2084SyncManager::Status SyncManager::SyncInternal::ComputeAggregatedStatus() {
2085  Status return_status =
2086      { ComputeAggregatedStatusSummary(),
2087        allstatus_.status().authenticated,
2088        allstatus_.status().server_up,
2089        allstatus_.status().server_reachable,
2090        allstatus_.status().server_broken,
2091        allstatus_.status().notifications_enabled,
2092        allstatus_.status().notifications_received,
2093        allstatus_.status().notifications_sent,
2094        allstatus_.status().unsynced_count,
2095        allstatus_.status().conflicting_count,
2096        allstatus_.status().syncing,
2097        allstatus_.status().initial_sync_ended,
2098        allstatus_.status().syncer_stuck,
2099        allstatus_.status().updates_available,
2100        allstatus_.status().updates_received,
2101        allstatus_.status().disk_full,
2102        false,   // TODO(ncarter): invalid store?
2103        allstatus_.status().max_consecutive_errors};
2104  return return_status;
2105}
2106
2107void SyncManager::SyncInternal::OnSyncEngineEvent(
2108    const SyncEngineEvent& event) {
2109  if (!observer_)
2110    return;
2111
2112  // Only send an event if this is due to a cycle ending and this cycle
2113  // concludes a canonical "sync" process; that is, based on what is known
2114  // locally we are "all happy" and up-to-date.  There may be new changes on
2115  // the server, but we'll get them on a subsequent sync.
2116  //
2117  // Notifications are sent at the end of every sync cycle, regardless of
2118  // whether we should sync again.
2119  if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
2120    ModelSafeRoutingInfo enabled_types;
2121    registrar_->GetModelSafeRoutingInfo(&enabled_types);
2122    if (enabled_types.count(syncable::PASSWORDS) > 0) {
2123      Cryptographer* cryptographer =
2124          GetUserShare()->dir_manager->cryptographer();
2125      if (!cryptographer->is_ready() && !cryptographer->has_pending_keys()) {
2126        sync_api::ReadTransaction trans(GetUserShare());
2127        sync_api::ReadNode node(&trans);
2128        if (!node.InitByTagLookup(kNigoriTag)) {
2129          DCHECK(!event.snapshot->is_share_usable);
2130          return;
2131        }
2132        const sync_pb::NigoriSpecifics& nigori = node.GetNigoriSpecifics();
2133        if (!nigori.encrypted().blob().empty()) {
2134          DCHECK(!cryptographer->CanDecrypt(nigori.encrypted()));
2135          cryptographer->SetPendingKeys(nigori.encrypted());
2136        }
2137      }
2138
2139      // If we've completed a sync cycle and the cryptographer isn't ready yet,
2140      // prompt the user for a passphrase.
2141      if (cryptographer->has_pending_keys()) {
2142        observer_->OnPassphraseRequired(true);
2143      } else if (!cryptographer->is_ready()) {
2144        observer_->OnPassphraseRequired(false);
2145      }
2146    }
2147
2148    if (!initialized())
2149      return;
2150
2151    if (!event.snapshot->has_more_to_sync) {
2152      observer_->OnSyncCycleCompleted(event.snapshot);
2153    }
2154
2155    if (notifier_options_.notification_method !=
2156        notifier::NOTIFICATION_SERVER) {
2157      // TODO(chron): Consider changing this back to track has_more_to_sync
2158      // only notify peers if a successful commit has occurred.
2159      bool new_pending_notification =
2160          (event.snapshot->syncer_status.num_successful_commits > 0);
2161      core_message_loop_->PostTask(
2162          FROM_HERE,
2163          NewRunnableMethod(
2164              this,
2165              &SyncManager::SyncInternal::SendPendingXMPPNotification,
2166              new_pending_notification));
2167    }
2168  }
2169
2170  if (event.what_happened == SyncEngineEvent::SYNCER_THREAD_PAUSED) {
2171    observer_->OnPaused();
2172    return;
2173  }
2174
2175  if (event.what_happened == SyncEngineEvent::SYNCER_THREAD_RESUMED) {
2176    observer_->OnResumed();
2177    return;
2178  }
2179
2180  if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
2181    observer_->OnStopSyncingPermanently();
2182    return;
2183  }
2184
2185  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
2186    observer_->OnClearServerDataSucceeded();
2187    return;
2188  }
2189
2190  if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
2191    observer_->OnClearServerDataFailed();
2192    return;
2193  }
2194
2195  if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
2196    observer_->OnUpdatedToken(event.updated_token);
2197    return;
2198  }
2199}
2200
2201void SyncManager::SyncInternal::OnNotificationStateChange(
2202    bool notifications_enabled) {
2203  VLOG(1) << "P2P: Notifications enabled = "
2204          << (notifications_enabled ? "true" : "false");
2205  allstatus_.SetNotificationsEnabled(notifications_enabled);
2206  if (syncer_thread()) {
2207    syncer_thread()->SetNotificationsEnabled(notifications_enabled);
2208  }
2209  if ((notifier_options_.notification_method !=
2210       notifier::NOTIFICATION_SERVER) && notifications_enabled) {
2211    // Nudge the syncer thread when notifications are enabled, in case there is
2212    // any data that has not yet been synced. If we are listening to
2213    // server-issued notifications, we are already guaranteed to receive a
2214    // notification on a successful connection.
2215    if (syncer_thread()) {
2216      syncer_thread()->NudgeSyncer(0, SyncerThread::kLocal);
2217    }
2218
2219    // Send a notification as soon as subscriptions are on
2220    // (see http://code.google.com/p/chromium/issues/detail?id=38563 ).
2221    core_message_loop_->PostTask(
2222        FROM_HERE,
2223        NewRunnableMethod(
2224            this,
2225            &SyncManager::SyncInternal::SendPendingXMPPNotification,
2226            true));
2227  }
2228}
2229
2230void SyncManager::SyncInternal::TalkMediatorLogin(
2231    const std::string& email, const std::string& token) {
2232  DCHECK_EQ(MessageLoop::current(), core_message_loop_);
2233  DCHECK(!email.empty());
2234  DCHECK(!token.empty());
2235  InitializeTalkMediator();
2236  talk_mediator_->SetAuthToken(email, token, SYNC_SERVICE_NAME);
2237  talk_mediator_->Login();
2238}
2239
2240void SyncManager::SyncInternal::OnIncomingNotification(
2241    const IncomingNotificationData& notification_data) {
2242  syncable::ModelTypeBitSet model_types;
2243
2244  // Check if the service url is a sync URL.  An empty service URL is
2245  // treated as a legacy sync notification.  If we're listening to
2246  // server-issued notifications, no need to check the service_url.
2247  if (notifier_options_.notification_method ==
2248      notifier::NOTIFICATION_SERVER) {
2249    VLOG(1) << "Sync received server notification: " <<
2250        notification_data.service_specific_data;
2251
2252    if (!syncable::ModelTypeBitSetFromString(
2253            notification_data.service_specific_data,
2254            &model_types)) {
2255      LOG(DFATAL) << "Could not extract model types from server data.";
2256      model_types.set();
2257    }
2258  } else if (notification_data.service_url.empty() ||
2259             (notification_data.service_url ==
2260              browser_sync::kSyncLegacyServiceUrl) ||
2261             (notification_data.service_url ==
2262              browser_sync::kSyncServiceUrl)) {
2263    VLOG(1) << "Sync received P2P notification.";
2264
2265    // Catch for sync integration tests (uses p2p). Just set all datatypes.
2266    model_types.set();
2267  } else {
2268    LOG(WARNING) << "Notification fron unexpected source: "
2269                 << notification_data.service_url;
2270  }
2271
2272  if (model_types.any()) {
2273    if (syncer_thread()) {
2274     // Introduce a delay to help coalesce initial notifications.
2275     syncer_thread()->NudgeSyncerWithDataTypes(
2276         250,
2277         SyncerThread::kNotification,
2278         model_types);
2279    }
2280    allstatus_.IncrementNotificationsReceived();
2281  } else {
2282    LOG(WARNING) << "Sync received notification without any type information.";
2283  }
2284}
2285
2286void SyncManager::SyncInternal::OnOutgoingNotification() {
2287  DCHECK_NE(notifier_options_.notification_method,
2288            notifier::NOTIFICATION_SERVER);
2289  allstatus_.IncrementNotificationsSent();
2290}
2291
2292void SyncManager::SyncInternal::WriteState(const std::string& state) {
2293  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2294  if (!lookup.good()) {
2295    LOG(ERROR) << "Could not write notification state";
2296    // TODO(akalin): Propagate result callback all the way to this
2297    // function and call it with "false" to signal failure.
2298    return;
2299  }
2300  if (VLOG_IS_ON(1)) {
2301    std::string encoded_state;
2302    base::Base64Encode(state, &encoded_state);
2303    VLOG(1) << "Writing notification state: " << encoded_state;
2304  }
2305  lookup->SetNotificationState(state);
2306  lookup->SaveChanges();
2307}
2308
2309SyncManager::Status::Summary SyncManager::GetStatusSummary() const {
2310  return data_->ComputeAggregatedStatusSummary();
2311}
2312
2313SyncManager::Status SyncManager::GetDetailedStatus() const {
2314  return data_->ComputeAggregatedStatus();
2315}
2316
2317SyncManager::SyncInternal* SyncManager::GetImpl() const { return data_; }
2318
2319void SyncManager::SaveChanges() {
2320  data_->SaveChanges();
2321}
2322
2323void SyncManager::SyncInternal::SaveChanges() {
2324  syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
2325  if (!lookup.good()) {
2326    DCHECK(false) << "ScopedDirLookup creation failed; Unable to SaveChanges";
2327    return;
2328  }
2329  lookup->SaveChanges();
2330}
2331
2332//////////////////////////////////////////////////////////////////////////
2333// BaseTransaction member definitions
2334BaseTransaction::BaseTransaction(UserShare* share)
2335    : lookup_(NULL) {
2336  DCHECK(share && share->dir_manager.get());
2337  lookup_ = new syncable::ScopedDirLookup(share->dir_manager.get(),
2338                                          share->name);
2339  cryptographer_ = share->dir_manager->cryptographer();
2340  if (!(lookup_->good()))
2341    DCHECK(false) << "ScopedDirLookup failed on valid DirManager.";
2342}
2343BaseTransaction::~BaseTransaction() {
2344  delete lookup_;
2345}
2346
2347UserShare* SyncManager::GetUserShare() const {
2348  DCHECK(data_->initialized()) << "GetUserShare requires initialization!";
2349  return data_->GetUserShare();
2350}
2351
2352bool SyncManager::HasUnsyncedItems() const {
2353  sync_api::ReadTransaction trans(GetUserShare());
2354  return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
2355}
2356
2357}  // namespace sync_api
2358