Home | History | Annotate | Download | only in extensions
      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 "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"
     18 
     19 namespace extensions {
     20 
     21 namespace {
     22 
     23 typedef std::vector<SharedModuleInfo::ImportInfo> ImportInfoVector;
     24 typedef std::list<SharedModuleInfo::ImportInfo> ImportInfoList;
     25 
     26 }  // namespace
     27 
     28 SharedModuleService::SharedModuleService(content::BrowserContext* context)
     29     : extension_registry_observer_(this), browser_context_(context) {
     30   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
     31 }
     32 
     33 SharedModuleService::~SharedModuleService() {
     34 }
     35 
     36 SharedModuleService::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 (version_required.IsValid() &&
     65                imported_module->version()->CompareTo(version_required) < 0) {
     66       if (imported_module->from_webstore()) {
     67         outdated_modules->push_back(*iter);
     68         status = IMPORT_STATUS_UNSATISFIED;
     69       } else {
     70         return IMPORT_STATUS_UNRECOVERABLE;
     71       }
     72     }
     73   }
     74 
     75   return status;
     76 }
     77 
     78 SharedModuleService::ImportStatus SharedModuleService::SatisfyImports(
     79     const Extension* extension) {
     80   ImportInfoList missing_modules;
     81   ImportInfoList outdated_modules;
     82   ImportStatus status =
     83       CheckImports(extension, &missing_modules, &outdated_modules);
     84 
     85   ExtensionService* service =
     86       ExtensionSystem::Get(browser_context_)->extension_service();
     87 
     88   PendingExtensionManager* pending_extension_manager =
     89       service->pending_extension_manager();
     90   DCHECK(pending_extension_manager);
     91 
     92   if (status == IMPORT_STATUS_UNSATISFIED) {
     93     for (ImportInfoList::const_iterator iter = missing_modules.begin();
     94          iter != missing_modules.end();
     95          ++iter) {
     96       pending_extension_manager->AddFromExtensionImport(
     97           iter->extension_id,
     98           extension_urls::GetWebstoreUpdateUrl(),
     99           SharedModuleInfo::IsSharedModule);
    100     }
    101     service->CheckForUpdatesSoon();
    102   }
    103   return status;
    104 }
    105 
    106 scoped_ptr<ExtensionSet> SharedModuleService::GetDependentExtensions(
    107     const Extension* extension) {
    108   scoped_ptr<ExtensionSet> dependents(new ExtensionSet());
    109 
    110   if (SharedModuleInfo::IsSharedModule(extension)) {
    111     ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
    112     ExtensionService* service =
    113         ExtensionSystem::Get(browser_context_)->extension_service();
    114 
    115     ExtensionSet set_to_check;
    116     set_to_check.InsertAll(registry->enabled_extensions());
    117     set_to_check.InsertAll(registry->disabled_extensions());
    118     set_to_check.InsertAll(*service->delayed_installs());
    119 
    120     for (ExtensionSet::const_iterator iter = set_to_check.begin();
    121          iter != set_to_check.end();
    122          ++iter) {
    123       if (SharedModuleInfo::ImportsExtensionById(iter->get(),
    124                                                  extension->id())) {
    125         dependents->Insert(*iter);
    126       }
    127     }
    128   }
    129   return dependents.PassAs<ExtensionSet>();
    130 }
    131 
    132 void SharedModuleService::PruneSharedModules() {
    133   ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
    134   ExtensionService* service =
    135       ExtensionSystem::Get(browser_context_)->extension_service();
    136 
    137   ExtensionSet set_to_check;
    138   set_to_check.InsertAll(registry->enabled_extensions());
    139   set_to_check.InsertAll(registry->disabled_extensions());
    140   set_to_check.InsertAll(*service->delayed_installs());
    141 
    142   std::vector<std::string> shared_modules;
    143   std::set<std::string> used_shared_modules;
    144 
    145   for (ExtensionSet::const_iterator iter = set_to_check.begin();
    146        iter != set_to_check.end();
    147        ++iter) {
    148     if (SharedModuleInfo::IsSharedModule(iter->get()))
    149       shared_modules.push_back(iter->get()->id());
    150 
    151     const ImportInfoVector& imports = SharedModuleInfo::GetImports(iter->get());
    152     for (ImportInfoVector::const_iterator imports_iter = imports.begin();
    153          imports_iter != imports.end();
    154          ++imports_iter) {
    155       used_shared_modules.insert(imports_iter->extension_id);
    156     }
    157   }
    158 
    159   std::vector<std::string>::const_iterator shared_modules_iter;
    160   for (shared_modules_iter = shared_modules.begin();
    161        shared_modules_iter != shared_modules.end();
    162        shared_modules_iter++) {
    163     if (used_shared_modules.count(*shared_modules_iter))
    164       continue;
    165     service->UninstallExtension(
    166         *shared_modules_iter,
    167         extensions::UNINSTALL_REASON_ORPHANED_SHARED_MODULE,
    168         base::Bind(&base::DoNothing),
    169         NULL);  // Ignore error.
    170   }
    171 }
    172 
    173 void SharedModuleService::OnExtensionInstalled(
    174     content::BrowserContext* browser_context,
    175     const Extension* extension,
    176     bool is_update) {
    177   if (is_update)
    178     PruneSharedModules();
    179 }
    180 
    181 void SharedModuleService::OnExtensionUninstalled(
    182     content::BrowserContext* browser_context,
    183     const Extension* extension,
    184     extensions::UninstallReason reason) {
    185   PruneSharedModules();
    186 }
    187 
    188 }  // namespace extensions
    189