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