1 // Copyright 2014 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.
5 #include "chrome/browser/extensions/shared_module_service.h"
10 #include "base/version.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/pending_extension_manager.h"
13 #include "extensions/browser/extension_registry.h"
14 #include "extensions/browser/extension_system.h"
15 #include "extensions/browser/uninstall_reason.h"
16 #include "extensions/common/extension.h"
17 #include "extensions/common/extension_urls.h"
19 namespace extensions {
23 typedef std::vector<SharedModuleInfo::ImportInfo> ImportInfoVector;
24 typedef std::list<SharedModuleInfo::ImportInfo> ImportInfoList;
28 SharedModuleService::SharedModuleService(content::BrowserContext* context)
29 : extension_registry_observer_(this), browser_context_(context) {
30 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
33 SharedModuleService::~SharedModuleService() {
36 SharedModuleService::ImportStatus SharedModuleService::CheckImports(
37 const Extension* extension,
38 ImportInfoList* missing_modules,
39 ImportInfoList* outdated_modules) {
41 DCHECK(missing_modules && missing_modules->empty());
42 DCHECK(outdated_modules && outdated_modules->empty());
44 ImportStatus status = IMPORT_STATUS_OK;
46 // TODO(crbug.com/420147): Code like this lives in CrxInstaller and
47 // UnpackedInstaller. If a change is made here that is important to enforce
48 // at install time, those locations need to be updated.
49 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
50 const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension);
51 for (ImportInfoVector::const_iterator iter = imports.begin();
52 iter != imports.end();
54 base::Version version_required(iter->minimum_version);
55 const Extension* imported_module =
56 registry->GetExtensionById(iter->extension_id,
57 ExtensionRegistry::EVERYTHING);
58 if (!imported_module) {
59 if (extension->from_webstore()) {
60 status = IMPORT_STATUS_UNSATISFIED;
61 missing_modules->push_back(*iter);
63 return IMPORT_STATUS_UNRECOVERABLE;
65 } else if (!SharedModuleInfo::IsSharedModule(imported_module)) {
66 return IMPORT_STATUS_UNRECOVERABLE;
67 } else if (version_required.IsValid() &&
68 imported_module->version()->CompareTo(version_required) < 0) {
69 if (imported_module->from_webstore()) {
70 outdated_modules->push_back(*iter);
71 status = IMPORT_STATUS_UNSATISFIED;
73 return IMPORT_STATUS_UNRECOVERABLE;
81 SharedModuleService::ImportStatus SharedModuleService::SatisfyImports(
82 const Extension* extension) {
83 ImportInfoList missing_modules;
84 ImportInfoList outdated_modules;
86 CheckImports(extension, &missing_modules, &outdated_modules);
88 ExtensionService* service =
89 ExtensionSystem::Get(browser_context_)->extension_service();
91 PendingExtensionManager* pending_extension_manager =
92 service->pending_extension_manager();
93 DCHECK(pending_extension_manager);
95 if (status == IMPORT_STATUS_UNSATISFIED) {
96 for (ImportInfoList::const_iterator iter = missing_modules.begin();
97 iter != missing_modules.end();
99 pending_extension_manager->AddFromExtensionImport(
101 extension_urls::GetWebstoreUpdateUrl(),
102 SharedModuleInfo::IsSharedModule);
104 service->CheckForUpdatesSoon();
109 scoped_ptr<ExtensionSet> SharedModuleService::GetDependentExtensions(
110 const Extension* extension) {
111 scoped_ptr<ExtensionSet> dependents(new ExtensionSet());
113 if (SharedModuleInfo::IsSharedModule(extension)) {
114 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
115 ExtensionService* service =
116 ExtensionSystem::Get(browser_context_)->extension_service();
118 ExtensionSet set_to_check;
119 set_to_check.InsertAll(registry->enabled_extensions());
120 set_to_check.InsertAll(registry->disabled_extensions());
121 set_to_check.InsertAll(*service->delayed_installs());
123 for (ExtensionSet::const_iterator iter = set_to_check.begin();
124 iter != set_to_check.end();
126 if (SharedModuleInfo::ImportsExtensionById(iter->get(),
128 dependents->Insert(*iter);
132 return dependents.Pass();
135 void SharedModuleService::PruneSharedModules() {
136 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
137 ExtensionService* service =
138 ExtensionSystem::Get(browser_context_)->extension_service();
140 ExtensionSet set_to_check;
141 set_to_check.InsertAll(registry->enabled_extensions());
142 set_to_check.InsertAll(registry->disabled_extensions());
143 set_to_check.InsertAll(*service->delayed_installs());
145 std::vector<std::string> shared_modules;
146 std::set<std::string> used_shared_modules;
148 for (ExtensionSet::const_iterator iter = set_to_check.begin();
149 iter != set_to_check.end();
151 if (SharedModuleInfo::IsSharedModule(iter->get()))
152 shared_modules.push_back(iter->get()->id());
154 const ImportInfoVector& imports = SharedModuleInfo::GetImports(iter->get());
155 for (ImportInfoVector::const_iterator imports_iter = imports.begin();
156 imports_iter != imports.end();
158 used_shared_modules.insert(imports_iter->extension_id);
162 std::vector<std::string>::const_iterator shared_modules_iter;
163 for (shared_modules_iter = shared_modules.begin();
164 shared_modules_iter != shared_modules.end();
165 shared_modules_iter++) {
166 if (used_shared_modules.count(*shared_modules_iter))
168 service->UninstallExtension(
169 *shared_modules_iter,
170 extensions::UNINSTALL_REASON_ORPHANED_SHARED_MODULE,
171 base::Bind(&base::DoNothing),
172 NULL); // Ignore error.
176 void SharedModuleService::OnExtensionInstalled(
177 content::BrowserContext* browser_context,
178 const Extension* extension,
181 PruneSharedModules();
184 void SharedModuleService::OnExtensionUninstalled(
185 content::BrowserContext* browser_context,
186 const Extension* extension,
187 extensions::UninstallReason reason) {
188 PruneSharedModules();
191 } // namespace extensions