| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/sync/glue/extension_model_associator.h" | 5 #include "chrome/browser/sync/glue/extension_model_associator.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 DCHECK(!extension_data->NeedsUpdate(source)); | 48 DCHECK(!extension_data->NeedsUpdate(source)); |
| 49 } else { | 49 } else { |
| 50 extension_data->SetData(source, merge_user_properties, data); | 50 extension_data->SetData(source, merge_user_properties, data); |
| 51 } | 51 } |
| 52 return extension_data; | 52 return extension_data; |
| 53 } | 53 } |
| 54 | 54 |
| 55 void GetSyncableExtensionsClientData( | 55 void GetSyncableExtensionsClientData( |
| 56 const ExtensionList& extensions, | 56 const ExtensionList& extensions, |
| 57 ExtensionsService* extensions_service, | 57 ExtensionsService* extensions_service, |
| 58 std::set<std::string>* unsyncable_extensions, |
| 58 ExtensionDataMap* extension_data_map) { | 59 ExtensionDataMap* extension_data_map) { |
| 59 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 60 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 60 for (ExtensionList::const_iterator it = extensions.begin(); | 61 for (ExtensionList::const_iterator it = extensions.begin(); |
| 61 it != extensions.end(); ++it) { | 62 it != extensions.end(); ++it) { |
| 62 CHECK(*it); | 63 CHECK(*it); |
| 63 const Extension& extension = **it; | 64 const Extension& extension = **it; |
| 64 if (IsExtensionSyncable(extension)) { | 65 if (IsExtensionSyncable(extension)) { |
| 65 sync_pb::ExtensionSpecifics client_specifics; | 66 sync_pb::ExtensionSpecifics client_specifics; |
| 66 GetExtensionSpecifics(extension, extensions_service, | 67 GetExtensionSpecifics(extension, extensions_service, |
| 67 &client_specifics); | 68 &client_specifics); |
| 68 DcheckIsExtensionSpecificsValid(client_specifics); | 69 DcheckIsExtensionSpecificsValid(client_specifics); |
| 69 const ExtensionData& extension_data = | 70 const ExtensionData& extension_data = |
| 70 *SetOrCreateData(extension_data_map, | 71 *SetOrCreateData(extension_data_map, |
| 71 ExtensionData::CLIENT, true, client_specifics); | 72 ExtensionData::CLIENT, true, client_specifics); |
| 72 DcheckIsExtensionSpecificsValid(extension_data.merged_data()); | 73 DcheckIsExtensionSpecificsValid(extension_data.merged_data()); |
| 73 // Assumes this is called before any server data is read. | 74 // Assumes this is called before any server data is read. |
| 74 DCHECK(extension_data.NeedsUpdate(ExtensionData::SERVER)); | 75 DCHECK(extension_data.NeedsUpdate(ExtensionData::SERVER)); |
| 75 DCHECK(!extension_data.NeedsUpdate(ExtensionData::CLIENT)); | 76 DCHECK(!extension_data.NeedsUpdate(ExtensionData::CLIENT)); |
| 77 } else { |
| 78 unsyncable_extensions->insert(extension.id()); |
| 76 } | 79 } |
| 77 } | 80 } |
| 78 } | 81 } |
| 79 | 82 |
| 80 } // namespace | 83 } // namespace |
| 81 | 84 |
| 82 ExtensionModelAssociator::ExtensionModelAssociator( | 85 ExtensionModelAssociator::ExtensionModelAssociator( |
| 83 ProfileSyncService* sync_service) : sync_service_(sync_service) { | 86 ProfileSyncService* sync_service) : sync_service_(sync_service) { |
| 84 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 87 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 85 DCHECK(sync_service_); | 88 DCHECK(sync_service_); |
| 86 } | 89 } |
| 87 | 90 |
| 88 ExtensionModelAssociator::~ExtensionModelAssociator() { | 91 ExtensionModelAssociator::~ExtensionModelAssociator() { |
| 89 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 92 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 90 } | 93 } |
| 91 | 94 |
| 92 bool ExtensionModelAssociator::AssociateModels() { | 95 bool ExtensionModelAssociator::AssociateModels() { |
| 93 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 96 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 94 sync_api::WriteTransaction trans( | 97 sync_api::WriteTransaction trans( |
| 95 sync_service_->backend()->GetUserShareHandle()); | 98 sync_service_->backend()->GetUserShareHandle()); |
| 96 sync_api::ReadNode root(&trans); | 99 sync_api::ReadNode root(&trans); |
| 97 if (!root.InitByTagLookup(kExtensionsTag)) { | 100 if (!root.InitByTagLookup(kExtensionsTag)) { |
| 98 LOG(ERROR) << kNoExtensionsFolderError; | 101 LOG(ERROR) << kNoExtensionsFolderError; |
| 99 return false; | 102 return false; |
| 100 } | 103 } |
| 101 | 104 |
| 105 std::set<std::string> unsyncable_extensions; |
| 102 ExtensionDataMap extension_data_map; | 106 ExtensionDataMap extension_data_map; |
| 103 | 107 |
| 104 // Read client-side data. Do this first so server data takes | 108 // Read client-side data. Do this first so server data takes |
| 105 // precedence. | 109 // precedence. |
| 106 { | 110 { |
| 107 ExtensionsService* extensions_service = GetExtensionsService(); | 111 ExtensionsService* extensions_service = GetExtensionsService(); |
| 108 | 112 |
| 109 const ExtensionList* extensions = extensions_service->extensions(); | 113 const ExtensionList* extensions = extensions_service->extensions(); |
| 110 CHECK(extensions); | 114 CHECK(extensions); |
| 111 GetSyncableExtensionsClientData( | 115 GetSyncableExtensionsClientData( |
| 112 *extensions, extensions_service, &extension_data_map); | 116 *extensions, extensions_service, |
| 117 &unsyncable_extensions, &extension_data_map); |
| 113 | 118 |
| 114 const ExtensionList* disabled_extensions = | 119 const ExtensionList* disabled_extensions = |
| 115 extensions_service->disabled_extensions(); | 120 extensions_service->disabled_extensions(); |
| 116 CHECK(disabled_extensions); | 121 CHECK(disabled_extensions); |
| 117 GetSyncableExtensionsClientData( | 122 GetSyncableExtensionsClientData( |
| 118 *disabled_extensions, extensions_service, &extension_data_map); | 123 *disabled_extensions, extensions_service, |
| 124 &unsyncable_extensions, &extension_data_map); |
| 119 } | 125 } |
| 120 | 126 |
| 121 // Read server-side data. | 127 // Read server-side data. |
| 122 { | 128 { |
| 123 int64 id = root.GetFirstChildId(); | 129 int64 id = root.GetFirstChildId(); |
| 124 while (id != sync_api::kInvalidId) { | 130 while (id != sync_api::kInvalidId) { |
| 125 sync_api::ReadNode sync_node(&trans); | 131 sync_api::ReadNode sync_node(&trans); |
| 126 if (!sync_node.InitByIdLookup(id)) { | 132 if (!sync_node.InitByIdLookup(id)) { |
| 127 LOG(ERROR) << "Failed to fetch sync node for id " << id; | 133 LOG(ERROR) << "Failed to fetch sync node for id " << id; |
| 128 return false; | 134 return false; |
| 129 } | 135 } |
| 130 const sync_pb::ExtensionSpecifics& server_data = | 136 const sync_pb::ExtensionSpecifics& server_data = |
| 131 sync_node.GetExtensionSpecifics(); | 137 sync_node.GetExtensionSpecifics(); |
| 132 if (!IsExtensionSpecificsValid(server_data)) { | 138 if (!IsExtensionSpecificsValid(server_data)) { |
| 133 LOG(ERROR) << "Invalid extensions specifics for id " << id; | 139 LOG(ERROR) << "Invalid extensions specifics for id " << id; |
| 134 return false; | 140 return false; |
| 135 } | 141 } |
| 136 // Pass in false for merge_user_properties so client user | 142 // Don't process server data for extensions we know are |
| 137 // settings always take precedence. | 143 // unsyncable. This doesn't catch everything, as if we don't |
| 138 const ExtensionData& extension_data = | 144 // have the extension already installed we can't check, but we |
| 139 *SetOrCreateData(&extension_data_map, | 145 // also check at extension install time. |
| 140 ExtensionData::SERVER, false, server_data); | 146 if (unsyncable_extensions.find(server_data.id()) == |
| 141 DcheckIsExtensionSpecificsValid(extension_data.merged_data()); | 147 unsyncable_extensions.end()) { |
| 148 // Pass in false for merge_user_properties so client user |
| 149 // settings always take precedence. |
| 150 const ExtensionData& extension_data = |
| 151 *SetOrCreateData(&extension_data_map, |
| 152 ExtensionData::SERVER, false, server_data); |
| 153 DcheckIsExtensionSpecificsValid(extension_data.merged_data()); |
| 154 } |
| 142 id = sync_node.GetSuccessorId(); | 155 id = sync_node.GetSuccessorId(); |
| 143 } | 156 } |
| 144 } | 157 } |
| 145 | 158 |
| 146 // Update server and client as necessary. | 159 // Update server and client as necessary. |
| 147 bool should_nudge_extension_updater = false; | 160 bool should_nudge_extension_updater = false; |
| 148 for (ExtensionDataMap::iterator it = extension_data_map.begin(); | 161 for (ExtensionDataMap::iterator it = extension_data_map.begin(); |
| 149 it != extension_data_map.end(); ++it) { | 162 it != extension_data_map.end(); ++it) { |
| 150 ExtensionData* extension_data = &it->second; | 163 ExtensionData* extension_data = &it->second; |
| 151 // Update server first. | 164 // Update server first. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 } | 210 } |
| 198 | 211 |
| 199 bool ExtensionModelAssociator::OnClientUpdate(const std::string& id) { | 212 bool ExtensionModelAssociator::OnClientUpdate(const std::string& id) { |
| 200 sync_api::WriteTransaction trans( | 213 sync_api::WriteTransaction trans( |
| 201 sync_service_->backend()->GetUserShareHandle()); | 214 sync_service_->backend()->GetUserShareHandle()); |
| 202 sync_api::ReadNode root(&trans); | 215 sync_api::ReadNode root(&trans); |
| 203 if (!root.InitByTagLookup(kExtensionsTag)) { | 216 if (!root.InitByTagLookup(kExtensionsTag)) { |
| 204 LOG(ERROR) << kNoExtensionsFolderError; | 217 LOG(ERROR) << kNoExtensionsFolderError; |
| 205 return false; | 218 return false; |
| 206 } | 219 } |
| 207 | 220 ExtensionsService* extensions_service = GetExtensionsService(); |
| 208 sync_pb::ExtensionSpecifics client_data; | 221 Extension* extension = extensions_service->GetExtensionById(id, true); |
| 209 if (GetExtensionDataFromClient(id, &client_data)) { | 222 if (extension) { |
| 223 if (!IsExtensionSyncable(*extension)) { |
| 224 LOG(DFATAL) << "OnClientUpdate() called for non-syncable extension " |
| 225 << id; |
| 226 return false; |
| 227 } |
| 228 sync_pb::ExtensionSpecifics client_data; |
| 229 GetExtensionSpecifics(*extension, extensions_service, &client_data); |
| 230 DcheckIsExtensionSpecificsValid(client_data); |
| 210 ExtensionData extension_data = | 231 ExtensionData extension_data = |
| 211 ExtensionData::FromData(ExtensionData::CLIENT, client_data); | 232 ExtensionData::FromData(ExtensionData::CLIENT, client_data); |
| 212 sync_pb::ExtensionSpecifics server_data; | 233 sync_pb::ExtensionSpecifics server_data; |
| 213 if (GetExtensionDataFromServer(id, &trans, root, &server_data)) { | 234 if (GetExtensionDataFromServer(id, &trans, root, &server_data)) { |
| 214 extension_data = | 235 extension_data = |
| 215 ExtensionData::FromData(ExtensionData::SERVER, server_data); | 236 ExtensionData::FromData(ExtensionData::SERVER, server_data); |
| 216 extension_data.SetData(ExtensionData::CLIENT, true, client_data); | 237 extension_data.SetData(ExtensionData::CLIENT, true, client_data); |
| 217 } | 238 } |
| 218 if (extension_data.NeedsUpdate(ExtensionData::SERVER)) { | 239 if (extension_data.NeedsUpdate(ExtensionData::SERVER)) { |
| 219 if (!UpdateServer(&extension_data, &trans, root)) { | 240 if (!UpdateServer(&extension_data, &trans, root)) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 238 } | 259 } |
| 239 } | 260 } |
| 240 return true; | 261 return true; |
| 241 } | 262 } |
| 242 | 263 |
| 243 void ExtensionModelAssociator::OnServerUpdate( | 264 void ExtensionModelAssociator::OnServerUpdate( |
| 244 const sync_pb::ExtensionSpecifics& server_data) { | 265 const sync_pb::ExtensionSpecifics& server_data) { |
| 245 DcheckIsExtensionSpecificsValid(server_data); | 266 DcheckIsExtensionSpecificsValid(server_data); |
| 246 ExtensionData extension_data = | 267 ExtensionData extension_data = |
| 247 ExtensionData::FromData(ExtensionData::SERVER, server_data); | 268 ExtensionData::FromData(ExtensionData::SERVER, server_data); |
| 248 sync_pb::ExtensionSpecifics client_data; | 269 ExtensionsService* extensions_service = GetExtensionsService(); |
| 249 if (GetExtensionDataFromClient(server_data.id(), &client_data)) { | 270 Extension* extension = |
| 250 ExtensionData extension_data = | 271 extensions_service->GetExtensionById(server_data.id(), true); |
| 272 if (extension) { |
| 273 if (!IsExtensionSyncable(*extension)) { |
| 274 // Ignore updates for non-syncable extensions (we may get those |
| 275 // for extensions that were previously syncable). |
| 276 return; |
| 277 } |
| 278 sync_pb::ExtensionSpecifics client_data; |
| 279 GetExtensionSpecifics(*extension, extensions_service, &client_data); |
| 280 DcheckIsExtensionSpecificsValid(client_data); |
| 281 extension_data = |
| 251 ExtensionData::FromData(ExtensionData::CLIENT, client_data); | 282 ExtensionData::FromData(ExtensionData::CLIENT, client_data); |
| 252 extension_data.SetData(ExtensionData::SERVER, true, server_data); | 283 extension_data.SetData(ExtensionData::SERVER, true, server_data); |
| 253 } | 284 } |
| 254 DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER)); | 285 DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER)); |
| 255 if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) { | 286 if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) { |
| 256 TryUpdateClient(&extension_data); | 287 TryUpdateClient(&extension_data); |
| 257 if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) { | 288 if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) { |
| 258 NudgeExtensionUpdater(); | 289 NudgeExtensionUpdater(); |
| 259 } | 290 } |
| 260 } | 291 } |
| 261 DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER)); | 292 DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER)); |
| 262 } | 293 } |
| 263 | 294 |
| 264 void ExtensionModelAssociator::OnServerRemove(const std::string& id) { | 295 void ExtensionModelAssociator::OnServerRemove(const std::string& id) { |
| 265 ExtensionsService* extensions_service = GetExtensionsService(); | 296 ExtensionsService* extensions_service = GetExtensionsService(); |
| 266 Extension* extension = extensions_service->GetExtensionById(id, true); | 297 Extension* extension = extensions_service->GetExtensionById(id, true); |
| 267 if (extension) { | 298 if (extension) { |
| 268 extensions_service->UninstallExtension(id, false); | 299 if (IsExtensionSyncable(*extension)) { |
| 300 extensions_service->UninstallExtension(id, false); |
| 301 } |
| 269 } else { | 302 } else { |
| 270 LOG(ERROR) << "Trying to uninstall nonexistent extension " << id; | 303 LOG(ERROR) << "Trying to uninstall nonexistent extension " << id; |
| 271 } | 304 } |
| 272 } | 305 } |
| 273 | 306 |
| 274 ExtensionsService* ExtensionModelAssociator::GetExtensionsService() { | 307 ExtensionsService* ExtensionModelAssociator::GetExtensionsService() { |
| 275 CHECK(sync_service_); | 308 CHECK(sync_service_); |
| 276 Profile* profile = sync_service_->profile(); | 309 Profile* profile = sync_service_->profile(); |
| 277 CHECK(profile); | 310 CHECK(profile); |
| 278 ExtensionsService* extensions_service = profile->GetExtensionsService(); | 311 ExtensionsService* extensions_service = profile->GetExtensionsService(); |
| 279 CHECK(extensions_service); | 312 CHECK(extensions_service); |
| 280 return extensions_service; | 313 return extensions_service; |
| 281 } | 314 } |
| 282 | 315 |
| 283 bool ExtensionModelAssociator::GetExtensionDataFromClient( | |
| 284 const std::string& id, sync_pb::ExtensionSpecifics* client_data) { | |
| 285 ExtensionsService* extensions_service = GetExtensionsService(); | |
| 286 Extension* extension = extensions_service->GetExtensionById(id, true); | |
| 287 if (!extension) { | |
| 288 return false; | |
| 289 } | |
| 290 GetExtensionSpecifics(*extension, extensions_service, client_data); | |
| 291 DcheckIsExtensionSpecificsValid(*client_data); | |
| 292 return true; | |
| 293 } | |
| 294 | |
| 295 bool ExtensionModelAssociator::GetExtensionDataFromServer( | 316 bool ExtensionModelAssociator::GetExtensionDataFromServer( |
| 296 const std::string& id, sync_api::WriteTransaction* trans, | 317 const std::string& id, sync_api::WriteTransaction* trans, |
| 297 const sync_api::ReadNode& root, | 318 const sync_api::ReadNode& root, |
| 298 sync_pb::ExtensionSpecifics* server_data) { | 319 sync_pb::ExtensionSpecifics* server_data) { |
| 299 sync_api::ReadNode sync_node(trans); | 320 sync_api::ReadNode sync_node(trans); |
| 300 if (!sync_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) { | 321 if (!sync_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) { |
| 301 LOG(ERROR) << "Failed to fetch sync node for id " << id; | 322 LOG(ERROR) << "Failed to fetch sync node for id " << id; |
| 302 return false; | 323 return false; |
| 303 } | 324 } |
| 304 const sync_pb::ExtensionSpecifics& read_server_data = | 325 const sync_pb::ExtensionSpecifics& read_server_data = |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 ExtensionData* extension_data) { | 374 ExtensionData* extension_data) { |
| 354 DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER)); | 375 DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER)); |
| 355 DCHECK(extension_data->NeedsUpdate(ExtensionData::CLIENT)); | 376 DCHECK(extension_data->NeedsUpdate(ExtensionData::CLIENT)); |
| 356 const sync_pb::ExtensionSpecifics& specifics = | 377 const sync_pb::ExtensionSpecifics& specifics = |
| 357 extension_data->merged_data(); | 378 extension_data->merged_data(); |
| 358 DcheckIsExtensionSpecificsValid(specifics); | 379 DcheckIsExtensionSpecificsValid(specifics); |
| 359 ExtensionsService* extensions_service = GetExtensionsService(); | 380 ExtensionsService* extensions_service = GetExtensionsService(); |
| 360 const std::string& id = specifics.id(); | 381 const std::string& id = specifics.id(); |
| 361 Extension* extension = extensions_service->GetExtensionById(id, true); | 382 Extension* extension = extensions_service->GetExtensionById(id, true); |
| 362 if (extension) { | 383 if (extension) { |
| 384 if (!IsExtensionSyncable(*extension)) { |
| 385 LOG(DFATAL) << "TryUpdateClient() called for non-syncable extension " |
| 386 << extension->id(); |
| 387 return; |
| 388 } |
| 363 SetExtensionProperties(specifics, extensions_service, extension); | 389 SetExtensionProperties(specifics, extensions_service, extension); |
| 364 { | 390 { |
| 365 sync_pb::ExtensionSpecifics extension_specifics; | 391 sync_pb::ExtensionSpecifics extension_specifics; |
| 366 GetExtensionSpecifics(*extension, extensions_service, | 392 GetExtensionSpecifics(*extension, extensions_service, |
| 367 &extension_specifics); | 393 &extension_specifics); |
| 368 DCHECK(AreExtensionSpecificsUserPropertiesEqual( | 394 DCHECK(AreExtensionSpecificsUserPropertiesEqual( |
| 369 specifics, extension_specifics)) | 395 specifics, extension_specifics)) |
| 370 << ExtensionSpecificsToString(specifics) << ", " | 396 << ExtensionSpecificsToString(specifics) << ", " |
| 371 << ExtensionSpecificsToString(extension_specifics); | 397 << ExtensionSpecificsToString(extension_specifics); |
| 372 } | 398 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 391 // ExtensionsService in ProfileImpl::InitExtensions()). | 417 // ExtensionsService in ProfileImpl::InitExtensions()). |
| 392 if (extension_updater) { | 418 if (extension_updater) { |
| 393 extension_updater->CheckNow(); | 419 extension_updater->CheckNow(); |
| 394 } else { | 420 } else { |
| 395 LOG(DFATAL) << "Extension updater unexpectedly NULL; " | 421 LOG(DFATAL) << "Extension updater unexpectedly NULL; " |
| 396 << "auto-updates may be turned off"; | 422 << "auto-updates may be turned off"; |
| 397 } | 423 } |
| 398 } | 424 } |
| 399 | 425 |
| 400 } // namespace browser_sync | 426 } // namespace browser_sync |
| OLD | NEW |