15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/sync_manager_impl.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_writer.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/ref_counted.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/observer_list.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/engine/sync_scheduler.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/engine/syncer_types.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/change_reorder_buffer.h"
22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "sync/internal_api/public/base/cancelation_signal.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/base/model_type.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/base_node.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/configure_reason.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/engine/polling_constants.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/http_post_provider_factory.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/internal_components_factory.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/read_node.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/read_transaction.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/user_share.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/util/experiments.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/write_node.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/public/write_transaction.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/syncapi_internal.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/internal_api/syncapi_server_connection_manager.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/js/js_arg_list.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/js/js_event_details.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/js/js_event_handler.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/js/js_reply_handler.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/notifier/invalidation_util.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/notifier/invalidator.h"
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "sync/notifier/object_id_invalidation_map.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/proto_value_conversions.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/protocol/sync.pb.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/directory.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/entry.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/in_memory_directory_backing_store.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sync/syncable/on_disk_directory_backing_store.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using sync_pb::GetUpdatesCallerInfo;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace syncer {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using sessions::SyncSessionContext;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::ImmutableWriteTransactionInfo;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using syncable::SPECIFICS;
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using syncable::UNIQUE_POSITION;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delays for syncer nudges.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kDefaultNudgeDelayMilliseconds = 200;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kPreferencesNudgeDelayMilliseconds = 2000;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSyncRefreshDelayMsec = 500;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kSyncSchedulerDelayMsec = 250;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum count and size for traffic recorder.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const unsigned int kMaxMessagesToRecord = 10;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const unsigned int kMaxMessageSizeToRecord = 5 * 1024;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason(
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ConfigureReason reason) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (reason) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIGURE_REASON_RECONFIGURATION:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GetUpdatesCallerInfo::RECONFIGURATION;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIGURE_REASON_MIGRATION:
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GetUpdatesCallerInfo::MIGRATION;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIGURE_REASON_NEW_CLIENT:
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GetUpdatesCallerInfo::NEW_CLIENT;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE:
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case CONFIGURE_REASON_CRYPTO:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetUpdatesCallerInfo::UNKNOWN;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A class to calculate nudge delays for types.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NudgeStrategy {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static TimeDelta GetNudgeDelayTimeDelta(const ModelType& model_type,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          SyncManagerImpl* core) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NudgeDelayStrategy delay_type = GetNudgeDelayStrategy(model_type);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetNudgeDelayTimeDeltaFromType(delay_type,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          model_type,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          core);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Possible types of nudge delay for datatypes.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note: These are just hints. If a sync happens then all dirty entries
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // would be committed as part of the sync.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum NudgeDelayStrategy {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync right away.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IMMEDIATE,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sync this change while syncing another change.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ACCOMPANY_ONLY,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The datatype does not use one of the predefined wait times but defines
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // its own wait time logic for nudge.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CUSTOM,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static NudgeDelayStrategy GetNudgeDelayStrategy(const ModelType& type) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (type) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case AUTOFILL:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       return ACCOMPANY_ONLY;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case PREFERENCES:
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case SESSIONS:
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     case FAVICON_IMAGES:
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)     case FAVICON_TRACKING:
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       return CUSTOM;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     default:
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       return IMMEDIATE;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static TimeDelta GetNudgeDelayTimeDeltaFromType(
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const NudgeDelayStrategy& delay_type, const ModelType& model_type,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const SyncManagerImpl* core) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(core);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TimeDelta delay = TimeDelta::FromMilliseconds(
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       kDefaultNudgeDelayMilliseconds);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (delay_type) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case IMMEDIATE:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       delay = TimeDelta::FromMilliseconds(
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           kDefaultNudgeDelayMilliseconds);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       break;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case ACCOMPANY_ONLY:
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       delay = TimeDelta::FromSeconds(kDefaultShortPollIntervalSeconds);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       break;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     case CUSTOM:
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       switch (model_type) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         case PREFERENCES:
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           delay = TimeDelta::FromMilliseconds(
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               kPreferencesNudgeDelayMilliseconds);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           break;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         case SESSIONS:
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         case FAVICON_IMAGES:
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         case FAVICON_TRACKING:
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           delay = core->scheduler()->GetSessionsCommitDelay();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           break;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         default:
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           NOTREACHED();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       break;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     default:
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       NOTREACHED();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return delay;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncManagerImpl::SyncManagerImpl(const std::string& name)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : name_(name),
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      change_delegate_(NULL),
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      initialized_(false),
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      observing_network_connectivity_changes_(false),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      invalidator_state_(DEFAULT_INVALIDATION_ERROR),
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      traffic_recorder_(kMaxMessagesToRecord, kMaxMessageSizeToRecord),
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encryptor_(NULL),
1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      report_unrecoverable_error_function_(NULL),
1794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      weak_ptr_factory_(this) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pre-fill |notification_info_map_|.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    notification_info_map_.insert(
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        std::make_pair(ModelTypeFromInt(i), NotificationInfo()));
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bind message handlers.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "getNotificationState",
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetNotificationState);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "getNotificationInfo",
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetNotificationInfo);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "getRootNodeDetails",
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetRootNodeDetails);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "getNodeSummariesById",
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetNodeSummariesById);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     "getNodeDetailsById",
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetNodeDetailsById);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "getAllNodes",
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetAllNodes);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "getChildNodeIds",
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetChildNodeIds);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BindJsMessageHandler(
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "getClientServerTraffic",
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &SyncManagerImpl::GetClientServerTraffic);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncManagerImpl::~SyncManagerImpl() {
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!initialized_);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncManagerImpl::NotificationInfo::NotificationInfo() : total_count(0) {}
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncManagerImpl::NotificationInfo::~NotificationInfo() {}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* SyncManagerImpl::NotificationInfo::ToValue() const {
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* value = new base::DictionaryValue();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetInteger("totalCount", total_count);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value->SetString("payload", payload);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncManagerImpl::VisiblePositionsDiffer(
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncable::EntryKernelMutation& mutation) const {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const syncable::EntryKernel& a = mutation.original;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const syncable::EntryKernel& b = mutation.mutated;
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!b.ShouldMaintainPosition())
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!a.ref(UNIQUE_POSITION).Equals(b.ref(UNIQUE_POSITION)))
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (a.ref(syncable::PARENT_ID) != b.ref(syncable::PARENT_ID))
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncManagerImpl::VisiblePropertiesDiffer(
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const syncable::EntryKernelMutation& mutation,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cryptographer* cryptographer) const {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const syncable::EntryKernel& a = mutation.original;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const syncable::EntryKernel& b = mutation.mutated;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const sync_pb::EntitySpecifics& a_specifics = a.ref(SPECIFICS);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const sync_pb::EntitySpecifics& b_specifics = b.ref(SPECIFICS);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(GetModelTypeFromSpecifics(a_specifics),
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            GetModelTypeFromSpecifics(b_specifics));
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelType model_type = GetModelTypeFromSpecifics(b_specifics);
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Suppress updates to items that aren't tracked by any browser model.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_type < FIRST_REAL_MODEL_TYPE ||
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !a.ref(syncable::UNIQUE_SERVER_TAG).empty()) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (a.ref(syncable::IS_DIR) != b.ref(syncable::IS_DIR))
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!AreSpecificsEqual(cryptographer,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         a.ref(syncable::SPECIFICS),
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         b.ref(syncable::SPECIFICS))) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only care if the name has changed if neither specifics is encrypted
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (encrypted nodes blow away the NON_UNIQUE_NAME).
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!a_specifics.has_encrypted() && !b_specifics.has_encrypted() &&
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a.ref(syncable::NON_UNIQUE_NAME) != b.ref(syncable::NON_UNIQUE_NAME))
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (VisiblePositionsDiffer(mutation))
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::ThrowUnrecoverableError() {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, GetUserShare());
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  trans.GetWrappedTrans()->OnUnrecoverableError(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE, "Simulating unrecoverable error for testing purposes.");
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ModelTypeSet SyncManagerImpl::InitialSyncEndedTypes() {
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return directory()->InitialSyncEndedTypes();
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ModelTypeSet SyncManagerImpl::GetTypesWithEmptyProgressMarkerToken(
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelTypeSet types) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelTypeSet result;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ModelTypeSet::Iterator i = types.First(); i.Good(); i.Inc()) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_pb::DataTypeProgressMarker marker;
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    directory()->GetDownloadProgress(i.Get(), &marker);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (marker.token().empty())
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result.Put(i.Get());
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::ConfigureSyncer(
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ConfigureReason reason,
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ModelTypeSet to_download,
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ModelTypeSet to_purge,
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ModelTypeSet to_journal,
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ModelTypeSet to_unapply,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelSafeRoutingInfo& new_routing_info,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& ready_task,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::Closure& retry_task) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!ready_task.is_null());
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!retry_task.is_null());
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DVLOG(1) << "Configuring -"
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           << "\n\t" << "current types: "
312868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           << ModelTypeSetToString(GetRoutingInfoTypes(new_routing_info))
313eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           << "\n\t" << "types to download: "
314eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           << ModelTypeSetToString(to_download)
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           << "\n\t" << "types to purge: "
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           << ModelTypeSetToString(to_purge)
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           << "\n\t" << "types to journal: "
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)           << ModelTypeSetToString(to_journal)
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           << "\n\t" << "types to unapply: "
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch           << ModelTypeSetToString(to_unapply);
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!PurgeDisabledTypes(to_purge,
322868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                          to_journal,
323868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                          to_unapply)) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We failed to cleanup the types. Invoke the ready task without actually
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // configuring any types. The caller should detect this as a configuration
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // failure and act appropriately.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ready_task.Run();
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigurationParams params(GetSourceFromReason(reason),
332868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                             to_download,
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             new_routing_info,
334f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             ready_task,
335f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             retry_task);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scheduler_->ScheduleConfiguration(params);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::Init(
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& database_location,
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<JsEventHandler>& event_handler,
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& sync_server_and_path,
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int port,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool use_ssl,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<HttpPostProviderFactory> post_factory,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<ModelSafeWorker*>& workers,
349a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    ExtensionsActivity* extensions_activity,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SyncManager::ChangeDelegate* change_delegate,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const SyncCredentials& credentials,
352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& invalidator_client_id,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& restored_key_for_bootstrapping,
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& restored_keystore_key_for_bootstrapping,
355a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    InternalComponentsFactory* internal_components_factory,
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Encryptor* encryptor,
357a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
3587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
359d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    CancelationSignal* cancelation_signal) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!initialized_);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(post_factory.get());
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!credentials.email.empty());
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!credentials.sync_token.empty());
365d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK(cancelation_signal);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "SyncManager starting Init...";
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_delegate_ = change_delegate;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddObserver(&js_sync_manager_observer_);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetJsEventHandler(event_handler);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddObserver(&debug_info_event_listener_);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  database_path_ = database_location.Append(
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      syncable::Directory::kSyncDatabaseFilename);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  encryptor_ = encryptor;
380a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  unrecoverable_error_handler_ = unrecoverable_error_handler.Pass();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  report_unrecoverable_error_function_ = report_unrecoverable_error_function;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetHasKeystoreKey(
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !restored_keystore_key_for_bootstrapping.empty());
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_encryption_handler_.reset(new SyncEncryptionHandlerImpl(
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &share_,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encryptor,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      restored_key_for_bootstrapping,
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      restored_keystore_key_for_bootstrapping));
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_encryption_handler_->AddObserver(this);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_encryption_handler_->AddObserver(&debug_info_event_listener_);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sync_encryption_handler_->AddObserver(&js_sync_encryption_handler_observer_);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::FilePath absolute_db_path = database_path_;
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(absolute_db_path.IsAbsolute());
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<syncable::DirectoryBackingStore> backing_store =
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      internal_components_factory->BuildDirectoryBackingStore(
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          credentials.email, absolute_db_path).Pass();
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(backing_store.get());
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const std::string& username = credentials.email;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  share_.directory.reset(
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new syncable::Directory(
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          backing_store.release(),
406a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          unrecoverable_error_handler_.get(),
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          report_unrecoverable_error_function_,
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sync_encryption_handler_.get(),
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sync_encryption_handler_->GetCryptographerUnsafe()));
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Username: " << username;
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!OpenDirectory(username)) {
4131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    NotifyInitializationFailure();
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Sync manager initialization failed!";
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_manager_.reset(new SyncAPIServerConnectionManager(
4191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      sync_server_and_path, port, use_ssl,
420d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      post_factory.release(), cancelation_signal));
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_manager_->set_client_id(directory()->cache_guid());
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_manager_->AddListener(this);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string sync_id = directory()->cache_guid();
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  allstatus_.SetSyncId(sync_id);
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  allstatus_.SetInvalidatorClientId(invalidator_client_id);
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Setting sync client ID: " << sync_id;
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Setting invalidator client ID: " << invalidator_client_id;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Build a SyncSessionContext and store the worker in it.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Sync is bringing up SyncSessionContext.";
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SyncEngineEventListener*> listeners;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listeners.push_back(&allstatus_);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  listeners.push_back(this);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  session_context_ = internal_components_factory->BuildContext(
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      connection_manager_.get(),
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      directory(),
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      workers,
441a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      extensions_activity,
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      listeners,
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &debug_info_event_listener_,
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &traffic_recorder_,
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      invalidator_client_id).Pass();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  session_context_->set_account_name(credentials.email);
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_ = internal_components_factory->BuildScheduler(
448d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      name_, session_context_.get(), cancelation_signal).Pass();
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialized_ = true;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::NetworkChangeNotifier::AddIPAddressObserver(this);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observing_network_connectivity_changes_ = true;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateCredentials(credentials);
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  NotifyInitializationSuccess();
4611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void SyncManagerImpl::NotifyInitializationSuccess() {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnInitializationComplete(
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()),
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        true, InitialSyncEndedTypes()));
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void SyncManagerImpl::NotifyInitializationFailure() {
4721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
4731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                    OnInitializationComplete(
4741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()),
4751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        MakeWeakHandle(debug_info_event_listener_.GetWeakPtr()),
4761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        false, ModelTypeSet()));
4771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
4781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnPassphraseRequired(
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PassphraseRequiredReason reason,
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const sync_pb::EncryptedData& pending_keys) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Does nothing.
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnPassphraseAccepted() {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Does nothing.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnBootstrapTokenUpdated(
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& bootstrap_token,
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BootstrapTokenType type) {
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == KEYSTORE_BOOTSTRAP_TOKEN)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    allstatus_.SetHasKeystoreKey(true);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              bool encrypt_everything) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetEncryptedTypes(encrypted_types);
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnEncryptionComplete() {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Does nothing.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnCryptographerStateChanged(
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cryptographer* cryptographer) {
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetCryptographerReady(cryptographer->is_ready());
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetCryptoHasPendingKeys(cryptographer->has_pending_keys());
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetKeystoreMigrationTime(
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_encryption_handler_->migration_time());
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnPassphraseTypeChanged(
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PassphraseType type,
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time explicit_passphrase_time) {
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetPassphraseType(type);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetKeystoreMigrationTime(
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sync_encryption_handler_->migration_time());
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::StartSyncingNormally(
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelSafeRoutingInfo& routing_info) {
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start the sync scheduler.
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(sync): We always want the newest set of routes when we switch back
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to normal mode. Figure out how to enforce set_routing_info is always
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // appropriately set and that it's only modified when switching to normal
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mode.
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  session_context_->set_routing_info(routing_info);
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_->Start(SyncScheduler::NORMAL_MODE);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)syncable::Directory* SyncManagerImpl::directory() {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return share_.directory.get();
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SyncScheduler* SyncManagerImpl::scheduler() const {
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scheduler_.get();
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncManagerImpl::GetHasInvalidAuthTokenForTest() const {
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return connection_manager_->HasInvalidAuthToken();
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SyncManagerImpl::OpenDirectory(const std::string& username) {
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!initialized_) << "Should only happen once";
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set before Open().
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_observer_ = MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr());
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WeakHandle<syncable::TransactionObserver> transaction_observer(
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      MakeWeakHandle(js_mutation_event_observer_.AsWeakPtr()));
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncable::DirOpenResult open_result = syncable::NOT_INITIALIZED;
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  open_result = directory()->Open(username, this, transaction_observer);
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (open_result != syncable::OPENED) {
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Could not open share for:" << username;
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unapplied datatypes (those that do not have initial sync ended set) get
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // re-downloaded during any configuration. But, it's possible for a datatype
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to have a progress marker but not have initial sync ended yet, making
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it a candidate for migration. This is a problem, as the DataTypeManager
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // does not support a migration while it's already in the middle of a
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // configuration. As a result, any partially synced datatype can stall the
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // DTM, waiting for the configuration to complete, which it never will due
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the migration error. In addition, a partially synced nigori will
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // trigger the migration logic before the backend is initialized, resulting
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in crashes. We therefore detect and purge any partially synced types as
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // part of initialization.
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PurgePartiallySyncedTypes())
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncManagerImpl::PurgePartiallySyncedTypes() {
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelTypeSet partially_synced_types = ModelTypeSet::All();
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  partially_synced_types.RemoveAll(InitialSyncEndedTypes());
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  partially_synced_types.RemoveAll(GetTypesWithEmptyProgressMarkerToken(
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ModelTypeSet::All()));
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "Purging partially synced types "
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << ModelTypeSetToString(partially_synced_types);
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_COUNTS("Sync.PartiallySyncedTypes",
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       partially_synced_types.Size());
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (partially_synced_types.Empty())
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return directory()->PurgeEntriesWithTypeIn(partially_synced_types,
590868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             ModelTypeSet(),
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             ModelTypeSet());
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncManagerImpl::PurgeDisabledTypes(
595eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ModelTypeSet to_purge,
596868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ModelTypeSet to_journal,
597868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ModelTypeSet to_unapply) {
598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (to_purge.Empty())
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
600eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DVLOG(1) << "Purging disabled types " << ModelTypeSetToString(to_purge);
601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(to_purge.HasAll(to_journal));
602eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(to_purge.HasAll(to_unapply));
603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return directory()->PurgeEntriesWithTypeIn(to_purge, to_journal, to_unapply);
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncManagerImpl::UpdateCredentials(const SyncCredentials& credentials) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(initialized_);
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!credentials.email.empty());
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!credentials.sync_token.empty());
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observing_network_connectivity_changes_ = true;
6137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!connection_manager_->SetAuthToken(credentials.sync_token))
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // Auth token is known to be invalid, so exit early.
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_->OnCredentialsUpdated();
617c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(zea): pass the credential age to the debug info event listener.
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::AddObserver(SyncManager::Observer* observer) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) {
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::ShutdownOnSyncThread() {
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prevent any in-flight method calls from running.  Also
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // invalidates |weak_handle_this_| and |change_observer_|.
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_mutation_event_observer_.InvalidateWeakPtrs();
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_.reset();
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  session_context_.reset();
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (sync_encryption_handler_) {
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_encryption_handler_->RemoveObserver(&debug_info_event_listener_);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_encryption_handler_->RemoveObserver(this);
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetJsEventHandler(WeakHandle<JsEventHandler>());
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveObserver(&js_sync_manager_observer_);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveObserver(&debug_info_event_listener_);
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
652eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // |connection_manager_| may end up being NULL here in tests (in synchronous
653eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // initialization mode).
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(akalin): Fix this behavior.
656c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (connection_manager_)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    connection_manager_->RemoveListener(this);
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  connection_manager_.reset();
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observing_network_connectivity_changes_ = false;
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized_ && directory()) {
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    directory()->SaveChanges();
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  share_.directory.reset();
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_delegate_ = NULL;
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialized_ = false;
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We reset these here, since only now we know they will not be
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // accessed from other threads (since we shut down everything).
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_observer_.Reset();
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_handle_this_.Reset();
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnIPAddressChanged() {
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!observing_network_connectivity_changes_) {
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "IP address change dropped.";
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "IP address change detected.";
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnNetworkConnectivityChangedImpl();
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnConnectionTypeChanged(
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::NetworkChangeNotifier::ConnectionType) {
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!observing_network_connectivity_changes_) {
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Connection type change dropped.";
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Connection type change detected.";
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnNetworkConnectivityChangedImpl();
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnNetworkConnectivityChangedImpl() {
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_->OnConnectionStatusChange();
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnServerConnectionEvent(
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ServerConnectionEvent& event) {
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.connection_code ==
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HttpResponse::SERVER_CONNECTION_OK) {
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      OnConnectionStatusChange(CONNECTION_OK));
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.connection_code == HttpResponse::SYNC_AUTH_ERROR) {
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    observing_network_connectivity_changes_ = false;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      OnConnectionStatusChange(CONNECTION_AUTH_ERROR));
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.connection_code == HttpResponse::SYNC_SERVER_ERROR) {
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      OnConnectionStatusChange(CONNECTION_SERVER_ERROR));
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::HandleTransactionCompleteChangeEvent(
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelTypeSet models_with_changes) {
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This notification happens immediately after the transaction mutex is
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // released. This allows work to be performed without blocking other threads
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from acquiring a transaction.
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!change_delegate_)
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call commit.
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ModelTypeSet::Iterator it = models_with_changes.First();
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it.Good(); it.Inc()) {
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change_delegate_->OnChangesComplete(it.Get());
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change_observer_.Call(
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &SyncManager::ChangeObserver::OnChangesComplete,
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        it.Get());
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ModelTypeSet
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncManagerImpl::HandleTransactionEndingChangeEvent(
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ImmutableWriteTransactionInfo& write_transaction_info,
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncable::BaseTransaction* trans) {
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This notification happens immediately before a syncable WriteTransaction
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // falls out of scope. It happens while the channel mutex is still held,
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and while the transaction mutex is held, so it cannot be re-entrant.
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!change_delegate_ || change_records_.empty())
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ModelTypeSet();
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This will continue the WriteTransaction using a read only wrapper.
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the last chance for read to occur in the WriteTransaction
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that's closing. This special ReadTransaction will not close the
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // underlying transaction.
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction read_trans(GetUserShare(), trans);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelTypeSet models_with_changes;
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ChangeRecordMap::const_iterator it = change_records_.begin();
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != change_records_.end(); ++it) {
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!it->second.Get().empty());
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType type = ModelTypeFromInt(it->first);
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change_delegate_->
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnChangesApplied(type, trans->directory()->GetTransactionVersion(type),
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         &read_trans, it->second);
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    change_observer_.Call(FROM_HERE,
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &SyncManager::ChangeObserver::OnChangesApplied,
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        type, write_transaction_info.Get().id, it->second);
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    models_with_changes.Put(type);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  change_records_.clear();
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return models_with_changes;
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncApi(
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ImmutableWriteTransactionInfo& write_transaction_info,
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncable::BaseTransaction* trans,
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<int64>* entries_changed) {
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We have been notified about a user action changing a sync model.
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG_IF(WARNING, !change_records_.empty()) <<
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CALCULATE_CHANGES called with unapplied old changes.";
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The mutated model type, or UNSPECIFIED if nothing was mutated.
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ModelTypeSet mutated_model_types;
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const syncable::ImmutableEntryKernelMutationMap& mutations =
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      write_transaction_info.Get().mutations;
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (syncable::EntryKernelMutationMap::const_iterator it =
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           mutations.Get().begin(); it != mutations.Get().end(); ++it) {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!it->second.mutated.ref(syncable::IS_UNSYNCED)) {
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType model_type =
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS));
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (model_type < FIRST_REAL_MODEL_TYPE) {
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED() << "Permanent or underspecified item changed via syncapi.";
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Found real mutation.
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (model_type != UNSPECIFIED) {
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      mutated_model_types.Put(model_type);
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      entries_changed->push_back(it->second.mutated.ref(syncable::META_HANDLE));
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Nudge if necessary.
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!mutated_model_types.Empty()) {
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (weak_handle_this_.IsInitialized()) {
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      weak_handle_this_.Call(FROM_HERE,
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             &SyncManagerImpl::RequestNudgeForDataTypes,
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             FROM_HERE,
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             mutated_model_types);
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::SetExtraChangeRecordData(int64 id,
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType type, ChangeReorderBuffer* buffer,
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Cryptographer* cryptographer, const syncable::EntryKernel& original,
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool existed_before, bool exists_now) {
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If this is a deletion and the datatype was encrypted, we need to decrypt it
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and attach it to the buffer.
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!exists_now && existed_before) {
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sync_pb::EntitySpecifics original_specifics(original.ref(SPECIFICS));
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (type == PASSWORDS) {
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Passwords must use their own legacy ExtraPasswordChangeRecordData.
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      scoped_ptr<sync_pb::PasswordSpecificsData> data(
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          DecryptPasswordSpecifics(original_specifics, cryptographer));
835c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!data) {
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      buffer->SetExtraDataForId(id, new ExtraPasswordChangeRecordData(*data));
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (original_specifics.has_encrypted()) {
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // All other datatypes can just create a new unencrypted specifics and
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // attach it.
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const sync_pb::EncryptedData& encrypted = original_specifics.encrypted();
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!cryptographer->Decrypt(encrypted, &original_specifics)) {
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NOTREACHED();
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->SetSpecificsForId(id, original_specifics);
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::HandleCalculateChangesChangeEventFromSyncer(
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ImmutableWriteTransactionInfo& write_transaction_info,
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    syncable::BaseTransaction* trans,
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<int64>* entries_changed) {
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only expect one notification per sync step, so change_buffers_ should
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // contain no pending entries.
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG_IF(WARNING, !change_records_.empty()) <<
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "CALCULATE_CHANGES called with unapplied old changes.";
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChangeReorderBuffer change_buffers[MODEL_TYPE_COUNT];
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Cryptographer* crypto = directory()->GetCryptographer(trans);
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const syncable::ImmutableEntryKernelMutationMap& mutations =
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      write_transaction_info.Get().mutations;
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (syncable::EntryKernelMutationMap::const_iterator it =
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           mutations.Get().begin(); it != mutations.Get().end(); ++it) {
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool existed_before = !it->second.original.ref(syncable::IS_DEL);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool exists_now = !it->second.mutated.ref(syncable::IS_DEL);
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Omit items that aren't associated with a model.
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelType type =
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetModelTypeFromSpecifics(it->second.mutated.ref(SPECIFICS));
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (type < FIRST_REAL_MODEL_TYPE)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 handle = it->first;
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (exists_now && !existed_before)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      change_buffers[type].PushAddedItem(handle);
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (!exists_now && existed_before)
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      change_buffers[type].PushDeletedItem(handle);
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (exists_now && existed_before &&
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             VisiblePropertiesDiffer(it->second, crypto)) {
8857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      change_buffers[type].PushUpdatedItem(handle);
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetExtraChangeRecordData(handle, type, &change_buffers[type], crypto,
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             it->second.original, existed_before, exists_now);
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction read_trans(GetUserShare(), trans);
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!change_buffers[i].IsEmpty()) {
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (change_buffers[i].GetAllChangesInTreeOrder(&read_trans,
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     &(change_records_[i]))) {
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t j = 0; j < change_records_[i].Get().size(); ++j)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          entries_changed->push_back((change_records_[i].Get())[j].id);
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (change_records_[i].Get().empty())
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        change_records_.erase(i);
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TimeDelta SyncManagerImpl::GetNudgeDelayTimeDelta(
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ModelType& model_type) {
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NudgeStrategy::GetNudgeDelayTimeDelta(model_type, this);
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::RequestNudgeForDataTypes(
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const tracked_objects::Location& nudge_location,
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ModelTypeSet types) {
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  debug_info_event_listener_.OnNudgeFromDatatype(types.First().Get());
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(lipalani) : Calculate the nudge delay based on all types.
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta nudge_delay = NudgeStrategy::GetNudgeDelayTimeDelta(
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      types.First().Get(),
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this);
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.IncrementNudgeCounter(NUDGE_SOURCE_LOCAL);
921b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  scheduler_->ScheduleLocalNudge(nudge_delay,
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 types,
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 nudge_location);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) {
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only send an event if this is due to a cycle ending and this cycle
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // concludes a canonical "sync" process; that is, based on what is known
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // locally we are "all happy" and up-to-date.  There may be new changes on
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the server, but we'll get them on a subsequent sync.
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Notifications are sent at the end of every sync cycle, regardless of
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // whether we should sync again.
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.what_happened == SyncEngineEvent::SYNC_CYCLE_ENDED) {
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!initialized_) {
937f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      DVLOG(1) << "OnSyncCycleCompleted not sent because sync api is not "
938f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)               << "initialized";
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Sending OnSyncCycleCompleted";
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      OnSyncCycleCompleted(event.snapshot));
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      OnStopSyncingPermanently());
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event.what_happened == SyncEngineEvent::ACTIONABLE_ERROR) {
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOR_EACH_OBSERVER(
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SyncManager::Observer, observers_,
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OnActionableError(
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            event.snapshot.model_neutral_state().sync_protocol_error));
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::SetJsEventHandler(
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<JsEventHandler>& event_handler) {
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_event_handler_ = event_handler;
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_sync_manager_observer_.SetJsEventHandler(js_event_handler_);
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_mutation_event_observer_.SetJsEventHandler(js_event_handler_);
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_sync_encryption_handler_observer_.SetJsEventHandler(js_event_handler_);
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::ProcessJsMessage(
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name, const JsArgList& args,
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const WeakHandle<JsReplyHandler>& reply_handler) {
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialized_) {
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!reply_handler.IsInitialized()) {
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Uninitialized reply handler; dropping unknown message "
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            << name << " with args " << args.ToString();
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JsMessageHandler js_message_handler = js_message_handlers_[name];
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (js_message_handler.is_null()) {
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Dropping unknown message " << name
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             << " with args " << args.ToString();
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reply_handler.Call(FROM_HERE,
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     &JsReplyHandler::HandleJsReply,
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     name, js_message_handler.Run(args));
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::BindJsMessageHandler(
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& name,
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UnboundJsMessageHandler unbound_message_handler) {
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  js_message_handlers_[name] =
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(unbound_message_handler, base::Unretained(this));
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::DictionaryValue* SyncManagerImpl::NotificationInfoToValue(
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const NotificationInfoMap& notification_info) {
10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* value = new base::DictionaryValue();
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (NotificationInfoMap::const_iterator it = notification_info.begin();
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      it != notification_info.end(); ++it) {
10094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string model_type_str = ModelTypeToString(it->first);
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value->Set(model_type_str, it->second.ToValue());
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string SyncManagerImpl::NotificationInfoToString(
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const NotificationInfoMap& notification_info) {
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> value(
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NotificationInfoToValue(notification_info));
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string str;
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::JSONWriter::Write(value.get(), &str);
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return str;
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetNotificationState(
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const JsArgList& args) {
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& notification_state =
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InvalidatorStateToString(invalidator_state_);
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "GetNotificationState: " << notification_state;
10302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue return_args;
10312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return_args.Append(new base::StringValue(notification_state));
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return JsArgList(&return_args);
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetNotificationInfo(
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const JsArgList& args) {
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "GetNotificationInfo: "
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           << NotificationInfoToString(notification_info_map_);
10392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue return_args;
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return_args.Append(NotificationInfoToValue(notification_info_map_));
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return JsArgList(&return_args);
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetRootNodeDetails(
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const JsArgList& args) {
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, GetUserShare());
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadNode root(&trans);
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  root.InitByRootLookup();
10492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue return_args;
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return_args.Append(root.GetDetailsAsValue());
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return JsArgList(&return_args);
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetClientServerTraffic(
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const JsArgList& args) {
10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue return_args;
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* value = traffic_recorder_.ToValue();
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (value != NULL)
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return_args.Append(value);
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return JsArgList(&return_args);
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int64 GetId(const base::ListValue& ids, int i) {
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string id_str;
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ids.GetString(i, &id_str)) {
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kInvalidId;
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id = kInvalidId;
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!base::StringToInt64(id_str, &id)) {
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return kInvalidId;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return id;
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)JsArgList GetNodeInfoById(
10782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const JsArgList& args,
10792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UserShare* user_share,
10802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* (BaseNode::*info_getter)() const) {
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(info_getter);
10822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue return_args;
10832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* node_summaries = new base::ListValue();
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return_args.Append(node_summaries);
10852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::ListValue* id_list = NULL;
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, user_share);
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (args.Get().GetList(0, &id_list)) {
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(id_list);
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < id_list->GetSize(); ++i) {
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      int64 id = GetId(*id_list, i);
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (id == kInvalidId) {
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReadNode node(&trans);
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (node.InitByIdLookup(id) != BaseNode::INIT_OK) {
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node_summaries->Append((node.*info_getter)());
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return JsArgList(&return_args);
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetNodeSummariesById(const JsArgList& args) {
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetSummaryAsValue);
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetNodeDetailsById(const JsArgList& args) {
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetNodeInfoById(args, GetUserShare(), &BaseNode::GetDetailsAsValue);
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetAllNodes(const JsArgList& args) {
11152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue return_args;
11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* result = new base::ListValue();
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return_args.Append(result);
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, GetUserShare());
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const syncable::EntryKernel*> entry_kernels;
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  trans.GetDirectory()->GetAllEntryKernels(trans.GetWrappedTrans(),
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &entry_kernels);
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (std::vector<const syncable::EntryKernel*>::const_iterator it =
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           entry_kernels.begin(); it != entry_kernels.end(); ++it) {
11262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result->Append((*it)->ToValue(trans.GetCryptographer()));
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return JsArgList(&return_args);
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JsArgList SyncManagerImpl::GetChildNodeIds(const JsArgList& args) {
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue return_args;
11342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* child_ids = new base::ListValue();
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return_args.Append(child_ids);
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 id = GetId(args.Get(), 0);
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (id != kInvalidId) {
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReadTransaction trans(FROM_HERE, GetUserShare());
1139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    syncable::Directory::Metahandles child_handles;
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    trans.GetDirectory()->GetChildHandlesByHandle(trans.GetWrappedTrans(),
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  id, &child_handles);
1142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (syncable::Directory::Metahandles::const_iterator it =
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             child_handles.begin(); it != child_handles.end(); ++it) {
11442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      child_ids->Append(new base::StringValue(base::Int64ToString(*it)));
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return JsArgList(&return_args);
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::UpdateNotificationInfo(
115158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const ObjectIdInvalidationMap& invalidation_map) {
11524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ObjectIdSet ids = invalidation_map.GetObjectIds();
11534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
115458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ModelType type = UNSPECIFIED;
11554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (!ObjectIdToRealModelType(*it, &type)) {
11564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      continue;
11574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
11584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const SingleObjectInvalidationSet& type_invalidations =
11594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        invalidation_map.ForObject(*it);
11604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    for (SingleObjectInvalidationSet::const_iterator inv_it =
11614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)         type_invalidations.begin(); inv_it != type_invalidations.end();
11624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)         ++inv_it) {
116358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      NotificationInfo* info = &notification_info_map_[type];
116458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      info->total_count++;
11654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      std::string payload =
11664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          inv_it->is_unknown_version() ? "UNKNOWN" : inv_it->payload();
11674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      info->payload = payload;
116858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnInvalidatorStateChange(InvalidatorState state) {
1173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
1174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& state_str = InvalidatorStateToString(state);
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  invalidator_state_ = state;
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Invalidator state changed to: " << state_str;
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool notifications_enabled =
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (invalidator_state_ == INVALIDATIONS_ENABLED);
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  allstatus_.SetNotificationsEnabled(notifications_enabled);
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scheduler_->SetNotificationsEnabled(notifications_enabled);
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (js_event_handler_.IsInitialized()) {
11842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue details;
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details.SetString("state", state_str);
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js_event_handler_.Call(FROM_HERE,
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &JsEventHandler::HandleJsEvent,
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "onNotificationStateChange",
11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           JsEventDetails(&details));
11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::OnIncomingInvalidation(
11942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ObjectIdInvalidationMap& invalidation_map) {
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
11962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
119758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  // We should never receive IDs from non-sync objects.
11984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ObjectIdSet ids = invalidation_map.GetObjectIds();
119958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
120058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ModelType type;
120158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (!ObjectIdToRealModelType(*it, &type)) {
120258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      DLOG(WARNING) << "Notification has invalid id: " << ObjectIdToString(*it);
120358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
120458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
120558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (invalidation_map.Empty()) {
12072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Sync received invalidation without any type information.";
12082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    allstatus_.IncrementNudgeCounter(NUDGE_SOURCE_NOTIFICATION);
1210b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scheduler_->ScheduleInvalidationNudge(
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TimeDelta::FromMilliseconds(kSyncSchedulerDelayMsec),
121258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        invalidation_map, FROM_HERE);
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    allstatus_.IncrementNotificationsReceived();
121458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    UpdateNotificationInfo(invalidation_map);
121558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    debug_info_event_listener_.OnIncomingNotification(invalidation_map);
12162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (js_event_handler_.IsInitialized()) {
12192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue details;
12202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* changed_types = new base::ListValue();
12212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    details.Set("changedTypes", changed_types);
12224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
12234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ObjectIdSet id_set = invalidation_map.GetObjectIds();
122458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ModelTypeSet nudged_types = ObjectIdSetToModelTypeSet(id_set);
122558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    DCHECK(!nudged_types.Empty());
122658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for (ModelTypeSet::Iterator it = nudged_types.First();
122758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)         it.Good(); it.Inc()) {
122858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      const std::string model_type_str = ModelTypeToString(it.Get());
12292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      changed_types->Append(new base::StringValue(model_type_str));
12302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
12312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    details.SetString("source", "REMOTE_INVALIDATION");
12322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    js_event_handler_.Call(FROM_HERE,
12332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           &JsEventHandler::HandleJsEvent,
12342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           "onIncomingNotification",
12352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           JsEventDetails(&details));
12362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
12372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SyncManagerImpl::RefreshTypes(ModelTypeSet types) {
12402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(thread_checker_.CalledOnValidThread());
1241b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (types.Empty()) {
12422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(WARNING) << "Sync received refresh request with no types specified.";
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
12442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    allstatus_.IncrementNudgeCounter(NUDGE_SOURCE_LOCAL_REFRESH);
1245b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    scheduler_->ScheduleLocalRefreshRequest(
12462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        TimeDelta::FromMilliseconds(kSyncRefreshDelayMsec),
1247b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        types, FROM_HERE);
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (js_event_handler_.IsInitialized()) {
12512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue details;
12522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ListValue* changed_types = new base::ListValue();
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    details.Set("changedTypes", changed_types);
1254b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& model_type_str =
1256b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)          ModelTypeToString(it.Get());
12572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      changed_types->Append(new base::StringValue(model_type_str));
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
12592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    details.SetString("source", "LOCAL_INVALIDATION");
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    js_event_handler_.Call(FROM_HERE,
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &JsEventHandler::HandleJsEvent,
12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           "onIncomingNotification",
12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           JsEventDetails(&details));
12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncStatus SyncManagerImpl::GetDetailedStatus() const {
12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return allstatus_.status();
12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SyncManagerImpl::SaveChanges() {
12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  directory()->SaveChanges();
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UserShare* SyncManagerImpl::GetUserShare() {
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(initialized_);
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return &share_;
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string SyncManagerImpl::cache_guid() {
12812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(initialized_);
12822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return directory()->cache_guid();
12832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
12842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncManagerImpl::ReceivedExperiment(Experiments* experiments) {
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, GetUserShare());
12872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReadNode nigori_node(&trans);
12882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) {
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DVLOG(1) << "Couldn't find Nigori node.";
12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool found_experiment = false;
12932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReadNode autofill_culling_node(&trans);
12952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (autofill_culling_node.InitByClientTagLookup(
12962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          syncer::EXPERIMENTS,
12972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          syncer::kAutofillCullingTag) == BaseNode::INIT_OK &&
12982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      autofill_culling_node.GetExperimentsSpecifics().
12992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          autofill_culling().enabled()) {
13002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    experiments->autofill_culling = true;
13012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    found_experiment = true;
13022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ReadNode favicon_sync_node(&trans);
13052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (favicon_sync_node.InitByClientTagLookup(
13062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          syncer::EXPERIMENTS,
1307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          syncer::kFaviconSyncTag) == BaseNode::INIT_OK) {
1308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    experiments->favicon_sync_limit =
1309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        favicon_sync_node.GetExperimentsSpecifics().favicon_sync().
1310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            favicon_sync_limit();
13112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    found_experiment = true;
13122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
13132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1314ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  ReadNode pre_commit_update_avoidance_node(&trans);
1315ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (pre_commit_update_avoidance_node.InitByClientTagLookup(
1316ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          syncer::EXPERIMENTS,
1317ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          syncer::kPreCommitUpdateAvoidanceTag) == BaseNode::INIT_OK) {
1318ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    session_context_->set_server_enabled_pre_commit_update_avoidance(
1319ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch        pre_commit_update_avoidance_node.GetExperimentsSpecifics().
1320ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            pre_commit_update_avoidance().enabled());
1321ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // We don't bother setting found_experiment.  The frontend doesn't need to
1322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // know about this.
1323ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
1324ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return found_experiment;
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SyncManagerImpl::HasUnsyncedItems() {
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadTransaction trans(FROM_HERE, GetUserShare());
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SyncEncryptionHandler* SyncManagerImpl::GetEncryptionHandler() {
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return sync_encryption_handler_.get();
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static.
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SyncManagerImpl::GetDefaultNudgeDelay() {
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kDefaultNudgeDelayMilliseconds;
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static.
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SyncManagerImpl::GetPreferencesNudgeDelay() {
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return kPreferencesNudgeDelayMilliseconds;
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace syncer
1348