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

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

Issue 14973007: Auto-install/uninstall shared module dependencies for extensions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: update checkimports logic per feedback Created 7 years, 6 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 1d03d3ab245502d3edca1b46481949929ab43d43..9865168f46021c0691375554ddb21f1311a0ec3d 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -76,6 +76,7 @@
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/extensions/background_info.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_manifest_constants.h"
#include "chrome/common/extensions/extension_messages.h"
@@ -85,6 +86,7 @@
#include "chrome/common/extensions/manifest.h"
#include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "chrome/common/extensions/manifest_handlers/shared_module_info.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "chrome/common/extensions/permissions/permissions_data.h"
#include "chrome/common/extensions/sync_helper.h"
@@ -127,6 +129,7 @@ using extensions::Manifest;
using extensions::PermissionMessage;
using extensions::PermissionMessages;
using extensions::PermissionSet;
+using extensions::SharedModuleInfo;
using extensions::UnloadedExtensionInfo;
namespace errors = extension_manifest_errors;
@@ -152,6 +155,10 @@ static const int kUpdateIdleDelay = 5;
// Wait this many seconds before trying to garbage collect extensions again.
static const int kGarbageCollectRetryDelay = 30;
+static bool IsSharedModule(const Extension* extension) {
+ return SharedModuleInfo::IsSharedModule(extension);
+}
+
} // namespace
ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
@@ -552,8 +559,6 @@ void ExtensionService::Init() {
// extension listens to onStartup and opens a window).
SetReadyAndNotifyListeners();
} else {
- // TODO(mek): It might be cleaner to do the FinishDelayedInstallInfo stuff
- // here instead of in installedloader.
if (g_browser_process->profile_manager() &&
g_browser_process->profile_manager()->will_import()) {
// Do not load any component extensions, since they may conflict with the
@@ -576,6 +581,32 @@ void ExtensionService::Init() {
GarbageCollectExtensions();
}
+ // Finish install (if possible) of extensions that were still delayed while
+ // the browser was shut down.
+ scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> delayed_info(
+ extension_prefs_->GetAllDelayedInstallInfo());
+ for (size_t i = 0; i < delayed_info->size(); ++i) {
+ ExtensionInfo* info = delayed_info->at(i).get();
+ scoped_refptr<const Extension> extension(NULL);
+ if (info->extension_manifest) {
+ std::string error;
+ extension = Extension::Create(
+ info->extension_path,
+ info->extension_location,
+ *info->extension_manifest,
+ extension_prefs_->GetDelayedInstallCreationFlags(
+ info->extension_id),
+ &error);
+ if (extension.get())
+ delayed_installs_.Insert(extension);
+ }
+ }
+ MaybeFinishDelayedInstallations();
+ scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> delayed_info2(
+ extension_prefs_->GetAllDelayedInstallInfo());
+ UMA_HISTOGRAM_COUNTS_100("Extensions.UpdateOnLoad",
+ delayed_info2->size() - delayed_info->size());
+
if (extension_prefs_->NeedsStorageGarbageCollection()) {
GarbageCollectIsolatedStorage();
extension_prefs_->SetNeedsStorageGarbageCollection(false);
@@ -701,7 +732,7 @@ void ExtensionService::ReloadExtension(const std::string& extension_id) {
path = unloaded_extension_paths_[extension_id];
}
- if (delayed_updates_for_idle_.Contains(extension_id)) {
+ if (delayed_installs_.Contains(extension_id)) {
FinishDelayedInstallation(extension_id);
return;
}
@@ -829,9 +860,10 @@ bool ExtensionService::UninstallExtension(
extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
}
- delayed_updates_for_idle_.Remove(extension_id);
delayed_installs_.Remove(extension_id);
+ PruneSharedModulesOnUninstall(extension);
+
// Track the uninstallation.
UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2);
@@ -2176,6 +2208,77 @@ void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
child_process_logging::SetActiveExtensions(extension_ids);
}
+bool ExtensionService::CheckImports(const Extension* extension) {
+ bool import_failed = false;
+ if (SharedModuleInfo::ImportsModules(extension)) {
+ const std::vector<SharedModuleInfo::ImportInfo>& imports =
+ SharedModuleInfo::GetImports(extension);
+ std::vector<SharedModuleInfo::ImportInfo>::const_iterator i;
+ for (i = imports.begin(); i != imports.end(); ++i) {
+ Version version_required(i->minimum_version);
+ const Extension* imported_module =
+ GetExtensionById(i->extension_id, true);
+ if (!imported_module) {
+ import_failed = true;
+ if (extension->from_webstore()) {
+ if (pending_extension_manager()->AddFromExtensionImport(
+ i->extension_id,
+ extension_urls::GetWebstoreUpdateUrl(),
+ IsSharedModule)) {
+ CheckForUpdatesSoon();
+ }
+ }
+ } else if (!SharedModuleInfo::IsSharedModule(imported_module)) {
+ import_failed = true;
+ } else if (version_required.IsValid() &&
+ imported_module->version()->CompareTo(version_required) < 0) {
+ import_failed = true;
+ if (imported_module->from_webstore())
+ CheckForUpdatesSoon();
+ }
+ }
+ }
+ return !import_failed;
+}
+
+scoped_ptr<const ExtensionSet>
+ ExtensionService::GetSharedModuleImporters(const Extension* extension) {
+ scoped_ptr<ExtensionSet> importers(new ExtensionSet());
+ scoped_ptr<ExtensionSet> set_to_check(new ExtensionSet());
+ if (SharedModuleInfo::IsSharedModule(extension)) {
+ set_to_check->InsertAll(disabled_extensions_);
+ set_to_check->InsertAll(delayed_installs_);
+ set_to_check->InsertAll(extensions_);
+ for (ExtensionSet::const_iterator iter = set_to_check->begin();
+ iter != set_to_check->end(); ++iter) {
+ if (SharedModuleInfo::ImportsExtensionById(*iter, extension->id())) {
+ importers->Insert(*iter);
+ }
+ }
+ }
+ return importers.PassAs<const ExtensionSet>();
+}
+
+void ExtensionService::PruneSharedModulesOnUninstall(
+ const Extension* extension) {
+ if (SharedModuleInfo::ImportsModules(extension)) {
+ const std::vector<SharedModuleInfo::ImportInfo>& imports =
+ SharedModuleInfo::GetImports(extension);
+ std::vector<SharedModuleInfo::ImportInfo>::const_iterator i;
+ for (i = imports.begin(); i != imports.end(); ++i) {
+ const Extension* imported_module =
+ GetExtensionById(i->extension_id, true);
+ if (imported_module && imported_module->from_webstore()) {
+ scoped_ptr<const ExtensionSet> importers =
+ GetSharedModuleImporters(imported_module);
Matt Perry 2013/06/12 00:58:29 Seems like all you really need is HasSharedModuleI
elijahtaylor1 2013/06/12 23:53:23 I originally had that functionality only, but then
+ if (importers->size() == 0) {
+ UninstallExtension(i->extension_id, false, NULL);
+ }
+ }
+ }
+ }
+}
+
void ExtensionService::OnExtensionInstalled(
const Extension* extension,
const syncer::StringOrdinal& page_ordinal,
@@ -2258,10 +2361,10 @@ void ExtensionService::OnExtensionInstalled(
initial_enable ? Extension::ENABLED : Extension::DISABLED;
if (ShouldDelayExtensionUpdate(id, wait_for_idle)) {
extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
- page_ordinal);
+ extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE, page_ordinal);
// Transfer ownership of |extension|.
- delayed_updates_for_idle_.Insert(extension);
+ delayed_installs_.Insert(extension);
// Notify extension of available update.
extensions::RuntimeEventRouter::DispatchOnUpdateAvailableEvent(
@@ -2275,7 +2378,12 @@ void ExtensionService::OnExtensionInstalled(
if (installs_delayed()) {
extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
- page_ordinal);
+ extensions::ExtensionPrefs::DELAY_REASON_GLOBAL, page_ordinal);
+ delayed_installs_.Insert(extension);
+ } else if (!CheckImports(extension)) {
Matt Perry 2013/06/12 00:58:29 If this fails because the imported module is not a
elijahtaylor1 2013/06/12 23:53:23 As discussed offline, I've added a TODO for messag
+ extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
+ extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IMPORTS,
+ page_ordinal);
delayed_installs_.Insert(extension);
} else {
AddNewOrUpdatedExtension(extension, initial_state, page_ordinal);
@@ -2298,13 +2406,23 @@ void ExtensionService::AddNewOrUpdatedExtension(
void ExtensionService::MaybeFinishDelayedInstallation(
const std::string& extension_id) {
- // Check if the extension already got updated.
- if (!delayed_updates_for_idle_.Contains(extension_id))
+ // Check if the extension already got installed.
+ if (!delayed_installs_.Contains(extension_id))
return;
+ extensions::ExtensionPrefs::DelayReason reason =
+ extension_prefs_->GetDelayedInstallReason(extension_id);
+
// Check if the extension is idle.
- if (!IsExtensionIdle(extension_id))
+ if (reason == extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IDLE &&
+ !IsExtensionIdle(extension_id))
return;
+ const Extension* extension = delayed_installs_.GetByID(extension_id);
+ if (reason == extensions::ExtensionPrefs::DELAY_REASON_WAIT_FOR_IMPORTS &&
+ !CheckImports(extension)) {
+ return;
+ }
+
FinishDelayedInstallation(extension_id);
}
@@ -2313,7 +2431,7 @@ void ExtensionService::FinishDelayedInstallation(
scoped_refptr<const Extension> extension(
GetPendingExtensionUpdate(extension_id));
CHECK(extension.get());
- delayed_updates_for_idle_.Remove(extension_id);
+ delayed_installs_.Remove(extension_id);
if (!extension_prefs_->FinishDelayedInstallInfo(extension_id))
NOTREACHED();
@@ -2370,11 +2488,17 @@ void ExtensionService::FinishInstallation(const Extension* extension) {
EXTERNAL_EXTENSION_INSTALLED,
EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
}
+
+ // Check extensions that may have been delayed only because this shared module
+ // was not available.
+ if (SharedModuleInfo::IsSharedModule(extension)) {
+ MaybeFinishDelayedInstallations();
+ }
}
const Extension* ExtensionService::GetPendingExtensionUpdate(
const std::string& id) const {
- return delayed_updates_for_idle_.GetByID(id);
+ return delayed_installs_.GetByID(id);
}
void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
@@ -2612,7 +2736,7 @@ void ExtensionService::Observe(int type,
extensions::ExtensionHost* host =
content::Details<extensions::ExtensionHost>(details).ptr();
std::string extension_id = host->extension_id();
- if (delayed_updates_for_idle_.Contains(extension_id)) {
+ if (delayed_installs_.Contains(extension_id)) {
// We were waiting for this extension to become idle, it now might have,
// so maybe finish installation.
base::MessageLoop::current()->PostDelayedTask(
@@ -2808,17 +2932,21 @@ void ExtensionService::GarbageCollectIsolatedStorage() {
void ExtensionService::OnGarbageCollectIsolatedStorageFinished() {
set_installs_delayed(false);
+ MaybeFinishDelayedInstallations();
+}
+
+void ExtensionService::MaybeFinishDelayedInstallations() {
+ std::vector<std::string> to_be_installed;
for (ExtensionSet::const_iterator it = delayed_installs_.begin();
it != delayed_installs_.end();
++it) {
- FinishDelayedInstallation((*it)->id());
+ to_be_installed.push_back((*it)->id());
}
- for (ExtensionSet::const_iterator it = delayed_updates_for_idle_.begin();
- it != delayed_updates_for_idle_.end();
+ for (std::vector<std::string>::const_iterator it = to_be_installed.begin();
+ it != to_be_installed.end();
++it) {
- MaybeFinishDelayedInstallation((*it)->id());
+ MaybeFinishDelayedInstallation(*it);
}
- delayed_installs_.Clear();
}
void ExtensionService::OnNeedsToGarbageCollectIsolatedStorage() {

Powered by Google App Engine
This is Rietveld 408576698