shared_module_service.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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 <vector>
8
9#include "base/version.h"
10#include "chrome/browser/extensions/extension_service.h"
11#include "chrome/browser/extensions/pending_extension_manager.h"
12#include "chrome/common/extensions/extension_constants.h"
13#include "extensions/browser/extension_registry.h"
14#include "extensions/browser/extension_system.h"
15#include "extensions/common/extension.h"
16
17namespace extensions {
18
19namespace {
20
21typedef std::vector<SharedModuleInfo::ImportInfo> ImportInfoVector;
22typedef std::list<SharedModuleInfo::ImportInfo> ImportInfoList;
23
24}  // namespace
25
26SharedModuleService::SharedModuleService(content::BrowserContext* context)
27    : extension_registry_observer_(this), browser_context_(context) {
28  extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
29}
30
31SharedModuleService::~SharedModuleService() {
32}
33
34SharedModuleService::ImportStatus SharedModuleService::CheckImports(
35    const Extension* extension,
36    ImportInfoList* missing_modules,
37    ImportInfoList* outdated_modules) {
38  DCHECK(extension);
39  DCHECK(missing_modules && missing_modules->empty());
40  DCHECK(outdated_modules && outdated_modules->empty());
41
42  ImportStatus status = IMPORT_STATUS_OK;
43
44  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
45  const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension);
46  for (ImportInfoVector::const_iterator iter = imports.begin();
47       iter != imports.end();
48       ++iter) {
49    base::Version version_required(iter->minimum_version);
50    const Extension* imported_module =
51        registry->GetExtensionById(iter->extension_id,
52                                   ExtensionRegistry::EVERYTHING);
53    if (!imported_module) {
54      if (extension->from_webstore()) {
55        status = IMPORT_STATUS_UNSATISFIED;
56        missing_modules->push_back(*iter);
57      } else {
58        return IMPORT_STATUS_UNRECOVERABLE;
59      }
60    } else if (!SharedModuleInfo::IsSharedModule(imported_module)) {
61      return IMPORT_STATUS_UNRECOVERABLE;
62    } else if (!SharedModuleInfo::IsExportAllowedByWhitelist(imported_module,
63                                                             extension->id())) {
64      return IMPORT_STATUS_UNRECOVERABLE;
65    } else if (version_required.IsValid() &&
66               imported_module->version()->CompareTo(version_required) < 0) {
67      if (imported_module->from_webstore()) {
68        outdated_modules->push_back(*iter);
69        status = IMPORT_STATUS_UNSATISFIED;
70      } else {
71        return IMPORT_STATUS_UNRECOVERABLE;
72      }
73    }
74  }
75
76  return status;
77}
78
79SharedModuleService::ImportStatus SharedModuleService::SatisfyImports(
80    const Extension* extension) {
81  ImportInfoList missing_modules;
82  ImportInfoList outdated_modules;
83  ImportStatus status =
84      CheckImports(extension, &missing_modules, &outdated_modules);
85
86  ExtensionService* service =
87      ExtensionSystem::Get(browser_context_)->extension_service();
88
89  PendingExtensionManager* pending_extension_manager =
90      service->pending_extension_manager();
91  DCHECK(pending_extension_manager);
92
93  if (status == IMPORT_STATUS_UNSATISFIED) {
94    for (ImportInfoList::const_iterator iter = missing_modules.begin();
95         iter != missing_modules.end();
96         ++iter) {
97      pending_extension_manager->AddFromExtensionImport(
98          iter->extension_id,
99          extension_urls::GetWebstoreUpdateUrl(),
100          SharedModuleInfo::IsSharedModule);
101    }
102    service->CheckForUpdatesSoon();
103  }
104  return status;
105}
106
107scoped_ptr<ExtensionSet> SharedModuleService::GetDependentExtensions(
108    const Extension* extension) {
109  scoped_ptr<ExtensionSet> dependents(new ExtensionSet());
110
111  if (SharedModuleInfo::IsSharedModule(extension)) {
112    ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
113    ExtensionService* service =
114        ExtensionSystem::Get(browser_context_)->extension_service();
115
116    ExtensionSet set_to_check;
117    set_to_check.InsertAll(registry->enabled_extensions());
118    set_to_check.InsertAll(registry->disabled_extensions());
119    set_to_check.InsertAll(*service->delayed_installs());
120
121    for (ExtensionSet::const_iterator iter = set_to_check.begin();
122         iter != set_to_check.end();
123         ++iter) {
124      if (SharedModuleInfo::ImportsExtensionById(iter->get(),
125                                                 extension->id())) {
126        dependents->Insert(*iter);
127      }
128    }
129  }
130  return dependents.PassAs<ExtensionSet>();
131}
132
133void SharedModuleService::OnExtensionUninstalled(
134    content::BrowserContext* browser_context,
135    const Extension* extension) {
136  // Uninstalls shared modules that were only referenced by |extension|.
137  if (!SharedModuleInfo::ImportsModules(extension))
138    return;
139
140  ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
141  ExtensionService* service =
142      ExtensionSystem::Get(browser_context_)->extension_service();
143
144  const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension);
145  for (ImportInfoVector::const_iterator iter = imports.begin();
146       iter != imports.end();
147       ++iter) {
148    const Extension* imported_module =
149        registry->GetExtensionById(iter->extension_id,
150                                   ExtensionRegistry::EVERYTHING);
151    if (imported_module && imported_module->from_webstore()) {
152      scoped_ptr<ExtensionSet> dependents =
153          GetDependentExtensions(imported_module);
154      if (dependents->is_empty()) {
155        service->UninstallExtension(iter->extension_id,
156                                    true,  // External uninstall.
157                                    NULL);  // Ignore error.
158      }
159    }
160  }
161}
162
163}  // namespace extensions
164