Home | History | Annotate | Download | only in sync_driver
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/sync_driver/device_info_sync_service.h"
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "components/sync_driver/local_device_info_provider.h"
      9 #include "sync/api/sync_change.h"
     10 #include "sync/protocol/sync.pb.h"
     11 #include "sync/util/time.h"
     12 
     13 namespace sync_driver {
     14 
     15 using syncer::ModelType;
     16 using syncer::SyncChange;
     17 using syncer::SyncChangeList;
     18 using syncer::SyncChangeProcessor;
     19 using syncer::SyncData;
     20 using syncer::SyncDataList;
     21 using syncer::SyncErrorFactory;
     22 using syncer::SyncMergeResult;
     23 
     24 DeviceInfoSyncService::DeviceInfoSyncService(
     25     LocalDeviceInfoProvider* local_device_info_provider)
     26     : local_device_backup_time_(-1),
     27       local_device_info_provider_(local_device_info_provider) {
     28   DCHECK(local_device_info_provider);
     29 }
     30 
     31 DeviceInfoSyncService::~DeviceInfoSyncService() {
     32 }
     33 
     34 SyncMergeResult DeviceInfoSyncService::MergeDataAndStartSyncing(
     35     ModelType type,
     36     const SyncDataList& initial_sync_data,
     37     scoped_ptr<SyncChangeProcessor> sync_processor,
     38     scoped_ptr<SyncErrorFactory> error_handler) {
     39   DCHECK(sync_processor.get());
     40   DCHECK(error_handler.get());
     41   DCHECK_EQ(type, syncer::DEVICE_INFO);
     42 
     43   DCHECK(all_data_.empty());
     44 
     45   sync_processor_ = sync_processor.Pass();
     46   error_handler_ = error_handler.Pass();
     47 
     48   // Initialization should be completed before this type is enabled
     49   // and local device info must be available.
     50   const DeviceInfo* local_device_info =
     51       local_device_info_provider_->GetLocalDeviceInfo();
     52   DCHECK(local_device_info != NULL);
     53 
     54   // Indicates whether a local device has been added or updated.
     55   // |change_type| defaults to ADD and might be changed to
     56   // UPDATE to INVALID down below if the initial data contains
     57   // data matching the local device ID.
     58   SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD;
     59   size_t num_items_new = 0;
     60   size_t num_items_updated = 0;
     61 
     62   // Iterate over all initial sync data and copy it to the cache.
     63   for (SyncDataList::const_iterator iter = initial_sync_data.begin();
     64        iter != initial_sync_data.end();
     65        ++iter) {
     66     DCHECK_EQ(syncer::DEVICE_INFO, iter->GetDataType());
     67 
     68     const std::string& id = iter->GetSpecifics().device_info().cache_guid();
     69 
     70     if (id == local_device_info->guid()) {
     71       // |initial_sync_data| contains data matching the local device.
     72       scoped_ptr<DeviceInfo> synced_local_device_info =
     73           make_scoped_ptr(CreateDeviceInfo(*iter));
     74 
     75       // Retrieve local device backup timestamp value from the sync data.
     76       bool has_synced_backup_time =
     77           iter->GetSpecifics().device_info().has_backup_timestamp();
     78       int64 synced_backup_time =
     79           has_synced_backup_time
     80               ? iter->GetSpecifics().device_info().backup_timestamp()
     81               : -1;
     82 
     83       // Overwrite |local_device_backup_time_| with this value if it
     84       // hasn't been set yet.
     85       if (!has_local_device_backup_time() && has_synced_backup_time) {
     86         set_local_device_backup_time(synced_backup_time);
     87       }
     88 
     89       // Store the synced device info for the local device only
     90       // it is the same as the local info. Otherwise store the local
     91       // device info and issue a change further below after finishing
     92       // processing the |initial_sync_data|.
     93       if (synced_local_device_info->Equals(*local_device_info) &&
     94           synced_backup_time == local_device_backup_time()) {
     95         change_type = SyncChange::ACTION_INVALID;
     96       } else {
     97         num_items_updated++;
     98         change_type = SyncChange::ACTION_UPDATE;
     99         continue;
    100       }
    101     } else {
    102       // A new device that doesn't match the local device.
    103       num_items_new++;
    104     }
    105 
    106     StoreSyncData(id, *iter);
    107   }
    108 
    109   syncer::SyncMergeResult result(type);
    110 
    111   // Add SyncData for the local device if it is new or different than
    112   // the synced one, and also add it to the |change_list|.
    113   if (change_type != SyncChange::ACTION_INVALID) {
    114     SyncData local_data = CreateLocalData(local_device_info);
    115     StoreSyncData(local_device_info->guid(), local_data);
    116 
    117     SyncChangeList change_list;
    118     change_list.push_back(SyncChange(FROM_HERE, change_type, local_data));
    119     result.set_error(
    120         sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
    121   }
    122 
    123   result.set_num_items_before_association(1);
    124   result.set_num_items_after_association(all_data_.size());
    125   result.set_num_items_added(num_items_new);
    126   result.set_num_items_modified(num_items_updated);
    127   result.set_num_items_deleted(0);
    128 
    129   NotifyObservers();
    130 
    131   return result;
    132 }
    133 
    134 void DeviceInfoSyncService::StopSyncing(syncer::ModelType type) {
    135   all_data_.clear();
    136   sync_processor_.reset();
    137   error_handler_.reset();
    138   clear_local_device_backup_time();
    139 }
    140 
    141 SyncDataList DeviceInfoSyncService::GetAllSyncData(
    142     syncer::ModelType type) const {
    143   SyncDataList list;
    144 
    145   for (SyncDataMap::const_iterator iter = all_data_.begin();
    146        iter != all_data_.end();
    147        ++iter) {
    148     list.push_back(iter->second);
    149   }
    150 
    151   return list;
    152 }
    153 
    154 syncer::SyncError DeviceInfoSyncService::ProcessSyncChanges(
    155     const tracked_objects::Location& from_here,
    156     const SyncChangeList& change_list) {
    157   syncer::SyncError error;
    158 
    159   DCHECK(local_device_info_provider_->GetLocalDeviceInfo());
    160   const std::string& local_device_id =
    161       local_device_info_provider_->GetLocalDeviceInfo()->guid();
    162 
    163   bool has_changes = false;
    164 
    165   // Iterate over all chanages and merge entries.
    166   for (SyncChangeList::const_iterator iter = change_list.begin();
    167        iter != change_list.end();
    168        ++iter) {
    169     const SyncData& sync_data = iter->sync_data();
    170     DCHECK_EQ(syncer::DEVICE_INFO, sync_data.GetDataType());
    171 
    172     const std::string& client_id =
    173         sync_data.GetSpecifics().device_info().cache_guid();
    174     // Ignore device info matching the local device.
    175     if (local_device_id == client_id) {
    176       DVLOG(1) << "Ignoring sync changes for the local DEVICE_INFO";
    177       continue;
    178     }
    179 
    180     if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
    181       has_changes = true;
    182       DeleteSyncData(client_id);
    183     } else if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE ||
    184                iter->change_type() == syncer::SyncChange::ACTION_ADD) {
    185       has_changes = true;
    186       StoreSyncData(client_id, sync_data);
    187     } else {
    188       error.Reset(FROM_HERE, "Invalid action received.", syncer::DEVICE_INFO);
    189     }
    190   }
    191 
    192   if (has_changes) {
    193     NotifyObservers();
    194   }
    195 
    196   return error;
    197 }
    198 
    199 scoped_ptr<DeviceInfo> DeviceInfoSyncService::GetDeviceInfo(
    200     const std::string& client_id) const {
    201   SyncDataMap::const_iterator iter = all_data_.find(client_id);
    202   if (iter == all_data_.end()) {
    203     return scoped_ptr<DeviceInfo>();
    204   }
    205 
    206   return make_scoped_ptr(CreateDeviceInfo(iter->second));
    207 }
    208 
    209 ScopedVector<DeviceInfo> DeviceInfoSyncService::GetAllDeviceInfo() const {
    210   ScopedVector<DeviceInfo> list;
    211 
    212   for (SyncDataMap::const_iterator iter = all_data_.begin();
    213        iter != all_data_.end();
    214        ++iter) {
    215     list.push_back(CreateDeviceInfo(iter->second));
    216   }
    217 
    218   return list.Pass();
    219 }
    220 
    221 void DeviceInfoSyncService::AddObserver(Observer* observer) {
    222   observers_.AddObserver(observer);
    223 }
    224 
    225 void DeviceInfoSyncService::RemoveObserver(Observer* observer) {
    226   observers_.RemoveObserver(observer);
    227 }
    228 
    229 void DeviceInfoSyncService::NotifyObservers() {
    230   FOR_EACH_OBSERVER(Observer, observers_, OnDeviceInfoChange());
    231 }
    232 
    233 void DeviceInfoSyncService::UpdateLocalDeviceBackupTime(
    234     base::Time backup_time) {
    235   set_local_device_backup_time(syncer::TimeToProtoTime(backup_time));
    236 
    237   if (sync_processor_.get()) {
    238     // Local device info must be available in advance
    239     DCHECK(local_device_info_provider_->GetLocalDeviceInfo());
    240     const std::string& local_id =
    241         local_device_info_provider_->GetLocalDeviceInfo()->guid();
    242 
    243     SyncDataMap::iterator iter = all_data_.find(local_id);
    244     DCHECK(iter != all_data_.end());
    245 
    246     syncer::SyncData& data = iter->second;
    247     if (UpdateBackupTime(&data)) {
    248       // Local device backup time has changed.
    249       // Push changes to the server via the |sync_processor_|.
    250       SyncChangeList change_list;
    251       change_list.push_back(SyncChange(
    252           FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
    253       sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
    254     }
    255   }
    256 }
    257 
    258 bool DeviceInfoSyncService::UpdateBackupTime(syncer::SyncData* sync_data) {
    259   DCHECK(has_local_device_backup_time());
    260   DCHECK(sync_data->GetSpecifics().has_device_info());
    261   const sync_pb::DeviceInfoSpecifics& source_specifics =
    262       sync_data->GetSpecifics().device_info();
    263 
    264   if (!source_specifics.has_backup_timestamp() ||
    265       source_specifics.backup_timestamp() != local_device_backup_time()) {
    266     sync_pb::EntitySpecifics entity(sync_data->GetSpecifics());
    267     entity.mutable_device_info()->set_backup_timestamp(
    268         local_device_backup_time());
    269     *sync_data = CreateLocalData(entity);
    270 
    271     return true;
    272   }
    273 
    274   return false;
    275 }
    276 
    277 base::Time DeviceInfoSyncService::GetLocalDeviceBackupTime() const {
    278   return has_local_device_backup_time()
    279              ? syncer::ProtoTimeToTime(local_device_backup_time())
    280              : base::Time();
    281 }
    282 
    283 SyncData DeviceInfoSyncService::CreateLocalData(const DeviceInfo* info) {
    284   sync_pb::EntitySpecifics entity;
    285   sync_pb::DeviceInfoSpecifics& specifics = *entity.mutable_device_info();
    286 
    287   specifics.set_cache_guid(info->guid());
    288   specifics.set_client_name(info->client_name());
    289   specifics.set_chrome_version(info->chrome_version());
    290   specifics.set_sync_user_agent(info->sync_user_agent());
    291   specifics.set_device_type(info->device_type());
    292   specifics.set_signin_scoped_device_id(info->signin_scoped_device_id());
    293 
    294   if (has_local_device_backup_time()) {
    295     specifics.set_backup_timestamp(local_device_backup_time());
    296   }
    297 
    298   return CreateLocalData(entity);
    299 }
    300 
    301 SyncData DeviceInfoSyncService::CreateLocalData(
    302     const sync_pb::EntitySpecifics& entity) {
    303   const sync_pb::DeviceInfoSpecifics& specifics = entity.device_info();
    304 
    305   std::string local_device_tag =
    306       base::StringPrintf("DeviceInfo_%s", specifics.cache_guid().c_str());
    307 
    308   return SyncData::CreateLocalData(
    309       local_device_tag, specifics.client_name(), entity);
    310 }
    311 
    312 DeviceInfo* DeviceInfoSyncService::CreateDeviceInfo(
    313     const syncer::SyncData sync_data) {
    314   const sync_pb::DeviceInfoSpecifics& specifics =
    315       sync_data.GetSpecifics().device_info();
    316 
    317   return new DeviceInfo(specifics.cache_guid(),
    318                         specifics.client_name(),
    319                         specifics.chrome_version(),
    320                         specifics.sync_user_agent(),
    321                         specifics.device_type(),
    322                         specifics.signin_scoped_device_id());
    323 }
    324 
    325 void DeviceInfoSyncService::StoreSyncData(const std::string& client_id,
    326                                           const SyncData& sync_data) {
    327   DVLOG(1) << "Storing DEVICE_INFO for "
    328            << sync_data.GetSpecifics().device_info().client_name()
    329            << " with ID " << client_id;
    330   all_data_[client_id] = sync_data;
    331 }
    332 
    333 void DeviceInfoSyncService::DeleteSyncData(const std::string& client_id) {
    334   SyncDataMap::iterator iter = all_data_.find(client_id);
    335   if (iter != all_data_.end()) {
    336     DVLOG(1) << "Deleting DEVICE_INFO for "
    337              << iter->second.GetSpecifics().device_info().client_name()
    338              << " with ID " << client_id;
    339     all_data_.erase(iter);
    340   }
    341 }
    342 
    343 }  // namespace sync_driver
    344