Index: chrome/browser/sync/glue/extension_model_associator.cc |
diff --git a/chrome/browser/sync/glue/extension_model_associator.cc b/chrome/browser/sync/glue/extension_model_associator.cc |
index 03374821d9de53c08cd784d0203c3a6ef8717f84..cb2890f5fd8ee3f950c86ba5a1d77e3dfa8c4eda 100644 |
--- a/chrome/browser/sync/glue/extension_model_associator.cc |
+++ b/chrome/browser/sync/glue/extension_model_associator.cc |
@@ -4,84 +4,15 @@ |
#include "chrome/browser/sync/glue/extension_model_associator.h" |
-#include <map> |
-#include <utility> |
- |
#include "base/logging.h" |
-#include "base/utf_string_conversions.h" |
-#include "chrome/browser/extensions/extension_updater.h" |
-#include "chrome/browser/extensions/extensions_service.h" |
-#include "chrome/browser/profile.h" |
-#include "chrome/browser/sync/engine/syncapi.h" |
-#include "chrome/browser/sync/glue/extension_util.h" |
-#include "chrome/browser/sync/profile_sync_service.h" |
+#include "chrome/browser/chrome_thread.h" |
+#include "chrome/browser/sync/glue/extension_data.h" |
+#include "chrome/browser/sync/glue/extension_sync_traits.h" |
+#include "chrome/browser/sync/glue/extension_sync.h" |
#include "chrome/browser/sync/protocol/extension_specifics.pb.h" |
-#include "chrome/common/extensions/extension.h" |
namespace browser_sync { |
-namespace { |
- |
-static const char kExtensionsTag[] = "google_chrome_extensions"; |
- |
-static const char kNoExtensionsFolderError[] = |
- "Server did not create the top-level extensions node. We " |
- "might be running against an out-of-date server."; |
- |
-typedef std::map<std::string, ExtensionData> ExtensionDataMap; |
- |
-ExtensionData* SetOrCreateData( |
- ExtensionDataMap* extension_data_map, |
- ExtensionData::Source source, |
- bool merge_user_properties, |
- const sync_pb::ExtensionSpecifics& data) { |
- DcheckIsExtensionSpecificsValid(data); |
- const std::string& extension_id = data.id(); |
- std::pair<ExtensionDataMap::iterator, bool> result = |
- extension_data_map->insert( |
- std::make_pair(extension_id, |
- ExtensionData::FromData(source, data))); |
- ExtensionData* extension_data = &result.first->second; |
- if (result.second) { |
- // The value was just inserted, so it shouldn't need an update |
- // from source. |
- DCHECK(!extension_data->NeedsUpdate(source)); |
- } else { |
- extension_data->SetData(source, merge_user_properties, data); |
- } |
- return extension_data; |
-} |
- |
-void GetSyncableExtensionsClientData( |
- const ExtensionList& extensions, |
- ExtensionsService* extensions_service, |
- std::set<std::string>* unsyncable_extensions, |
- ExtensionDataMap* extension_data_map) { |
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
- for (ExtensionList::const_iterator it = extensions.begin(); |
- it != extensions.end(); ++it) { |
- CHECK(*it); |
- const Extension& extension = **it; |
- if (IsExtensionSyncable(extension)) { |
- sync_pb::ExtensionSpecifics client_specifics; |
- GetExtensionSpecifics(extension, extensions_service, |
- &client_specifics); |
- DcheckIsExtensionSpecificsValid(client_specifics); |
- const ExtensionData& extension_data = |
- *SetOrCreateData(extension_data_map, |
- ExtensionData::CLIENT, true, client_specifics); |
- DcheckIsExtensionSpecificsValid(extension_data.merged_data()); |
- // Assumes this is called before any server data is read. |
- DCHECK(extension_data.NeedsUpdate(ExtensionData::SERVER)); |
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::CLIENT)); |
- } else { |
- unsyncable_extensions->insert(extension.id()); |
- } |
- } |
-} |
- |
-} // namespace |
- |
ExtensionModelAssociator::ExtensionModelAssociator( |
ProfileSyncService* sync_service) : sync_service_(sync_service) { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
@@ -94,93 +25,14 @@ ExtensionModelAssociator::~ExtensionModelAssociator() { |
bool ExtensionModelAssociator::AssociateModels() { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
- sync_api::WriteTransaction trans( |
- sync_service_->backend()->GetUserShareHandle()); |
- sync_api::ReadNode root(&trans); |
- if (!root.InitByTagLookup(kExtensionsTag)) { |
- LOG(ERROR) << kNoExtensionsFolderError; |
- return false; |
- } |
+ const ExtensionSyncTraits traits = GetExtensionSyncTraits(); |
- std::set<std::string> unsyncable_extensions; |
ExtensionDataMap extension_data_map; |
- |
- // Read client-side data. Do this first so server data takes |
- // precedence. |
- { |
- ExtensionsService* extensions_service = GetExtensionsService(); |
- |
- const ExtensionList* extensions = extensions_service->extensions(); |
- CHECK(extensions); |
- GetSyncableExtensionsClientData( |
- *extensions, extensions_service, |
- &unsyncable_extensions, &extension_data_map); |
- |
- const ExtensionList* disabled_extensions = |
- extensions_service->disabled_extensions(); |
- CHECK(disabled_extensions); |
- GetSyncableExtensionsClientData( |
- *disabled_extensions, extensions_service, |
- &unsyncable_extensions, &extension_data_map); |
- } |
- |
- // Read server-side data. |
- { |
- int64 id = root.GetFirstChildId(); |
- while (id != sync_api::kInvalidId) { |
- sync_api::ReadNode sync_node(&trans); |
- if (!sync_node.InitByIdLookup(id)) { |
- LOG(ERROR) << "Failed to fetch sync node for id " << id; |
- return false; |
- } |
- const sync_pb::ExtensionSpecifics& server_data = |
- sync_node.GetExtensionSpecifics(); |
- if (!IsExtensionSpecificsValid(server_data)) { |
- LOG(ERROR) << "Invalid extensions specifics for id " << id; |
- return false; |
- } |
- // Don't process server data for extensions we know are |
- // unsyncable. This doesn't catch everything, as if we don't |
- // have the extension already installed we can't check, but we |
- // also check at extension install time. |
- if (unsyncable_extensions.find(server_data.id()) == |
- unsyncable_extensions.end()) { |
- // Pass in false for merge_user_properties so client user |
- // settings always take precedence. |
- const ExtensionData& extension_data = |
- *SetOrCreateData(&extension_data_map, |
- ExtensionData::SERVER, false, server_data); |
- DcheckIsExtensionSpecificsValid(extension_data.merged_data()); |
- } |
- id = sync_node.GetSuccessorId(); |
- } |
- } |
- |
- // Update server and client as necessary. |
- bool should_nudge_extension_updater = false; |
- for (ExtensionDataMap::iterator it = extension_data_map.begin(); |
- it != extension_data_map.end(); ++it) { |
- ExtensionData* extension_data = &it->second; |
- // Update server first. |
- if (extension_data->NeedsUpdate(ExtensionData::SERVER)) { |
- if (!UpdateServer(extension_data, &trans, root)) { |
- LOG(ERROR) << "Could not update server data for extension " |
- << it->first; |
- return false; |
- } |
- } |
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER)); |
- if (extension_data->NeedsUpdate(ExtensionData::CLIENT)) { |
- TryUpdateClient(extension_data); |
- if (extension_data->NeedsUpdate(ExtensionData::CLIENT)) { |
- should_nudge_extension_updater = true; |
- } |
- } |
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER)); |
+ if (!SlurpExtensionData(traits, sync_service_, &extension_data_map)) { |
+ return false; |
} |
- |
- if (should_nudge_extension_updater) { |
- NudgeExtensionUpdater(); |
+ if (!FlushExtensionData(traits, extension_data_map, sync_service_)) { |
+ return false; |
} |
return true; |
@@ -194,233 +46,8 @@ bool ExtensionModelAssociator::DisassociateModels() { |
bool ExtensionModelAssociator::SyncModelHasUserCreatedNodes(bool* has_nodes) { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
- CHECK(has_nodes); |
- *has_nodes = false; |
- sync_api::ReadTransaction trans( |
- sync_service_->backend()->GetUserShareHandle()); |
- sync_api::ReadNode root(&trans); |
- if (!root.InitByTagLookup(kExtensionsTag)) { |
- LOG(ERROR) << kNoExtensionsFolderError; |
- return false; |
- } |
- // The sync model has user created nodes iff the extensions folder has |
- // any children. |
- *has_nodes = root.GetFirstChildId() != sync_api::kInvalidId; |
- return true; |
-} |
- |
-bool ExtensionModelAssociator::OnClientUpdate(const std::string& id) { |
- sync_api::WriteTransaction trans( |
- sync_service_->backend()->GetUserShareHandle()); |
- sync_api::ReadNode root(&trans); |
- if (!root.InitByTagLookup(kExtensionsTag)) { |
- LOG(ERROR) << kNoExtensionsFolderError; |
- return false; |
- } |
- ExtensionsService* extensions_service = GetExtensionsService(); |
- Extension* extension = extensions_service->GetExtensionById(id, true); |
- if (extension) { |
- if (!IsExtensionSyncable(*extension)) { |
- LOG(DFATAL) << "OnClientUpdate() called for non-syncable extension " |
- << id; |
- return false; |
- } |
- sync_pb::ExtensionSpecifics client_data; |
- GetExtensionSpecifics(*extension, extensions_service, &client_data); |
- DcheckIsExtensionSpecificsValid(client_data); |
- ExtensionData extension_data = |
- ExtensionData::FromData(ExtensionData::CLIENT, client_data); |
- sync_pb::ExtensionSpecifics server_data; |
- if (GetExtensionDataFromServer(id, &trans, root, &server_data)) { |
- extension_data = |
- ExtensionData::FromData(ExtensionData::SERVER, server_data); |
- extension_data.SetData(ExtensionData::CLIENT, true, client_data); |
- } |
- if (extension_data.NeedsUpdate(ExtensionData::SERVER)) { |
- if (!UpdateServer(&extension_data, &trans, root)) { |
- LOG(ERROR) << "Could not update server data for extension " << id; |
- return false; |
- } |
- } |
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER)); |
- // Client may still need updating, e.g. if we disable an extension |
- // while it's being auto-updated. If so, then we'll be called |
- // again once the auto-update is finished. |
- // |
- // TODO(akalin): Figure out a way to tell when the above happens, |
- // so we know exactly what NeedsUpdate(CLIENT) should return. |
- } else { |
- sync_api::WriteNode write_node(&trans); |
- if (write_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) { |
- write_node.Remove(); |
- } else { |
- LOG(ERROR) << "Trying to remove server data for " |
- << "nonexistent extension " << id; |
- } |
- } |
- return true; |
-} |
- |
-void ExtensionModelAssociator::OnServerUpdate( |
- const sync_pb::ExtensionSpecifics& server_data) { |
- DcheckIsExtensionSpecificsValid(server_data); |
- ExtensionData extension_data = |
- ExtensionData::FromData(ExtensionData::SERVER, server_data); |
- ExtensionsService* extensions_service = GetExtensionsService(); |
- Extension* extension = |
- extensions_service->GetExtensionById(server_data.id(), true); |
- if (extension) { |
- if (!IsExtensionSyncable(*extension)) { |
- // Ignore updates for non-syncable extensions (we may get those |
- // for extensions that were previously syncable). |
- return; |
- } |
- sync_pb::ExtensionSpecifics client_data; |
- GetExtensionSpecifics(*extension, extensions_service, &client_data); |
- DcheckIsExtensionSpecificsValid(client_data); |
- extension_data = |
- ExtensionData::FromData(ExtensionData::CLIENT, client_data); |
- extension_data.SetData(ExtensionData::SERVER, true, server_data); |
- } |
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER)); |
- if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) { |
- TryUpdateClient(&extension_data); |
- if (extension_data.NeedsUpdate(ExtensionData::CLIENT)) { |
- NudgeExtensionUpdater(); |
- } |
- } |
- DCHECK(!extension_data.NeedsUpdate(ExtensionData::SERVER)); |
-} |
- |
-void ExtensionModelAssociator::OnServerRemove(const std::string& id) { |
- ExtensionsService* extensions_service = GetExtensionsService(); |
- Extension* extension = extensions_service->GetExtensionById(id, true); |
- if (extension) { |
- if (IsExtensionSyncable(*extension)) { |
- extensions_service->UninstallExtension(id, false); |
- } |
- } else { |
- LOG(ERROR) << "Trying to uninstall nonexistent extension " << id; |
- } |
-} |
- |
-ExtensionsService* ExtensionModelAssociator::GetExtensionsService() { |
- CHECK(sync_service_); |
- Profile* profile = sync_service_->profile(); |
- CHECK(profile); |
- ExtensionsService* extensions_service = profile->GetExtensionsService(); |
- CHECK(extensions_service); |
- return extensions_service; |
-} |
- |
-bool ExtensionModelAssociator::GetExtensionDataFromServer( |
- const std::string& id, sync_api::WriteTransaction* trans, |
- const sync_api::ReadNode& root, |
- sync_pb::ExtensionSpecifics* server_data) { |
- sync_api::ReadNode sync_node(trans); |
- if (!sync_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) { |
- LOG(ERROR) << "Failed to fetch sync node for id " << id; |
- return false; |
- } |
- const sync_pb::ExtensionSpecifics& read_server_data = |
- sync_node.GetExtensionSpecifics(); |
- if (!IsExtensionSpecificsValid(read_server_data)) { |
- LOG(ERROR) << "Invalid extensions specifics for id " << id; |
- return false; |
- } |
- *server_data = read_server_data; |
- return true; |
-} |
- |
-namespace { |
- |
-void SetNodeData(const sync_pb::ExtensionSpecifics& specifics, |
- sync_api::WriteNode* node) { |
- node->SetTitle(UTF8ToWide(specifics.name())); |
- node->SetExtensionSpecifics(specifics); |
-} |
- |
-} // namespace |
- |
-bool ExtensionModelAssociator::UpdateServer( |
- ExtensionData* extension_data, |
- sync_api::WriteTransaction* trans, |
- const sync_api::ReadNode& root) { |
- DCHECK(extension_data->NeedsUpdate(ExtensionData::SERVER)); |
- const sync_pb::ExtensionSpecifics& specifics = |
- extension_data->merged_data(); |
- const std::string& id = specifics.id(); |
- sync_api::WriteNode write_node(trans); |
- if (write_node.InitByClientTagLookup(syncable::EXTENSIONS, id)) { |
- SetNodeData(specifics, &write_node); |
- } else { |
- sync_api::WriteNode create_node(trans); |
- if (!create_node.InitUniqueByCreation(syncable::EXTENSIONS, root, id)) { |
- LOG(ERROR) << "Could not create node for extension " << id; |
- return false; |
- } |
- SetNodeData(specifics, &create_node); |
- } |
- bool old_client_needs_update = |
- extension_data->NeedsUpdate(ExtensionData::CLIENT); |
- extension_data->ResolveData(ExtensionData::SERVER); |
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER)); |
- DCHECK_EQ(extension_data->NeedsUpdate(ExtensionData::CLIENT), |
- old_client_needs_update); |
- return true; |
-} |
- |
-void ExtensionModelAssociator::TryUpdateClient( |
- ExtensionData* extension_data) { |
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER)); |
- DCHECK(extension_data->NeedsUpdate(ExtensionData::CLIENT)); |
- const sync_pb::ExtensionSpecifics& specifics = |
- extension_data->merged_data(); |
- DcheckIsExtensionSpecificsValid(specifics); |
- ExtensionsService* extensions_service = GetExtensionsService(); |
- const std::string& id = specifics.id(); |
- Extension* extension = extensions_service->GetExtensionById(id, true); |
- if (extension) { |
- if (!IsExtensionSyncable(*extension)) { |
- LOG(DFATAL) << "TryUpdateClient() called for non-syncable extension " |
- << extension->id(); |
- return; |
- } |
- SetExtensionProperties(specifics, extensions_service, extension); |
- { |
- sync_pb::ExtensionSpecifics extension_specifics; |
- GetExtensionSpecifics(*extension, extensions_service, |
- &extension_specifics); |
- DCHECK(AreExtensionSpecificsUserPropertiesEqual( |
- specifics, extension_specifics)) |
- << ExtensionSpecificsToString(specifics) << ", " |
- << ExtensionSpecificsToString(extension_specifics); |
- } |
- if (!IsExtensionOutdated(*extension, specifics)) { |
- extension_data->ResolveData(ExtensionData::CLIENT); |
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::CLIENT)); |
- } |
- } else { |
- GURL update_url(specifics.update_url()); |
- // TODO(akalin): Replace silent update with a list of enabled |
- // permissions. |
- extensions_service->AddPendingExtension( |
- id, update_url, false, true, |
- specifics.enabled(), specifics.incognito_enabled()); |
- } |
- DCHECK(!extension_data->NeedsUpdate(ExtensionData::SERVER)); |
-} |
- |
-void ExtensionModelAssociator::NudgeExtensionUpdater() { |
- ExtensionUpdater* extension_updater = GetExtensionsService()->updater(); |
- // Auto-updates should now be on always (see the construction of the |
- // ExtensionsService in ProfileImpl::InitExtensions()). |
- if (extension_updater) { |
- extension_updater->CheckNow(); |
- } else { |
- LOG(DFATAL) << "Extension updater unexpectedly NULL; " |
- << "auto-updates may be turned off"; |
- } |
+ const ExtensionSyncTraits traits = GetExtensionSyncTraits(); |
+ return RootNodeHasChildren(traits.root_node_tag, sync_service_, has_nodes); |
} |
} // namespace browser_sync |