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 <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 
     17 namespace extensions {
     18 
     19 namespace {
     20 
     21 typedef std::vector<SharedModuleInfo::ImportInfo> ImportInfoVector;
     22 typedef std::list<SharedModuleInfo::ImportInfo> ImportInfoList;
     23 
     24 }  // namespace
     25 
     26 SharedModuleService::SharedModuleService(content::BrowserContext* context)
     27     : extension_registry_observer_(this), browser_context_(context) {
     28   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
     29 }
     30 
     31 SharedModuleService::~SharedModuleService() {
     32 }
     33 
     34 SharedModuleService::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 
     79 SharedModuleService::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 
    107 scoped_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 
    133 void 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