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() { } 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.InitTypeRoot(syncer::DEVICE_INFO) != 108 syncer::BaseNode::INIT_OK) { 109 return; 110 } 111 112 // Get all the children of the root node and use the child id to read 113 // device info for devices. 114 std::vector<int64> children; 115 root_node.GetChildIds(&children); 116 117 for (std::vector<int64>::const_iterator it = children.begin(); 118 it != children.end(); ++it) { 119 syncer::ReadNode node(&trans); 120 if (node.InitByIdLookup(*it) != syncer::BaseNode::INIT_OK) 121 return; 122 123 const sync_pb::DeviceInfoSpecifics& specifics = 124 node.GetDeviceInfoSpecifics(); 125 device_info->push_back( 126 new DeviceInfo(specifics.cache_guid(), 127 specifics.client_name(), 128 specifics.chrome_version(), 129 specifics.sync_user_agent(), 130 specifics.device_type())); 131 } 132 } 133 134 std::string SyncedDeviceTracker::cache_guid() const { 135 return cache_guid_; 136 } 137 138 void SyncedDeviceTracker::AddObserver(Observer* observer) { 139 observers_->AddObserver(observer); 140 } 141 142 void SyncedDeviceTracker::RemoveObserver(Observer* observer) { 143 observers_->RemoveObserver(observer); 144 } 145 146 void SyncedDeviceTracker::InitLocalDeviceInfo(const base::Closure& callback) { 147 DeviceInfo::CreateLocalDeviceInfo( 148 cache_guid_, 149 base::Bind(&SyncedDeviceTracker::InitLocalDeviceInfoContinuation, 150 weak_factory_.GetWeakPtr(), callback)); 151 } 152 153 void SyncedDeviceTracker::InitLocalDeviceInfoContinuation( 154 const base::Closure& callback, const DeviceInfo& local_info) { 155 WriteLocalDeviceInfo(local_info); 156 callback.Run(); 157 } 158 159 void SyncedDeviceTracker::WriteLocalDeviceInfo(const DeviceInfo& info) { 160 sync_pb::DeviceInfoSpecifics specifics; 161 DCHECK_EQ(cache_guid_, info.guid()); 162 specifics.set_cache_guid(cache_guid_); 163 specifics.set_client_name(info.client_name()); 164 specifics.set_chrome_version(info.chrome_version()); 165 specifics.set_sync_user_agent(info.sync_user_agent()); 166 specifics.set_device_type(info.device_type()); 167 168 WriteDeviceInfo(specifics, local_device_info_tag_); 169 } 170 171 void SyncedDeviceTracker::WriteDeviceInfo( 172 const sync_pb::DeviceInfoSpecifics& specifics, 173 const std::string& tag) { 174 syncer::WriteTransaction trans(FROM_HERE, user_share_); 175 syncer::WriteNode node(&trans); 176 177 if (node.InitByClientTagLookup(syncer::DEVICE_INFO, tag) == 178 syncer::BaseNode::INIT_OK) { 179 node.SetDeviceInfoSpecifics(specifics); 180 node.SetTitle(specifics.client_name()); 181 } else { 182 syncer::ReadNode type_root(&trans); 183 syncer::BaseNode::InitByLookupResult type_root_lookup_result = 184 type_root.InitTypeRoot(syncer::DEVICE_INFO); 185 DCHECK_EQ(syncer::BaseNode::INIT_OK, type_root_lookup_result); 186 187 syncer::WriteNode new_node(&trans); 188 syncer::WriteNode::InitUniqueByCreationResult create_result = 189 new_node.InitUniqueByCreation(syncer::DEVICE_INFO, 190 type_root, 191 tag); 192 DCHECK_EQ(syncer::WriteNode::INIT_SUCCESS, create_result); 193 new_node.SetDeviceInfoSpecifics(specifics); 194 new_node.SetTitle(specifics.client_name()); 195 } 196 } 197 198 } // namespace browser_sync 199