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