shared_module_service.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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/install_tracker.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/common/extension.h" 17 18namespace extensions { 19 20namespace { 21 22typedef std::vector<SharedModuleInfo::ImportInfo> ImportInfoVector; 23typedef std::list<SharedModuleInfo::ImportInfo> ImportInfoList; 24 25} // namespace 26 27SharedModuleService::SharedModuleService(content::BrowserContext* context) 28 : context_(context), observing_(false) { 29 InstallTracker::Get(context_)->AddObserver(this); 30} 31 32SharedModuleService::~SharedModuleService() { 33 if (observing_) 34 InstallTracker::Get(context_)->RemoveObserver(this); 35} 36 37SharedModuleService::ImportStatus SharedModuleService::CheckImports( 38 const extensions::Extension* extension, 39 ImportInfoList* missing_modules, 40 ImportInfoList* outdated_modules) { 41 DCHECK(extension); 42 DCHECK(missing_modules && missing_modules->empty()); 43 DCHECK(outdated_modules && outdated_modules->empty()); 44 45 ImportStatus status = IMPORT_STATUS_OK; 46 47 ExtensionRegistry* registry = ExtensionRegistry::Get(context_); 48 const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension); 49 for (ImportInfoVector::const_iterator iter = imports.begin(); 50 iter != imports.end(); 51 ++iter) { 52 base::Version version_required(iter->minimum_version); 53 const Extension* imported_module = 54 registry->GetExtensionById(iter->extension_id, 55 ExtensionRegistry::EVERYTHING); 56 if (!imported_module) { 57 if (extension->from_webstore()) { 58 status = IMPORT_STATUS_UNSATISFIED; 59 missing_modules->push_back(*iter); 60 } else { 61 return IMPORT_STATUS_UNRECOVERABLE; 62 } 63 } else if (!SharedModuleInfo::IsSharedModule(imported_module)) { 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(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<const 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(context_); 113 ExtensionService* service = 114 ExtensionSystem::Get(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<const ExtensionSet>(); 131} 132 133void SharedModuleService::PruneSharedModulesOnUninstall( 134 const Extension* extension) { 135 if (!SharedModuleInfo::ImportsModules(extension)) 136 return; 137 138 ExtensionRegistry* registry = ExtensionRegistry::Get(context_); 139 ExtensionService* service = 140 ExtensionSystem::Get(context_)->extension_service(); 141 142 const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension); 143 for (ImportInfoVector::const_iterator iter = imports.begin(); 144 iter != imports.end(); 145 ++iter) { 146 const Extension* imported_module = 147 registry->GetExtensionById(iter->extension_id, 148 ExtensionRegistry::EVERYTHING); 149 if (imported_module && imported_module->from_webstore()) { 150 scoped_ptr<const ExtensionSet> dependents = 151 GetDependentExtensions(imported_module); 152 if (dependents->is_empty()) { 153 service->UninstallExtension(iter->extension_id, 154 true, // External uninstall. 155 NULL); // Ignore error. 156 } 157 } 158 } 159} 160 161void SharedModuleService::OnExtensionUninstalled(const Extension* extension) { 162 PruneSharedModulesOnUninstall(extension); 163} 164 165void SharedModuleService::OnShutdown() { 166 InstallTracker::Get(context_)->RemoveObserver(this); 167 observing_ = false; 168} 169 170} // namespace extensions 171