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/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/version.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/pending_extension_manager.h"
15 #include "extensions/browser/extension_registry.h"
16 #include "extensions/browser/extension_system.h"
17 #include "extensions/browser/uninstall_reason.h"
18 #include "extensions/common/extension.h"
19 #include "extensions/common/extension_urls.h"
21 namespace extensions
{
25 typedef std::vector
<SharedModuleInfo::ImportInfo
> ImportInfoVector
;
26 typedef std::list
<SharedModuleInfo::ImportInfo
> ImportInfoList
;
30 SharedModuleService::SharedModuleService(content::BrowserContext
* context
)
31 : extension_registry_observer_(this), browser_context_(context
) {
32 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context_
));
35 SharedModuleService::~SharedModuleService() {
38 SharedModuleService::ImportStatus
SharedModuleService::CheckImports(
39 const Extension
* extension
,
40 ImportInfoList
* missing_modules
,
41 ImportInfoList
* outdated_modules
) {
43 DCHECK(missing_modules
&& missing_modules
->empty());
44 DCHECK(outdated_modules
&& outdated_modules
->empty());
46 ImportStatus status
= IMPORT_STATUS_OK
;
48 // TODO(crbug.com/420147): Code like this lives in CrxInstaller and
49 // UnpackedInstaller. If a change is made here that is important to enforce
50 // at install time, those locations need to be updated.
51 ExtensionRegistry
* registry
= ExtensionRegistry::Get(browser_context_
);
52 const ImportInfoVector
& imports
= SharedModuleInfo::GetImports(extension
);
53 for (ImportInfoVector::const_iterator iter
= imports
.begin();
54 iter
!= imports
.end();
56 base::Version
version_required(iter
->minimum_version
);
57 const Extension
* imported_module
=
58 registry
->GetExtensionById(iter
->extension_id
,
59 ExtensionRegistry::EVERYTHING
);
60 if (!imported_module
) {
61 if (extension
->from_webstore()) {
62 status
= IMPORT_STATUS_UNSATISFIED
;
63 missing_modules
->push_back(*iter
);
65 return IMPORT_STATUS_UNRECOVERABLE
;
67 } else if (!SharedModuleInfo::IsSharedModule(imported_module
)) {
68 return IMPORT_STATUS_UNRECOVERABLE
;
69 } else if (version_required
.IsValid() &&
70 imported_module
->version()->CompareTo(version_required
) < 0) {
71 if (imported_module
->from_webstore()) {
72 outdated_modules
->push_back(*iter
);
73 status
= IMPORT_STATUS_UNSATISFIED
;
75 return IMPORT_STATUS_UNRECOVERABLE
;
83 SharedModuleService::ImportStatus
SharedModuleService::SatisfyImports(
84 const Extension
* extension
) {
85 ImportInfoList missing_modules
;
86 ImportInfoList outdated_modules
;
88 CheckImports(extension
, &missing_modules
, &outdated_modules
);
90 ExtensionService
* service
=
91 ExtensionSystem::Get(browser_context_
)->extension_service();
93 PendingExtensionManager
* pending_extension_manager
=
94 service
->pending_extension_manager();
95 DCHECK(pending_extension_manager
);
97 if (status
== IMPORT_STATUS_UNSATISFIED
) {
98 for (ImportInfoList::const_iterator iter
= missing_modules
.begin();
99 iter
!= missing_modules
.end();
101 pending_extension_manager
->AddFromExtensionImport(
103 extension_urls::GetWebstoreUpdateUrl(),
104 SharedModuleInfo::IsSharedModule
);
106 service
->CheckForUpdatesSoon();
111 scoped_ptr
<ExtensionSet
> SharedModuleService::GetDependentExtensions(
112 const Extension
* extension
) {
113 scoped_ptr
<ExtensionSet
> dependents(new ExtensionSet());
115 if (SharedModuleInfo::IsSharedModule(extension
)) {
116 ExtensionRegistry
* registry
= ExtensionRegistry::Get(browser_context_
);
117 ExtensionService
* service
=
118 ExtensionSystem::Get(browser_context_
)->extension_service();
120 ExtensionSet set_to_check
;
121 set_to_check
.InsertAll(registry
->enabled_extensions());
122 set_to_check
.InsertAll(registry
->disabled_extensions());
123 set_to_check
.InsertAll(*service
->delayed_installs());
125 for (ExtensionSet::const_iterator iter
= set_to_check
.begin();
126 iter
!= set_to_check
.end();
128 if (SharedModuleInfo::ImportsExtensionById(iter
->get(),
130 dependents
->Insert(*iter
);
134 return dependents
.Pass();
137 void SharedModuleService::PruneSharedModules() {
138 ExtensionRegistry
* registry
= ExtensionRegistry::Get(browser_context_
);
139 ExtensionService
* service
=
140 ExtensionSystem::Get(browser_context_
)->extension_service();
142 ExtensionSet set_to_check
;
143 set_to_check
.InsertAll(registry
->enabled_extensions());
144 set_to_check
.InsertAll(registry
->disabled_extensions());
145 set_to_check
.InsertAll(*service
->delayed_installs());
147 std::vector
<std::string
> shared_modules
;
148 std::set
<std::string
> used_shared_modules
;
150 for (ExtensionSet::const_iterator iter
= set_to_check
.begin();
151 iter
!= set_to_check
.end();
153 if (SharedModuleInfo::IsSharedModule(iter
->get()))
154 shared_modules
.push_back(iter
->get()->id());
156 const ImportInfoVector
& imports
= SharedModuleInfo::GetImports(iter
->get());
157 for (ImportInfoVector::const_iterator imports_iter
= imports
.begin();
158 imports_iter
!= imports
.end();
160 used_shared_modules
.insert(imports_iter
->extension_id
);
164 std::vector
<std::string
>::const_iterator shared_modules_iter
;
165 for (shared_modules_iter
= shared_modules
.begin();
166 shared_modules_iter
!= shared_modules
.end();
167 shared_modules_iter
++) {
168 if (used_shared_modules
.count(*shared_modules_iter
))
170 service
->UninstallExtension(
171 *shared_modules_iter
,
172 extensions::UNINSTALL_REASON_ORPHANED_SHARED_MODULE
,
173 base::Bind(&base::DoNothing
),
174 NULL
); // Ignore error.
178 void SharedModuleService::OnExtensionInstalled(
179 content::BrowserContext
* browser_context
,
180 const Extension
* extension
,
183 PruneSharedModules();
186 void SharedModuleService::OnExtensionUninstalled(
187 content::BrowserContext
* browser_context
,
188 const Extension
* extension
,
189 extensions::UninstallReason reason
) {
190 PruneSharedModules();
193 } // namespace extensions