1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync/glue/synced_device_tracker.h" 6 7 #include "base/strings/stringprintf.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/sync/glue/device_info.h" 10 #include "sync/internal_api/public/base/model_type.h" 11 #include "sync/internal_api/public/read_node.h" 12 #include "sync/internal_api/public/read_transaction.h" 13 #include "sync/internal_api/public/user_share.h" 14 #include "sync/internal_api/public/write_node.h" 15 #include "sync/internal_api/public/write_transaction.h" 16 17 namespace browser_sync { 18 19 namespace { 20 21 // Return the DeviceInfo UNIQUE_CLIENT_TAG value for the given sync cache_guid. 22 std::string DeviceInfoLookupString(const std::string& cache_guid) { 23 return base::StringPrintf("DeviceInfo_%s", cache_guid.c_str()); 24 } 25 26 } // namespace 27 28 SyncedDeviceTracker::SyncedDeviceTracker(syncer::UserShare* user_share, 29 const std::string& cache_guid) 30 : ChangeProcessor(NULL), 31 user_share_(user_share), 32 cache_guid_(cache_guid), 33 local_device_info_tag_(DeviceInfoLookupString(cache_guid)), 34 weak_factory_(this) { 35 observers_ = new ObserverListThreadSafe<Observer>; 36 } 37 38 SyncedDeviceTracker::~SyncedDeviceTracker() { 39 } 40 41 void SyncedDeviceTracker::StartImpl(Profile* profile) { } 42 43 void SyncedDeviceTracker::ApplyChangesFromSyncModel( 44 const syncer::BaseTransaction* trans, 45 int64 model_version, 46 const syncer::ImmutableChangeRecordList& changes) { 47 // If desired, we could maintain a cache of device info. This method will be 48 // called with a transaction every time the device info is modified, so this 49 // would be the right place to update the cache. 50 } 51 52 void SyncedDeviceTracker::CommitChangesFromSyncModel() { 53 observers_->Notify(&Observer::OnDeviceInfoChange); 54 } 55 56 scoped_ptr<DeviceInfo> SyncedDeviceTracker::ReadLocalDeviceInfo() const { 57 syncer::ReadTransaction trans(FROM_HERE, user_share_); 58 return ReadLocalDeviceInfo(trans); 59 } 60 61 scoped_ptr<DeviceInfo> SyncedDeviceTracker::ReadLocalDeviceInfo( 62 const syncer::BaseTransaction& trans) const { 63 syncer::ReadNode node(&trans); 64 if (node.InitByClientTagLookup(syncer::DEVICE_INFO, local_device_info_tag_) != 65 syncer::BaseNode::INIT_OK) { 66 return scoped_ptr<DeviceInfo>(); 67 } 68 69 const sync_pb::DeviceInfoSpecifics& specifics = node.GetDeviceInfoSpecifics(); 70 return scoped_ptr<DeviceInfo> ( 71 new DeviceInfo(specifics.cache_guid(), 72 specifics.client_name(), 73 specifics.chrome_version(), 74 specifics.sync_user_agent(), 75 specifics.device_type())); 76 } 77 78 scoped_ptr<DeviceInfo> SyncedDeviceTracker::ReadDeviceInfo( 79 const std::string& client_id) const { 80 syncer::ReadTransaction trans(FROM_HERE, user_share_); 81 syncer::ReadNode node(&trans); 82 std::string lookup_string = DeviceInfoLookupString(client_id); 83 if (node.InitByClientTagLookup(syncer::DEVICE_INFO, lookup_string) != 84 syncer::BaseNode::INIT_OK) { 85 return scoped_ptr<DeviceInfo>(); 86 } 87 88 const sync_pb::DeviceInfoSpecifics& specifics = node.GetDeviceInfoSpecifics(); 89 return scoped_ptr<DeviceInfo> ( 90 new DeviceInfo(specifics.cache_guid(), 91 specifics.client_name(), 92 specifics.chrome_version(), 93 specifics.sync_user_agent(), 94 specifics.device_type())); 95 } 96 97 void SyncedDeviceTracker::GetAllSyncedDeviceInfo( 98 ScopedVector<DeviceInfo>* device_info) const { 99 if (device_info == NULL) 100 return; 101 102 device_info->clear(); 103 104 syncer::ReadTransaction trans(FROM_HERE, user_share_); 105 syncer::ReadNode root_node(&trans); 106 107 if (root_node.InitByTagLookup( 108 syncer::ModelTypeToRootTag(syncer::DEVICE_INFO)) != 109 syncer::BaseNode::INIT_OK) { 110 return; 111 } 112 113 // Get all the children of the root node and use the child id to read 114 // device info for devices. 115 std::vector<int64> children; 116 root_node.GetChildIds(&children); 117 118 for (std::vector<int64>::const_iterator it = children.begin(); 119 it != children.end(); ++it) { 120 syncer::ReadNode node(&trans); 121 if (node.InitByIdLookup(*it) != syncer::BaseNode::INIT_OK) 122 return; 123 124 const sync_pb::DeviceInfoSpecifics& specifics = 125 node.GetDeviceInfoSpecifics(); 126 device_info->push_back( 127 new DeviceInfo(specifics.cache_guid(), 128 specifics.client_name(), 129 specifics.chrome_version(), 130 specifics.sync_user_agent(), 131 specifics.device_type())); 132 133 } 134 } 135 136 std::string SyncedDeviceTracker::cache_guid() const { 137 return cache_guid_; 138 } 139 140 void SyncedDeviceTracker::AddObserver(Observer* observer) { 141 observers_->AddObserver(observer); 142 } 143 144 void SyncedDeviceTracker::RemoveObserver(Observer* observer) { 145 observers_->RemoveObserver(observer); 146 } 147 148 void SyncedDeviceTracker::InitLocalDeviceInfo(const base::Closure& callback) { 149 DeviceInfo::CreateLocalDeviceInfo( 150 cache_guid_, 151 base::Bind(&SyncedDeviceTracker::InitLocalDeviceInfoContinuation, 152 weak_factory_.GetWeakPtr(), callback)); 153 } 154 155 void SyncedDeviceTracker::InitLocalDeviceInfoContinuation( 156 const base::Closure& callback, const DeviceInfo& local_info) { 157 WriteLocalDeviceInfo(local_info); 158 callback.Run(); 159 } 160 161 void SyncedDeviceTracker::WriteLocalDeviceInfo(const DeviceInfo& info) { 162 sync_pb::DeviceInfoSpecifics specifics; 163 DCHECK_EQ(cache_guid_, info.guid()); 164 specifics.set_cache_guid(cache_guid_); 165 specifics.set_client_name(info.client_name()); 166 specifics.set_chrome_version(info.chrome_version()); 167 specifics.set_sync_user_agent(info.sync_user_agent()); 168 specifics.set_device_type(info.device_type()); 169 170 WriteDeviceInfo(specifics, local_device_info_tag_); 171 } 172 173 void SyncedDeviceTracker::WriteDeviceInfo( 174 const sync_pb::DeviceInfoSpecifics& specifics, 175 const std::string& tag) { 176 syncer::WriteTransaction trans(FROM_HERE, user_share_); 177 syncer::WriteNode node(&trans); 178 179 if (node.InitByClientTagLookup(syncer::DEVICE_INFO, tag) == 180 syncer::BaseNode::INIT_OK) { 181 node.SetDeviceInfoSpecifics(specifics); 182 node.SetTitle(UTF8ToWide(specifics.client_name())); 183 } else { 184 syncer::ReadNode type_root(&trans); 185 syncer::BaseNode::InitByLookupResult type_root_lookup_result = 186 type_root.InitByTagLookup(ModelTypeToRootTag(syncer::DEVICE_INFO)); 187 DCHECK_EQ(syncer::BaseNode::INIT_OK, type_root_lookup_result); 188 189 syncer::WriteNode new_node(&trans); 190 syncer::WriteNode::InitUniqueByCreationResult create_result = 191 new_node.InitUniqueByCreation(syncer::DEVICE_INFO, 192 type_root, 193 tag); 194 DCHECK_EQ(syncer::WriteNode::INIT_SUCCESS, create_result); 195 new_node.SetDeviceInfoSpecifics(specifics); 196 new_node.SetTitle(UTF8ToWide(specifics.client_name())); 197 } 198 } 199 200 } // namespace browser_sync 201