summaryrefslogtreecommitdiffstats
path: root/components/sync_driver
diff options
context:
space:
mode:
Diffstat (limited to 'components/sync_driver')
-rw-r--r--components/sync_driver/BUILD.gn8
-rw-r--r--components/sync_driver/device_info.cc113
-rw-r--r--components/sync_driver/device_info.h101
-rw-r--r--components/sync_driver/device_info_data_type_controller.cc48
-rw-r--r--components/sync_driver/device_info_data_type_controller.h40
-rw-r--r--components/sync_driver/device_info_sync_service.cc343
-rw-r--r--components/sync_driver/device_info_sync_service.h108
-rw-r--r--components/sync_driver/device_info_tracker.h40
-rw-r--r--components/sync_driver/local_device_info_provider.h50
9 files changed, 851 insertions, 0 deletions
diff --git a/components/sync_driver/BUILD.gn b/components/sync_driver/BUILD.gn
index 04dcc74..5a04237 100644
--- a/components/sync_driver/BUILD.gn
+++ b/components/sync_driver/BUILD.gn
@@ -20,10 +20,18 @@ static_library("sync_driver") {
"data_type_manager_observer.h",
"data_type_status_table.cc",
"data_type_status_table.h",
+ "device_info.cc",
+ "device_info.h",
+ "device_info_data_type_controller.cc",
+ "device_info_data_type_controller.h",
+ "device_info_sync_service.cc",
+ "device_info_sync_service.h",
+ "device_info_tracker.h",
"generic_change_processor.cc",
"generic_change_processor.h",
"generic_change_processor_factory.cc",
"generic_change_processor_factory.h",
+ "local_device_info_provider.h",
"model_association_manager.cc",
"model_association_manager.h",
"model_associator.h",
diff --git a/components/sync_driver/device_info.cc b/components/sync_driver/device_info.cc
new file mode 100644
index 0000000..c80a157
--- /dev/null
+++ b/components/sync_driver/device_info.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/values.h"
+#include "components/sync_driver/device_info.h"
+
+namespace sync_driver {
+
+DeviceInfo::DeviceInfo(const std::string& guid,
+ const std::string& client_name,
+ const std::string& chrome_version,
+ const std::string& sync_user_agent,
+ const sync_pb::SyncEnums::DeviceType device_type,
+ const std::string& signin_scoped_device_id)
+ : guid_(guid),
+ client_name_(client_name),
+ chrome_version_(chrome_version),
+ sync_user_agent_(sync_user_agent),
+ device_type_(device_type),
+ signin_scoped_device_id_(signin_scoped_device_id) {
+}
+
+DeviceInfo::~DeviceInfo() { }
+
+const std::string& DeviceInfo::guid() const {
+ return guid_;
+}
+
+const std::string& DeviceInfo::client_name() const {
+ return client_name_;
+}
+
+const std::string& DeviceInfo::chrome_version() const {
+ return chrome_version_;
+}
+
+const std::string& DeviceInfo::sync_user_agent() const {
+ return sync_user_agent_;
+}
+
+const std::string& DeviceInfo::public_id() const {
+ return public_id_;
+}
+
+sync_pb::SyncEnums::DeviceType DeviceInfo::device_type() const {
+ return device_type_;
+}
+
+const std::string& DeviceInfo::signin_scoped_device_id() const {
+ return signin_scoped_device_id_;
+}
+
+std::string DeviceInfo::GetOSString() const {
+ switch (device_type_) {
+ case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
+ return "win";
+ case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
+ return "mac";
+ case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
+ return "linux";
+ case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
+ return "chrome_os";
+ case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
+ case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
+ // TODO(lipalani): crbug.com/170375. Add support for ios
+ // phones and tablets.
+ return "android";
+ default:
+ return "unknown";
+ }
+}
+
+std::string DeviceInfo::GetDeviceTypeString() const {
+ switch (device_type_) {
+ case sync_pb::SyncEnums_DeviceType_TYPE_WIN:
+ case sync_pb::SyncEnums_DeviceType_TYPE_MAC:
+ case sync_pb::SyncEnums_DeviceType_TYPE_LINUX:
+ case sync_pb::SyncEnums_DeviceType_TYPE_CROS:
+ return "desktop_or_laptop";
+ case sync_pb::SyncEnums_DeviceType_TYPE_PHONE:
+ return "phone";
+ case sync_pb::SyncEnums_DeviceType_TYPE_TABLET:
+ return "tablet";
+ default:
+ return "unknown";
+ }
+}
+
+bool DeviceInfo::Equals(const DeviceInfo& other) const {
+ return this->guid() == other.guid() &&
+ this->client_name() == other.client_name() &&
+ this->chrome_version() == other.chrome_version() &&
+ this->sync_user_agent() == other.sync_user_agent() &&
+ this->device_type() == other.device_type() &&
+ this->signin_scoped_device_id() == other.signin_scoped_device_id();
+}
+
+base::DictionaryValue* DeviceInfo::ToValue() {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ value->SetString("name", client_name_);
+ value->SetString("id", public_id_);
+ value->SetString("os", GetOSString());
+ value->SetString("type", GetDeviceTypeString());
+ value->SetString("chromeVersion", chrome_version_);
+ return value;
+}
+
+void DeviceInfo::set_public_id(std::string id) {
+ public_id_ = id;
+}
+
+} // namespace sync_driver
diff --git a/components/sync_driver/device_info.h b/components/sync_driver/device_info.h
new file mode 100644
index 0000000..d2a8f49
--- /dev/null
+++ b/components/sync_driver/device_info.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_DRIVER_DEVICE_INFO_H_
+#define COMPONENTS_SYNC_DRIVER_DEVICE_INFO_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "sync/protocol/sync.pb.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace sync_driver {
+
+// A class that holds information regarding the properties of a device.
+class DeviceInfo {
+ public:
+ DeviceInfo(const std::string& guid,
+ const std::string& client_name,
+ const std::string& chrome_version,
+ const std::string& sync_user_agent,
+ const sync_pb::SyncEnums::DeviceType device_type,
+ const std::string& signin_scoped_device_id);
+ ~DeviceInfo();
+
+ // Sync specific unique identifier for the device. Note if a device
+ // is wiped and sync is set up again this id WILL be different.
+ // The same device might have more than 1 guid if the device has multiple
+ // accounts syncing.
+ const std::string& guid() const;
+
+ // The host name for the client.
+ const std::string& client_name() const;
+
+ // Chrome version string.
+ const std::string& chrome_version() const;
+
+ // The user agent is the combination of OS type, chrome version and which
+ // channel of chrome(stable or beta). For more information see
+ // |LocalDeviceInfoProviderImpl::MakeUserAgentForSyncApi|.
+ const std::string& sync_user_agent() const;
+
+ // Third party visible id for the device. See |public_id_| for more details.
+ const std::string& public_id() const;
+
+ // Device Type.
+ sync_pb::SyncEnums::DeviceType device_type() const;
+
+ // Device_id that is stable until user signs out. This device_id is used for
+ // annotating login scoped refresh token.
+ const std::string& signin_scoped_device_id() const;
+
+ // Gets the OS in string form.
+ std::string GetOSString() const;
+
+ // Gets the device type in string form.
+ std::string GetDeviceTypeString() const;
+
+ // Compares this object's fields with another's.
+ bool Equals(const DeviceInfo& other) const;
+
+ // Apps can set ids for a device that is meaningful to them but
+ // not unique enough so the user can be tracked. Exposing |guid|
+ // would lead to a stable unique id for a device which can potentially
+ // be used for tracking.
+ void set_public_id(std::string id);
+
+ // Converts the |DeviceInfo| values to a JS friendly DictionaryValue,
+ // which extension APIs can expose to third party apps.
+ base::DictionaryValue* ToValue();
+
+ private:
+ const std::string guid_;
+
+ const std::string client_name_;
+
+ const std::string chrome_version_;
+
+ const std::string sync_user_agent_;
+
+ const sync_pb::SyncEnums::DeviceType device_type_;
+
+ std::string signin_scoped_device_id_;
+
+ // Exposing |guid| would lead to a stable unique id for a device which
+ // can potentially be used for tracking. Public ids are privacy safe
+ // ids in that the same device will have different id for different apps
+ // and they are also reset when app/extension is uninstalled.
+ std::string public_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceInfo);
+};
+
+} // namespace sync_driver
+
+#endif // COMPONENTS_SYNC_DRIVER_DEVICE_INFO_H_
diff --git a/components/sync_driver/device_info_data_type_controller.cc b/components/sync_driver/device_info_data_type_controller.cc
new file mode 100644
index 0000000..592633d
--- /dev/null
+++ b/components/sync_driver/device_info_data_type_controller.cc
@@ -0,0 +1,48 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync_driver/device_info_data_type_controller.h"
+
+#include "base/callback.h"
+#include "components/sync_driver/local_device_info_provider.h"
+
+namespace sync_driver {
+
+DeviceInfoDataTypeController::DeviceInfoDataTypeController(
+ const scoped_refptr<base::MessageLoopProxy>& ui_thread,
+ const base::Closure& error_callback,
+ SyncApiComponentFactory* sync_factory,
+ LocalDeviceInfoProvider* local_device_info_provider)
+ : UIDataTypeController(
+ ui_thread,
+ error_callback,
+ syncer::DEVICE_INFO,
+ sync_factory),
+ local_device_info_provider_(local_device_info_provider) {
+}
+
+DeviceInfoDataTypeController::~DeviceInfoDataTypeController() {
+}
+
+bool DeviceInfoDataTypeController::StartModels() {
+ // Start the data type as soon as the local device info gets available.
+ if (local_device_info_provider_->GetLocalDeviceInfo()) {
+ return true;
+ }
+
+ subscription_ = local_device_info_provider_->RegisterOnInitializedCallback(
+ base::Bind(&DeviceInfoDataTypeController::OnLocalDeviceInfoLoaded, this));
+
+ return false;
+}
+
+void DeviceInfoDataTypeController::OnLocalDeviceInfoLoaded() {
+ DCHECK_EQ(state_, MODEL_STARTING);
+ DCHECK(local_device_info_provider_->GetLocalDeviceInfo());
+
+ subscription_.reset();
+ OnModelLoaded();
+}
+
+} // namespace sync_driver
diff --git a/components/sync_driver/device_info_data_type_controller.h b/components/sync_driver/device_info_data_type_controller.h
new file mode 100644
index 0000000..aa1b067
--- /dev/null
+++ b/components/sync_driver/device_info_data_type_controller.h
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_DRIVER_DEVICE_INFO_DATA_TYPE_CONTROLLER_H_
+#define COMPONENTS_SYNC_DRIVER_DEVICE_INFO_DATA_TYPE_CONTROLLER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "components/sync_driver/local_device_info_provider.h"
+#include "components/sync_driver/ui_data_type_controller.h"
+
+namespace sync_driver {
+
+// DataTypeController for DEVICE_INFO model type.
+class DeviceInfoDataTypeController : public UIDataTypeController {
+ public:
+ DeviceInfoDataTypeController(
+ const scoped_refptr<base::MessageLoopProxy>& ui_thread,
+ const base::Closure& error_callback,
+ SyncApiComponentFactory* sync_factory,
+ LocalDeviceInfoProvider* local_device_info_provider);
+
+ private:
+ virtual ~DeviceInfoDataTypeController();
+
+ // UIDataTypeController implementations.
+ virtual bool StartModels() OVERRIDE;
+
+ // Called by LocalDeviceInfoProvider when the local device into becomes
+ // available.
+ void OnLocalDeviceInfoLoaded();
+
+ LocalDeviceInfoProvider* const local_device_info_provider_;
+ scoped_ptr<LocalDeviceInfoProvider::Subscription> subscription_;
+ DISALLOW_COPY_AND_ASSIGN(DeviceInfoDataTypeController);
+};
+
+} // namespace sync_driver
+
+#endif // COMPONENTS_SYNC_DRIVER_DEVICE_INFO_DATA_TYPE_CONTROLLER_H_
diff --git a/components/sync_driver/device_info_sync_service.cc b/components/sync_driver/device_info_sync_service.cc
new file mode 100644
index 0000000..cdb98e1
--- /dev/null
+++ b/components/sync_driver/device_info_sync_service.cc
@@ -0,0 +1,343 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync_driver/device_info_sync_service.h"
+
+#include "base/strings/stringprintf.h"
+#include "components/sync_driver/local_device_info_provider.h"
+#include "sync/api/sync_change.h"
+#include "sync/protocol/sync.pb.h"
+#include "sync/util/time.h"
+
+namespace sync_driver {
+
+using syncer::ModelType;
+using syncer::SyncChange;
+using syncer::SyncChangeList;
+using syncer::SyncChangeProcessor;
+using syncer::SyncData;
+using syncer::SyncDataList;
+using syncer::SyncErrorFactory;
+using syncer::SyncMergeResult;
+
+DeviceInfoSyncService::DeviceInfoSyncService(
+ LocalDeviceInfoProvider* local_device_info_provider)
+ : local_device_backup_time_(-1),
+ local_device_info_provider_(local_device_info_provider) {
+ DCHECK(local_device_info_provider);
+}
+
+DeviceInfoSyncService::~DeviceInfoSyncService() {
+}
+
+SyncMergeResult DeviceInfoSyncService::MergeDataAndStartSyncing(
+ ModelType type,
+ const SyncDataList& initial_sync_data,
+ scoped_ptr<SyncChangeProcessor> sync_processor,
+ scoped_ptr<SyncErrorFactory> error_handler) {
+ DCHECK(sync_processor.get());
+ DCHECK(error_handler.get());
+ DCHECK_EQ(type, syncer::DEVICE_INFO);
+
+ DCHECK(all_data_.empty());
+
+ sync_processor_ = sync_processor.Pass();
+ error_handler_ = error_handler.Pass();
+
+ // Initialization should be completed before this type is enabled
+ // and local device info must be available.
+ const DeviceInfo* local_device_info =
+ local_device_info_provider_->GetLocalDeviceInfo();
+ DCHECK(local_device_info != NULL);
+
+ // Indicates whether a local device has been added or updated.
+ // |change_type| defaults to ADD and might be changed to
+ // UPDATE to INVALID down below if the initial data contains
+ // data matching the local device ID.
+ SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD;
+ size_t num_items_new = 0;
+ size_t num_items_updated = 0;
+
+ // Iterate over all initial sync data and copy it to the cache.
+ for (SyncDataList::const_iterator iter = initial_sync_data.begin();
+ iter != initial_sync_data.end();
+ ++iter) {
+ DCHECK_EQ(syncer::DEVICE_INFO, iter->GetDataType());
+
+ const std::string& id = iter->GetSpecifics().device_info().cache_guid();
+
+ if (id == local_device_info->guid()) {
+ // |initial_sync_data| contains data matching the local device.
+ scoped_ptr<DeviceInfo> synced_local_device_info =
+ make_scoped_ptr(CreateDeviceInfo(*iter));
+
+ // Retrieve local device backup timestamp value from the sync data.
+ bool has_synced_backup_time =
+ iter->GetSpecifics().device_info().has_backup_timestamp();
+ int64 synced_backup_time =
+ has_synced_backup_time
+ ? iter->GetSpecifics().device_info().backup_timestamp()
+ : -1;
+
+ // Overwrite |local_device_backup_time_| with this value if it
+ // hasn't been set yet.
+ if (!has_local_device_backup_time() && has_synced_backup_time) {
+ set_local_device_backup_time(synced_backup_time);
+ }
+
+ // Store the synced device info for the local device only
+ // it is the same as the local info. Otherwise store the local
+ // device info and issue a change further below after finishing
+ // processing the |initial_sync_data|.
+ if (synced_local_device_info->Equals(*local_device_info) &&
+ synced_backup_time == local_device_backup_time()) {
+ change_type = SyncChange::ACTION_INVALID;
+ } else {
+ num_items_updated++;
+ change_type = SyncChange::ACTION_UPDATE;
+ continue;
+ }
+ } else {
+ // A new device that doesn't match the local device.
+ num_items_new++;
+ }
+
+ StoreSyncData(id, *iter);
+ }
+
+ syncer::SyncMergeResult result(type);
+
+ // Add SyncData for the local device if it is new or different than
+ // the synced one, and also add it to the |change_list|.
+ if (change_type != SyncChange::ACTION_INVALID) {
+ SyncData local_data = CreateLocalData(local_device_info);
+ StoreSyncData(local_device_info->guid(), local_data);
+
+ SyncChangeList change_list;
+ change_list.push_back(SyncChange(FROM_HERE, change_type, local_data));
+ result.set_error(
+ sync_processor_->ProcessSyncChanges(FROM_HERE, change_list));
+ }
+
+ result.set_num_items_before_association(1);
+ result.set_num_items_after_association(all_data_.size());
+ result.set_num_items_added(num_items_new);
+ result.set_num_items_modified(num_items_updated);
+ result.set_num_items_deleted(0);
+
+ NotifyObservers();
+
+ return result;
+}
+
+void DeviceInfoSyncService::StopSyncing(syncer::ModelType type) {
+ all_data_.clear();
+ sync_processor_.reset();
+ error_handler_.reset();
+ clear_local_device_backup_time();
+}
+
+SyncDataList DeviceInfoSyncService::GetAllSyncData(
+ syncer::ModelType type) const {
+ SyncDataList list;
+
+ for (SyncDataMap::const_iterator iter = all_data_.begin();
+ iter != all_data_.end();
+ ++iter) {
+ list.push_back(iter->second);
+ }
+
+ return list;
+}
+
+syncer::SyncError DeviceInfoSyncService::ProcessSyncChanges(
+ const tracked_objects::Location& from_here,
+ const SyncChangeList& change_list) {
+ syncer::SyncError error;
+
+ DCHECK(local_device_info_provider_->GetLocalDeviceInfo());
+ const std::string& local_device_id =
+ local_device_info_provider_->GetLocalDeviceInfo()->guid();
+
+ bool has_changes = false;
+
+ // Iterate over all chanages and merge entries.
+ for (SyncChangeList::const_iterator iter = change_list.begin();
+ iter != change_list.end();
+ ++iter) {
+ const SyncData& sync_data = iter->sync_data();
+ DCHECK_EQ(syncer::DEVICE_INFO, sync_data.GetDataType());
+
+ const std::string& client_id =
+ sync_data.GetSpecifics().device_info().cache_guid();
+ // Ignore device info matching the local device.
+ if (local_device_id == client_id) {
+ DVLOG(1) << "Ignoring sync changes for the local DEVICE_INFO";
+ continue;
+ }
+
+ if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
+ has_changes = true;
+ DeleteSyncData(client_id);
+ } else if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE ||
+ iter->change_type() == syncer::SyncChange::ACTION_ADD) {
+ has_changes = true;
+ StoreSyncData(client_id, sync_data);
+ } else {
+ error.Reset(FROM_HERE, "Invalid action received.", syncer::DEVICE_INFO);
+ }
+ }
+
+ if (has_changes) {
+ NotifyObservers();
+ }
+
+ return error;
+}
+
+scoped_ptr<DeviceInfo> DeviceInfoSyncService::GetDeviceInfo(
+ const std::string& client_id) const {
+ SyncDataMap::const_iterator iter = all_data_.find(client_id);
+ if (iter == all_data_.end()) {
+ return scoped_ptr<DeviceInfo>();
+ }
+
+ return make_scoped_ptr(CreateDeviceInfo(iter->second));
+}
+
+ScopedVector<DeviceInfo> DeviceInfoSyncService::GetAllDeviceInfo() const {
+ ScopedVector<DeviceInfo> list;
+
+ for (SyncDataMap::const_iterator iter = all_data_.begin();
+ iter != all_data_.end();
+ ++iter) {
+ list.push_back(CreateDeviceInfo(iter->second));
+ }
+
+ return list.Pass();
+}
+
+void DeviceInfoSyncService::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void DeviceInfoSyncService::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void DeviceInfoSyncService::NotifyObservers() {
+ FOR_EACH_OBSERVER(Observer, observers_, OnDeviceInfoChange());
+}
+
+void DeviceInfoSyncService::UpdateLocalDeviceBackupTime(
+ base::Time backup_time) {
+ set_local_device_backup_time(syncer::TimeToProtoTime(backup_time));
+
+ if (sync_processor_.get()) {
+ // Local device info must be available in advance
+ DCHECK(local_device_info_provider_->GetLocalDeviceInfo());
+ const std::string& local_id =
+ local_device_info_provider_->GetLocalDeviceInfo()->guid();
+
+ SyncDataMap::iterator iter = all_data_.find(local_id);
+ DCHECK(iter != all_data_.end());
+
+ syncer::SyncData& data = iter->second;
+ if (UpdateBackupTime(&data)) {
+ // Local device backup time has changed.
+ // Push changes to the server via the |sync_processor_|.
+ SyncChangeList change_list;
+ change_list.push_back(SyncChange(
+ FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
+ sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
+ }
+ }
+}
+
+bool DeviceInfoSyncService::UpdateBackupTime(syncer::SyncData* sync_data) {
+ DCHECK(has_local_device_backup_time());
+ DCHECK(sync_data->GetSpecifics().has_device_info());
+ const sync_pb::DeviceInfoSpecifics& source_specifics =
+ sync_data->GetSpecifics().device_info();
+
+ if (!source_specifics.has_backup_timestamp() ||
+ source_specifics.backup_timestamp() != local_device_backup_time()) {
+ sync_pb::EntitySpecifics entity(sync_data->GetSpecifics());
+ entity.mutable_device_info()->set_backup_timestamp(
+ local_device_backup_time());
+ *sync_data = CreateLocalData(entity);
+
+ return true;
+ }
+
+ return false;
+}
+
+base::Time DeviceInfoSyncService::GetLocalDeviceBackupTime() const {
+ return has_local_device_backup_time()
+ ? syncer::ProtoTimeToTime(local_device_backup_time())
+ : base::Time();
+}
+
+SyncData DeviceInfoSyncService::CreateLocalData(const DeviceInfo* info) {
+ sync_pb::EntitySpecifics entity;
+ sync_pb::DeviceInfoSpecifics& specifics = *entity.mutable_device_info();
+
+ specifics.set_cache_guid(info->guid());
+ specifics.set_client_name(info->client_name());
+ specifics.set_chrome_version(info->chrome_version());
+ specifics.set_sync_user_agent(info->sync_user_agent());
+ specifics.set_device_type(info->device_type());
+ specifics.set_signin_scoped_device_id(info->signin_scoped_device_id());
+
+ if (has_local_device_backup_time()) {
+ specifics.set_backup_timestamp(local_device_backup_time());
+ }
+
+ return CreateLocalData(entity);
+}
+
+SyncData DeviceInfoSyncService::CreateLocalData(
+ const sync_pb::EntitySpecifics& entity) {
+ const sync_pb::DeviceInfoSpecifics& specifics = entity.device_info();
+
+ std::string local_device_tag =
+ base::StringPrintf("DeviceInfo_%s", specifics.cache_guid().c_str());
+
+ return SyncData::CreateLocalData(
+ local_device_tag, specifics.client_name(), entity);
+}
+
+DeviceInfo* DeviceInfoSyncService::CreateDeviceInfo(
+ const syncer::SyncData sync_data) {
+ const sync_pb::DeviceInfoSpecifics& specifics =
+ sync_data.GetSpecifics().device_info();
+
+ return new DeviceInfo(specifics.cache_guid(),
+ specifics.client_name(),
+ specifics.chrome_version(),
+ specifics.sync_user_agent(),
+ specifics.device_type(),
+ specifics.signin_scoped_device_id());
+}
+
+void DeviceInfoSyncService::StoreSyncData(const std::string& client_id,
+ const SyncData& sync_data) {
+ DVLOG(1) << "Storing DEVICE_INFO for "
+ << sync_data.GetSpecifics().device_info().client_name()
+ << " with ID " << client_id;
+ all_data_[client_id] = sync_data;
+}
+
+void DeviceInfoSyncService::DeleteSyncData(const std::string& client_id) {
+ SyncDataMap::iterator iter = all_data_.find(client_id);
+ if (iter != all_data_.end()) {
+ DVLOG(1) << "Deleting DEVICE_INFO for "
+ << iter->second.GetSpecifics().device_info().client_name()
+ << " with ID " << client_id;
+ all_data_.erase(iter);
+ }
+}
+
+} // namespace sync_driver
diff --git a/components/sync_driver/device_info_sync_service.h b/components/sync_driver/device_info_sync_service.h
new file mode 100644
index 0000000..26eb9a0
--- /dev/null
+++ b/components/sync_driver/device_info_sync_service.h
@@ -0,0 +1,108 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_DRIVER_DEVICE_INFO_SYNC_SERVICE_H_
+#define COMPONENTS_SYNC_DRIVER_DEVICE_INFO_SYNC_SERVICE_H_
+
+#include "base/observer_list.h"
+#include "components/sync_driver/device_info_tracker.h"
+#include "sync/api/sync_change_processor.h"
+#include "sync/api/sync_data.h"
+#include "sync/api/sync_error_factory.h"
+#include "sync/api/syncable_service.h"
+
+namespace sync_driver {
+
+class LocalDeviceInfoProvider;
+
+// SyncableService implementation for DEVICE_INFO model type.
+class DeviceInfoSyncService : public syncer::SyncableService,
+ public DeviceInfoTracker {
+ public:
+ explicit DeviceInfoSyncService(
+ LocalDeviceInfoProvider* local_device_info_provider);
+ virtual ~DeviceInfoSyncService();
+
+ // syncer::SyncableService implementation.
+ virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
+ syncer::ModelType type,
+ const syncer::SyncDataList& initial_sync_data,
+ scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+ scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE;
+ virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
+ virtual syncer::SyncDataList GetAllSyncData(
+ syncer::ModelType type) const OVERRIDE;
+ virtual syncer::SyncError ProcessSyncChanges(
+ const tracked_objects::Location& from_here,
+ const syncer::SyncChangeList& change_list) OVERRIDE;
+
+ // DeviceInfoTracker implementation.
+ virtual scoped_ptr<DeviceInfo> GetDeviceInfo(
+ const std::string& client_id) const OVERRIDE;
+ virtual ScopedVector<DeviceInfo> GetAllDeviceInfo() const OVERRIDE;
+ virtual void AddObserver(Observer* observer) OVERRIDE;
+ virtual void RemoveObserver(Observer* observer) OVERRIDE;
+
+ // Called to update local device backup time.
+ void UpdateLocalDeviceBackupTime(base::Time backup_time);
+ // Gets the most recently set local device backup time.
+ base::Time GetLocalDeviceBackupTime() const;
+
+ private:
+ // Create SyncData from local DeviceInfo and |local_device_backup_time_|.
+ syncer::SyncData CreateLocalData(const DeviceInfo* info);
+ // Create SyncData from EntitySpecifics.
+ static syncer::SyncData CreateLocalData(
+ const sync_pb::EntitySpecifics& entity);
+
+ // Allocate new DeviceInfo from SyncData.
+ static DeviceInfo* CreateDeviceInfo(const syncer::SyncData sync_data);
+ // Store SyncData in the cache.
+ void StoreSyncData(const std::string& client_id,
+ const syncer::SyncData& sync_data);
+ // Delete SyncData from the cache.
+ void DeleteSyncData(const std::string& client_id);
+ // Notify all registered observers.
+ void NotifyObservers();
+
+ // Updates backup time in place in |sync_data| if it is different than
+ // the one stored in |local_device_backup_time_|.
+ // Returns true if backup time was updated.
+ bool UpdateBackupTime(syncer::SyncData* sync_data);
+
+ // |local_device_backup_time_| accessors.
+ int64 local_device_backup_time() const { return local_device_backup_time_; }
+ bool has_local_device_backup_time() const {
+ return local_device_backup_time_ >= 0;
+ }
+ void set_local_device_backup_time(int64 value) {
+ local_device_backup_time_ = value;
+ }
+ void clear_local_device_backup_time() { local_device_backup_time_ = -1; }
+
+ // Local device last set backup time (in proto format).
+ // -1 if the value hasn't been specified
+ int64 local_device_backup_time_;
+
+ // |local_device_info_provider_| isn't owned.
+ const LocalDeviceInfoProvider* const local_device_info_provider_;
+
+ // Receives ownership of |sync_processor_| and |error_handler_| in
+ // MergeDataAndStartSyncing() and destroy them in StopSyncing().
+ scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
+ scoped_ptr<syncer::SyncErrorFactory> error_handler_;
+
+ // Cache of all syncable and local data.
+ typedef std::map<std::string, syncer::SyncData> SyncDataMap;
+ SyncDataMap all_data_;
+
+ // Registered observers, not owned.
+ ObserverList<Observer, true> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceInfoSyncService);
+};
+
+} // namespace sync_driver
+
+#endif // COMPONENTS_SYNC_DRIVER_DEVICE_INFO_SYNC_SERVICE_H_
diff --git a/components/sync_driver/device_info_tracker.h b/components/sync_driver/device_info_tracker.h
new file mode 100644
index 0000000..cad6e87
--- /dev/null
+++ b/components/sync_driver/device_info_tracker.h
@@ -0,0 +1,40 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_DRIVER_DEVICE_INFO_TRACKER_H_
+#define COMPONENTS_SYNC_DRIVER_DEVICE_INFO_TRACKER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "components/sync_driver/device_info.h"
+
+namespace sync_driver {
+
+// Interface for tracking synced DeviceInfo.
+class DeviceInfoTracker {
+ public:
+ virtual ~DeviceInfoTracker() {}
+
+ // Observer class for listening to device info changes.
+ class Observer {
+ public:
+ virtual void OnDeviceInfoChange() = 0;
+ };
+
+ // Gets DeviceInfo the synced device with specified client ID.
+ // Returns an empty scoped_ptr if device with the given |client_id| hasn't
+ // been synced.
+ virtual scoped_ptr<DeviceInfo> GetDeviceInfo(
+ const std::string& client_id) const = 0;
+ // Gets DeviceInfo for all synced devices (including the local one).
+ virtual ScopedVector<DeviceInfo> GetAllDeviceInfo() const = 0;
+ // Registers an observer to be called on syncing any updated DeviceInfo.
+ virtual void AddObserver(Observer* observer) = 0;
+ // Unregisters an observer.
+ virtual void RemoveObserver(Observer* observer) = 0;
+};
+
+} // namespace sync_driver
+
+#endif // COMPONENTS_SYNC_DRIVER_DEVICE_INFO_TRACKER_H_
diff --git a/components/sync_driver/local_device_info_provider.h b/components/sync_driver/local_device_info_provider.h
new file mode 100644
index 0000000..6036a7e
--- /dev/null
+++ b/components/sync_driver/local_device_info_provider.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_DRIVER_LOCAL_DEVICE_INFO_PROVIDER_H_
+#define COMPONENTS_SYNC_DRIVER_LOCAL_DEVICE_INFO_PROVIDER_H_
+
+#include <string>
+#include "base/callback_list.h"
+
+namespace sync_driver {
+
+class DeviceInfo;
+
+// Interface for providing sync specific informaiton about the
+// local device.
+class LocalDeviceInfoProvider {
+ public:
+ typedef base::CallbackList<void(void)>::Subscription Subscription;
+
+ virtual ~LocalDeviceInfoProvider() {}
+
+ // Returns sync's representation of the local device info;
+ // NULL if the device info is unavailable.
+ // The returned object is fully owned by LocalDeviceInfoProvider (must not
+ // be freed by the caller). It remains valid until LocalDeviceInfoProvider
+ // is destroyed.
+ virtual const DeviceInfo* GetLocalDeviceInfo() const = 0;
+
+ // Returns a GUID string used for creation of the machine tag for
+ // this local session; an empty sting if LocalDeviceInfoProvider hasn't been
+ // initialized yet.
+ virtual std::string GetLocalSyncCacheGUID() const = 0;
+
+ // Starts initializing local device info.
+ virtual void Initialize(
+ const std::string& cache_guid,
+ const std::string& signin_scoped_device_id) = 0;
+
+ // Registers a callback to be called when local device info becomes available.
+ // The callback will remain registered until the
+ // returned Subscription is destroyed, which must occur before the
+ // CallbackList is destroyed.
+ virtual scoped_ptr<Subscription> RegisterOnInitializedCallback(
+ const base::Closure& callback) = 0;
+};
+
+} // namespace sync_driver
+
+#endif // COMPONENTS_SYNC_DRIVER_LOCAL_DEVICE_INFO_PROVIDER_H_