Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1473)

Unified Diff: chrome/browser/extensions/extension_service.cc

Issue 7564037: Apps/Extensions Sync refactoring -- delete most of the old glue, implement new sync API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Release build warning :-/ Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/extension_service.cc
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c2f64316ba7f11e6c16f6035067e36f1cc6b359a..cc9435e82d406aa311c490455f41b6207eb6cfb0 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -53,6 +53,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/sync/api/sync_change.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
@@ -151,6 +152,14 @@ static void ForceShutdownPlugin(const FilePath& plugin_path) {
plugin->ForceShutdown();
}
+static bool IsSyncableExtension(const Extension& extension) {
+ return extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION;
+}
+
+static bool IsSyncableApp(const Extension& extension) {
+ return extension.GetSyncType() == Extension::SYNC_TYPE_APP;
+}
+
// Manages an ExtensionInstallUI for a particular extension.
class SimpleExtensionLoadPrompt : public ExtensionInstallUI::Delegate {
public:
@@ -517,8 +526,9 @@ const Extension* ExtensionService::GetInstalledAppForRenderer(
// static
// This function is used to implement the command-line switch
-// --uninstall-extension. The LOG statements within this function are used to
-// inform the user if the uninstall cannot be done.
+// --uninstall-extension, and to uninstall an extension via sync. The LOG
+// statements within this function are used to inform the user if the uninstall
+// cannot be done.
bool ExtensionService::UninstallExtensionHelper(
ExtensionService* extensions_service,
const std::string& extension_id) {
@@ -855,6 +865,18 @@ bool ExtensionService::UninstallExtension(
return false;
}
+ // Extract the data we need for sync now, but don't actually sync until we've
+ // completed the uninstallation.
+ SyncBundle* sync_bundle = GetSyncBundleForExtension(*extension);
+
+ SyncChange sync_change;
+ if (sync_bundle) {
+ ExtensionSyncData extension_sync_data(*extension,
+ IsExtensionEnabled(extension_id),
+ IsIncognitoEnabled(extension_id));
+ sync_change = extension_sync_data.GetSyncChange(SyncChange::ACTION_DELETE);
+ }
+
UninstalledExtensionInfo uninstalled_extension_info(*extension);
UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
@@ -894,6 +916,12 @@ bool ExtensionService::UninstallExtension(
Source<Profile>(profile_),
Details<UninstalledExtensionInfo>(&uninstalled_extension_info));
+ if (sync_bundle && sync_bundle->HasExtensionId(extension_id)) {
+ sync_bundle->sync_processor->ProcessSyncChanges(
+ FROM_HERE, SyncChangeList(1, sync_change));
+ sync_bundle->synced_extensions.erase(extension_id);
+ }
+
return true;
}
@@ -952,6 +980,8 @@ void ExtensionService::EnableExtension(const std::string& extension_id) {
extension_prefs_->SetBrowserActionVisibility(extension, true);
NotifyExtensionLoaded(extension);
+
+ SyncExtensionChangeIfNeeded(*extension);
}
void ExtensionService::DisableExtension(const std::string& extension_id) {
@@ -988,6 +1018,8 @@ void ExtensionService::DisableExtension(const std::string& extension_id) {
}
NotifyExtensionUnloaded(extension, extension_misc::UNLOAD_REASON_DISABLE);
+
+ SyncExtensionChangeIfNeeded(*extension);
}
void ExtensionService::GrantPermissions(const Extension* extension) {
@@ -1620,60 +1652,224 @@ void ExtensionService::CheckForUpdatesSoon() {
}
}
-ExtensionSyncData ExtensionService::GetSyncDataHelper(
- const Extension& extension) const {
- const std::string& id = extension.id();
- ExtensionSyncData data;
- data.id = id;
- data.uninstalled = false;
- data.enabled = IsExtensionEnabled(id);
- data.incognito_enabled = IsIncognitoEnabled(id);
- data.version = *extension.version();
- data.update_url = extension.update_url();
- data.name = extension.name();
- return data;
+namespace {
+ bool IsSyncableNone(const Extension& extension) { return false; }
+} // namespace
+
+ExtensionService::SyncBundle::SyncBundle()
+ : filter(IsSyncableNone),
+ sync_processor(NULL) {
}
-bool ExtensionService::GetSyncData(
- const Extension& extension,
- ExtensionFilter filter,
- ExtensionSyncData* extension_sync_data) const {
- if (!(*filter)(extension)) {
- return false;
+ExtensionService::SyncBundle::~SyncBundle() {
+}
+
+bool ExtensionService::SyncBundle::HasExtensionId(const std::string& id) const {
+ return synced_extensions.find(id) != synced_extensions.end();
+}
+
+bool ExtensionService::SyncBundle::HasPendingExtensionId(const std::string& id)
+ const {
+ return pending_sync_data.find(id) != pending_sync_data.end();
+}
+
+void ExtensionService::SyncExtensionChangeIfNeeded(const Extension& extension) {
+ SyncBundle* sync_bundle = GetSyncBundleForExtension(extension);
+ if (sync_bundle) {
+ ExtensionSyncData extension_sync_data(extension,
+ IsExtensionEnabled(extension.id()),
+ IsIncognitoEnabled(extension.id()));
+
+ SyncChangeList sync_change_list(1, extension_sync_data.GetSyncChange(
+ sync_bundle->HasExtensionId(extension.id()) ?
+ SyncChange::ACTION_UPDATE : SyncChange::ACTION_ADD));
+ sync_bundle->sync_processor->ProcessSyncChanges(
+ FROM_HERE, sync_change_list);
+ sync_bundle->synced_extensions.insert(extension.id());
+ sync_bundle->pending_sync_data.erase(extension.id());
}
- *extension_sync_data = GetSyncDataHelper(extension);
- return true;
+}
+
+ExtensionService::SyncBundle* ExtensionService::GetSyncBundleForExtension(
+ const Extension& extension) {
+ if (app_sync_bundle_.filter(extension))
+ return &app_sync_bundle_;
+ else if (extension_sync_bundle_.filter(extension))
+ return &extension_sync_bundle_;
+ else
+ return NULL;
+}
+
+ExtensionService::SyncBundle*
+ ExtensionService::GetSyncBundleForExtensionSyncData(
+ const ExtensionSyncData& extension_sync_data) {
+ switch (extension_sync_data.type()) {
+ case Extension::SYNC_TYPE_APP:
+ return &app_sync_bundle_;
+ case Extension::SYNC_TYPE_EXTENSION:
+ return &extension_sync_bundle_;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+#define GET_SYNC_BUNDLE_FOR_MODEL_TYPE_BODY() \
+ do { \
+ switch (type) { \
+ case syncable::APPS: \
+ return &app_sync_bundle_; \
+ case syncable::EXTENSIONS: \
+ return &extension_sync_bundle_; \
+ default: \
+ NOTREACHED(); \
+ return NULL; \
+ } \
+ } while (0)
+
+const ExtensionService::SyncBundle*
+ ExtensionService::GetSyncBundleForModelTypeConst(
+ syncable::ModelType type) const {
+ GET_SYNC_BUNDLE_FOR_MODEL_TYPE_BODY();
+}
+
+ExtensionService::SyncBundle* ExtensionService::GetSyncBundleForModelType(
+ syncable::ModelType type) {
+ GET_SYNC_BUNDLE_FOR_MODEL_TYPE_BODY();
+}
+
+#undef GET_SYNC_BUNDLE_FOR_MODEL_TYPE_BODY
+
+SyncError ExtensionService::MergeDataAndStartSyncing(
+ syncable::ModelType type,
+ const SyncDataList& initial_sync_data,
+ SyncChangeProcessor* sync_processor) {
+ CHECK(sync_processor);
+
+ SyncBundle* bundle = NULL;
+
+ switch (type) {
+ case syncable::EXTENSIONS:
+ bundle = &extension_sync_bundle_;
+ bundle->filter = IsSyncableExtension;
+ break;
+
+ case syncable::APPS:
+ bundle = &app_sync_bundle_;
+ bundle->filter = IsSyncableApp;
+ break;
+
+ default:
+ LOG(FATAL) << "Got " << type << " ModelType";
+ }
+
+ bundle->sync_processor = sync_processor;
+
+ for (SyncDataList::const_iterator i = initial_sync_data.begin();
+ i != initial_sync_data.end();
+ ++i) {
+ ExtensionSyncData extension_sync_data = ExtensionSyncData(*i);
+ bundle->synced_extensions.insert(extension_sync_data.id());
+ ProcessExtensionSyncData(extension_sync_data, *bundle);
+ }
+
+ SyncDataList sync_data_list = GetAllSyncData(type);
+ SyncChangeList sync_change_list;
+ for (SyncDataList::const_iterator i = sync_data_list.begin();
+ i != sync_data_list.end();
+ ++i) {
+ if (bundle->HasExtensionId(i->GetTag()))
+ sync_change_list.push_back(SyncChange(SyncChange::ACTION_UPDATE, *i));
+ else
+ sync_change_list.push_back(SyncChange(SyncChange::ACTION_ADD, *i));
+ }
+ bundle->sync_processor->ProcessSyncChanges(FROM_HERE, sync_change_list);
+
+ return SyncError();
+}
+
+void ExtensionService::StopSyncing(syncable::ModelType type) {
+ SyncBundle* bundle = GetSyncBundleForModelType(type);
+ CHECK(bundle);
+ // This is the simplest way to clear out the bundle.
+ *bundle = SyncBundle();
+}
+
+SyncDataList ExtensionService::GetAllSyncData(syncable::ModelType type) const {
+ const SyncBundle* bundle = GetSyncBundleForModelTypeConst(type);
+ CHECK(bundle);
+ std::vector<ExtensionSyncData> extension_sync_data = GetSyncDataList(*bundle);
+ SyncDataList result(extension_sync_data.size());
+ for (int i = 0; i < static_cast<int>(extension_sync_data.size()); ++i) {
+ result[i] = extension_sync_data[i].GetSyncData();
+ }
+ return result;
+}
+
+SyncError ExtensionService::ProcessSyncChanges(
+ const tracked_objects::Location& from_here,
+ const SyncChangeList& change_list) {
+ for (SyncChangeList::const_iterator i = change_list.begin();
+ i != change_list.end();
+ ++i) {
+ ExtensionSyncData extension_sync_data = ExtensionSyncData(*i);
+ SyncBundle* bundle = GetSyncBundleForExtensionSyncData(extension_sync_data);
+ CHECK(bundle);
+
+ if (extension_sync_data.uninstalled())
+ bundle->synced_extensions.erase(extension_sync_data.id());
+ else
+ bundle->synced_extensions.insert(extension_sync_data.id());
+ ProcessExtensionSyncData(extension_sync_data, *bundle);
+ }
+
+ return SyncError();
}
void ExtensionService::GetSyncDataListHelper(
const ExtensionList& extensions,
- ExtensionFilter filter,
+ const SyncBundle& bundle,
std::vector<ExtensionSyncData>* sync_data_list) const {
for (ExtensionList::const_iterator it = extensions.begin();
it != extensions.end(); ++it) {
const Extension& extension = **it;
- if ((*filter)(extension)) {
- sync_data_list->push_back(GetSyncDataHelper(extension));
+ if (bundle.filter(extension) &&
+ // If we have pending extension data for this extension, then this
+ // version is out of date. We'll sync back the version we got from
+ // sync.
+ !bundle.HasPendingExtensionId(extension.id())) {
+ sync_data_list->push_back(
+ ExtensionSyncData(extension,
+ IsExtensionEnabled(extension.id()),
+ IsIncognitoEnabled(extension.id())));
}
}
}
std::vector<ExtensionSyncData> ExtensionService::GetSyncDataList(
- ExtensionFilter filter) const {
- std::vector<ExtensionSyncData> sync_data_list;
- GetSyncDataListHelper(extensions_, filter, &sync_data_list);
- GetSyncDataListHelper(disabled_extensions_, filter, &sync_data_list);
- GetSyncDataListHelper(terminated_extensions_, filter, &sync_data_list);
- return sync_data_list;
+ const SyncBundle& bundle) const {
+ std::vector<ExtensionSyncData> extension_sync_list;
+ GetSyncDataListHelper(extensions_, bundle, &extension_sync_list);
+ GetSyncDataListHelper(disabled_extensions_, bundle, &extension_sync_list);
+ GetSyncDataListHelper(terminated_extensions_, bundle, &extension_sync_list);
+
+ for (std::map<std::string, ExtensionSyncData>::const_iterator i =
+ bundle.pending_sync_data.begin();
+ i != bundle.pending_sync_data.end();
+ ++i) {
+ extension_sync_list.push_back(i->second);
+ }
+
+ return extension_sync_list;
}
-void ExtensionService::ProcessSyncData(
+void ExtensionService::ProcessExtensionSyncData(
const ExtensionSyncData& extension_sync_data,
- ExtensionFilter filter) {
- const std::string& id = extension_sync_data.id;
+ SyncBundle& bundle) {
+ const std::string& id = extension_sync_data.id();
// Handle uninstalls first.
- if (extension_sync_data.uninstalled) {
+ if (extension_sync_data.uninstalled()) {
std::string error;
if (!UninstallExtensionHelper(this, id)) {
LOG(WARNING) << "Could not uninstall extension " << id
@@ -1683,25 +1879,21 @@ void ExtensionService::ProcessSyncData(
}
// Set user settings.
- if (extension_sync_data.enabled) {
+ if (extension_sync_data.enabled()) {
EnableExtension(id);
} else {
DisableExtension(id);
}
- SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled);
+ SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled());
const Extension* extension = GetInstalledExtension(id);
if (extension) {
// If the extension is already installed, check if it's outdated.
- int result = extension->version()->CompareTo(extension_sync_data.version);
+ int result = extension->version()->CompareTo(extension_sync_data.version());
if (result < 0) {
// Extension is outdated.
+ bundle.pending_sync_data[extension_sync_data.id()] = extension_sync_data;
CheckForUpdatesSoon();
- } else if (result > 0) {
- // Sync version is outdated. Do nothing for now, as sync code
- // in other places will eventually update the sync data.
- //
- // TODO(akalin): Move that code here.
}
} else {
// TODO(akalin): Replace silent update with a list of enabled
@@ -1709,12 +1901,17 @@ void ExtensionService::ProcessSyncData(
const bool kInstallSilently = true;
if (!pending_extension_manager()->AddFromSync(
id,
- extension_sync_data.update_url,
- filter,
+ extension_sync_data.update_url(),
+ bundle.filter,
kInstallSilently)) {
LOG(WARNING) << "Could not add pending extension for " << id;
- return;
+ // This means that the extension is already pending installation, with a
+ // non-INTERNAL location. Add to pending_sync_data, even though it will
+ // never be removed (we'll never install a syncable version of the
+ // extension), so that GetAllSyncData() continues to send it.
}
+ // Track pending extensions so that we can return them in GetAllSyncData().
+ bundle.pending_sync_data[extension_sync_data.id()] = extension_sync_data;
CheckForUpdatesSoon();
}
}
@@ -1757,6 +1954,9 @@ void ExtensionService::SetIsIncognitoEnabled(
enabled_extension, extension_misc::UNLOAD_REASON_DISABLE);
NotifyExtensionLoaded(enabled_extension);
}
+
+ if (extension)
+ SyncExtensionChangeIfNeeded(*extension);
}
bool ExtensionService::CanCrossIncognito(const Extension* extension) {
@@ -2026,10 +2226,12 @@ void ExtensionService::AddExtension(const Extension* extension) {
chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
Source<Profile>(profile_),
Details<const Extension>(extension));
+ SyncExtensionChangeIfNeeded(*extension);
return;
}
extensions_.push_back(scoped_extension);
+ SyncExtensionChangeIfNeeded(*extension);
NotifyExtensionLoaded(extension);
}
« no previous file with comments | « chrome/browser/extensions/extension_service.h ('k') | chrome/browser/extensions/extension_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698