shared_module_service.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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.
4
5#include "chrome/browser/extensions/shared_module_service.h"
6
7#include <set>
8#include <vector>
9
10#include "base/version.h"
11#include "chrome/browser/extensions/extension_service.h"
12#include "chrome/browser/extensions/pending_extension_manager.h"
13#include "chrome/common/extensions/extension_constants.h"
14#include "extensions/browser/extension_registry.h"
15#include "extensions/browser/extension_system.h"
16#include "extensions/browser/uninstall_reason.h"
17#include "extensions/common/extension.h"
18
19namespace extensions {
20
21namespace {
22
23typedef std::vector<SharedModuleInfo::ImportInfo> ImportInfoVector;
24typedef std::list<SharedModuleInfo::ImportInfo> ImportInfoList;
25
26}  // namespace
27
28SharedModuleService::SharedModuleService(content::BrowserContext* context)
29    : extension_registry_observer_(this), browser_context_(context) {
30  extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
31}
32
33SharedModuleService::~SharedModuleService() {
34}
35
36SharedModuleService::ImportStatus SharedModuleService::CheckImports(
37    const Extension* extension,
38    ImportInfoList* missing_modules,
39    ImportInfoList* outdated_modules) {
40  DCHECK(extension);
41  DCHECK(missing_modules && missing_modules->empty());
42  DCHECK(outdated_modules && outdated_modules->empty());
43
44  ImportStatus status = IMPORT_STATUS_OK;
45
46  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
47  const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension);
48  for (ImportInfoVector::const_iterator iter = imports.begin();
49       iter != imports.end();
50       ++iter) {
51    base::Version version_required(iter->minimum_version);
52    const Extension* imported_module =
53        registry->GetExtensionById(iter->extension_id,
54                                   ExtensionRegistry::EVERYTHING);
55    if (!imported_module) {
56      if (extension->from_webstore()) {
57        status = IMPORT_STATUS_UNSATISFIED;
58        missing_modules->push_back(*iter);
59      } else {
60        return IMPORT_STATUS_UNRECOVERABLE;
61      }
62    } else if (!SharedModuleInfo::IsSharedModule(imported_module)) {
63      return IMPORT_STATUS_UNRECOVERABLE;
64    } else if (!SharedModuleInfo::IsExportAllowedByWhitelist(imported_module,
65                                                             extension->id())) {
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;
72      } else {
73        return IMPORT_STATUS_UNRECOVERABLE;
74      }
75    }
76  }
77
78  return status;
79}
80
81SharedModuleService::ImportStatus SharedModuleService::SatisfyImports(
82    const Extension* extension) {
83  ImportInfoList missing_modules;
84  ImportInfoList outdated_modules;
85  ImportStatus status =
86      CheckImports(extension, &missing_modules, &outdated_modules);
87
88  ExtensionService* service =
89      ExtensionSystem::Get(browser_context_)->extension_service();
90
91  PendingExtensionManager* pending_extension_manager =
92      service->pending_extension_manager();
93  DCHECK(pending_extension_manager);
94
95  if (status == IMPORT_STATUS_UNSATISFIED) {
96    for (ImportInfoList::const_iterator iter = missing_modules.begin();
97         iter != missing_modules.end();
98         ++iter) {
99      pending_extension_manager->AddFromExtensionImport(
100          iter->extension_id,
101          extension_urls::GetWebstoreUpdateUrl(),
102          SharedModuleInfo::IsSharedModule);
103    }
104    service->CheckForUpdatesSoon();
105  }
106  return status;
107}
108
109scoped_ptr<ExtensionSet> SharedModuleService::GetDependentExtensions(
110    const Extension* extension) {
111  scoped_ptr<ExtensionSet> dependents(new ExtensionSet());
112
113  if (SharedModuleInfo::IsSharedModule(extension)) {
114    ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
115    ExtensionService* service =
116        ExtensionSystem::Get(browser_context_)->extension_service();
117
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());
122
123    for (ExtensionSet::const_iterator iter = set_to_check.begin();
124         iter != set_to_check.end();
125         ++iter) {
126      if (SharedModuleInfo::ImportsExtensionById(iter->get(),
127                                                 extension->id())) {
128        dependents->Insert(*iter);
129      }
130    }
131  }
132  return dependents.PassAs<ExtensionSet>();
133}
134
135void SharedModuleService::PruneSharedModules() {
136  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
137  ExtensionService* service =
138      ExtensionSystem::Get(browser_context_)->extension_service();
139
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());
144
145  std::vector<std::string> shared_modules;
146  std::set<std::string> used_shared_modules;
147
148  for (ExtensionSet::const_iterator iter = set_to_check.begin();
149       iter != set_to_check.end();
150       ++iter) {
151    if (SharedModuleInfo::IsSharedModule(iter->get()))
152      shared_modules.push_back(iter->get()->id());
153
154    const ImportInfoVector& imports = SharedModuleInfo::GetImports(iter->get());
155    for (ImportInfoVector::const_iterator imports_iter = imports.begin();
156         imports_iter != imports.end();
157         ++imports_iter) {
158      used_shared_modules.insert(imports_iter->extension_id);
159    }
160  }
161
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))
167      continue;
168    service->UninstallExtension(
169        *shared_modules_iter,
170        extensions::UNINSTALL_REASON_ORPHANED_SHARED_MODULE,
171        base::Bind(&base::DoNothing),
172        NULL);  // Ignore error.
173  }
174}
175
176void SharedModuleService::OnExtensionInstalled(
177    content::BrowserContext* browser_context,
178    const Extension* extension,
179    bool is_update) {
180  if (is_update)
181    PruneSharedModules();
182}
183
184void SharedModuleService::OnExtensionUninstalled(
185    content::BrowserContext* browser_context,
186    const Extension* extension,
187    extensions::UninstallReason reason) {
188  PruneSharedModules();
189}
190
191}  // namespace extensions
192