1 // Copyright (c) 2012 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/extension_system.h" 6 7 #include "base/base_switches.h" 8 #include "base/bind.h" 9 #include "base/command_line.h" 10 #include "base/files/file_path.h" 11 #include "base/strings/string_tokenizer.h" 12 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/content_settings/cookie_settings.h" 14 #include "chrome/browser/extensions/blacklist.h" 15 #include "chrome/browser/extensions/component_loader.h" 16 #include "chrome/browser/extensions/error_console/error_console.h" 17 #include "chrome/browser/extensions/event_router.h" 18 #include "chrome/browser/extensions/extension_error_reporter.h" 19 #include "chrome/browser/extensions/extension_info_map.h" 20 #include "chrome/browser/extensions/extension_pref_store.h" 21 #include "chrome/browser/extensions/extension_pref_value_map.h" 22 #include "chrome/browser/extensions/extension_pref_value_map_factory.h" 23 #include "chrome/browser/extensions/extension_prefs.h" 24 #include "chrome/browser/extensions/extension_process_manager.h" 25 #include "chrome/browser/extensions/extension_service.h" 26 #include "chrome/browser/extensions/extension_system_factory.h" 27 #include "chrome/browser/extensions/extension_warning_badge_service.h" 28 #include "chrome/browser/extensions/extension_warning_set.h" 29 #include "chrome/browser/extensions/lazy_background_task_queue.h" 30 #include "chrome/browser/extensions/management_policy.h" 31 #include "chrome/browser/extensions/navigation_observer.h" 32 #include "chrome/browser/extensions/standard_management_policy_provider.h" 33 #include "chrome/browser/extensions/state_store.h" 34 #include "chrome/browser/extensions/unpacked_installer.h" 35 #include "chrome/browser/extensions/user_script_master.h" 36 #include "chrome/browser/profiles/profile.h" 37 #include "chrome/browser/profiles/profile_manager.h" 38 #include "chrome/browser/sync/glue/sync_start_util.h" 39 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 40 #include "chrome/common/chrome_switches.h" 41 #include "chrome/common/chrome_version_info.h" 42 #include "chrome/common/extensions/extension.h" 43 #include "chrome/common/extensions/features/feature_channel.h" 44 #include "chrome/common/extensions/manifest.h" 45 #include "content/public/browser/browser_thread.h" 46 #include "content/public/browser/url_data_source.h" 47 #include "extensions/common/constants.h" 48 49 #if defined(OS_CHROMEOS) 50 #include "chrome/browser/app_mode/app_mode_utils.h" 51 #include "chromeos/chromeos_switches.h" 52 #include "chromeos/login/login_state.h" 53 #endif 54 55 using content::BrowserThread; 56 57 namespace extensions { 58 59 // 60 // ExtensionSystem 61 // 62 63 ExtensionSystem::ExtensionSystem() { 64 // Only set if it hasn't already been set (e.g. by a test). 65 if (GetCurrentChannel() == GetDefaultChannel()) 66 SetCurrentChannel(chrome::VersionInfo::GetChannel()); 67 } 68 69 ExtensionSystem::~ExtensionSystem() { 70 } 71 72 // static 73 ExtensionSystem* ExtensionSystem::Get(Profile* profile) { 74 return ExtensionSystemFactory::GetForProfile(profile); 75 } 76 77 // 78 // ExtensionSystemImpl::Shared 79 // 80 81 ExtensionSystemImpl::Shared::Shared(Profile* profile) 82 : profile_(profile) { 83 } 84 85 ExtensionSystemImpl::Shared::~Shared() { 86 } 87 88 void ExtensionSystemImpl::Shared::InitPrefs() { 89 lazy_background_task_queue_.reset(new LazyBackgroundTaskQueue(profile_)); 90 event_router_.reset(new EventRouter(profile_, ExtensionPrefs::Get(profile_))); 91 // TODO(yoz): Remove once crbug.com/159265 is fixed. 92 #if defined(ENABLE_EXTENSIONS) 93 // Two state stores. The latter, which contains declarative rules, must be 94 // loaded immediately so that the rules are ready before we issue network 95 // requests. 96 state_store_.reset(new StateStore( 97 profile_, 98 profile_->GetPath().AppendASCII(ExtensionService::kStateStoreName), 99 true)); 100 101 rules_store_.reset(new StateStore( 102 profile_, 103 profile_->GetPath().AppendASCII(ExtensionService::kRulesStoreName), 104 false)); 105 106 blacklist_.reset(new Blacklist(ExtensionPrefs::Get(profile_))); 107 108 standard_management_policy_provider_.reset( 109 new StandardManagementPolicyProvider(ExtensionPrefs::Get(profile_))); 110 #endif 111 } 112 113 void ExtensionSystemImpl::Shared::RegisterManagementPolicyProviders() { 114 // TODO(yoz): Remove once crbug.com/159265 is fixed. 115 #if defined(ENABLE_EXTENSIONS) 116 DCHECK(standard_management_policy_provider_.get()); 117 management_policy_->RegisterProvider( 118 standard_management_policy_provider_.get()); 119 #endif 120 } 121 122 void ExtensionSystemImpl::Shared::Init(bool extensions_enabled) { 123 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 124 125 navigation_observer_.reset(new NavigationObserver(profile_)); 126 127 bool allow_noisy_errors = !command_line->HasSwitch(switches::kNoErrorDialogs); 128 ExtensionErrorReporter::Init(allow_noisy_errors); 129 130 user_script_master_ = new UserScriptMaster(profile_); 131 132 bool autoupdate_enabled = true; 133 #if defined(OS_CHROMEOS) 134 if (!extensions_enabled) 135 autoupdate_enabled = false; 136 else 137 autoupdate_enabled = 138 !command_line->HasSwitch(chromeos::switches::kGuestSession); 139 #endif 140 extension_service_.reset(new ExtensionService( 141 profile_, 142 CommandLine::ForCurrentProcess(), 143 profile_->GetPath().AppendASCII(extensions::kInstallDirectoryName), 144 ExtensionPrefs::Get(profile_), 145 blacklist_.get(), 146 autoupdate_enabled, 147 extensions_enabled, 148 &ready_)); 149 extension_service_->SetSyncStartFlare( 150 sync_start_util::GetFlareForSyncableService(profile_->GetPath())); 151 152 // These services must be registered before the ExtensionService tries to 153 // load any extensions. 154 { 155 management_policy_.reset(new ManagementPolicy); 156 RegisterManagementPolicyProviders(); 157 } 158 159 bool skip_session_extensions = false; 160 #if defined(OS_CHROMEOS) 161 // Skip loading session extensions if we are not in a user session. 162 skip_session_extensions = !chromeos::LoginState::Get()->IsUserLoggedIn(); 163 if (!chrome::IsRunningInForcedAppMode()) { 164 extension_service_->component_loader()->AddDefaultComponentExtensions( 165 skip_session_extensions); 166 } 167 #else 168 extension_service_->component_loader()->AddDefaultComponentExtensions( 169 skip_session_extensions); 170 #endif 171 if (command_line->HasSwitch(switches::kLoadComponentExtension)) { 172 CommandLine::StringType path_list = command_line->GetSwitchValueNative( 173 switches::kLoadComponentExtension); 174 base::StringTokenizerT<CommandLine::StringType, 175 CommandLine::StringType::const_iterator> t(path_list, 176 FILE_PATH_LITERAL(",")); 177 while (t.GetNext()) { 178 // Load the component extension manifest synchronously. 179 // Blocking the UI thread is acceptable here since 180 // this flag designated for developers. 181 base::ThreadRestrictions::ScopedAllowIO allow_io; 182 extension_service_->component_loader()->AddOrReplace( 183 base::FilePath(t.token())); 184 } 185 } 186 extension_service_->Init(); 187 188 if (extensions_enabled) { 189 // Load any extensions specified with --load-extension. 190 // TODO(yoz): Seems like this should move into ExtensionService::Init. 191 // But maybe it's no longer important. 192 if (command_line->HasSwitch(switches::kLoadExtension)) { 193 CommandLine::StringType path_list = command_line->GetSwitchValueNative( 194 switches::kLoadExtension); 195 base::StringTokenizerT<CommandLine::StringType, 196 CommandLine::StringType::const_iterator> t(path_list, 197 FILE_PATH_LITERAL(",")); 198 while (t.GetNext()) { 199 std::string extension_id; 200 UnpackedInstaller::Create(extension_service_.get())-> 201 LoadFromCommandLine(base::FilePath(t.token()), &extension_id); 202 } 203 } 204 } 205 206 // Make the chrome://extension-icon/ resource available. 207 content::URLDataSource::Add(profile_, new ExtensionIconSource(profile_)); 208 209 // Initialize extension event routers. Note that on Chrome OS, this will 210 // not succeed if the user has not logged in yet, in which case the 211 // event routers are initialized in LoginUtilsImpl::CompleteLogin instead. 212 // The InitEventRouters call used to be in BrowserMain, because when bookmark 213 // import happened on first run, the bookmark bar was not being correctly 214 // initialized (see issue 40144). Now that bookmarks aren't imported and 215 // the event routers need to be initialized for every profile individually, 216 // initialize them with the extension service. 217 extension_service_->InitEventRouters(); 218 219 extension_warning_service_.reset(new ExtensionWarningService(profile_)); 220 extension_warning_badge_service_.reset( 221 new ExtensionWarningBadgeService(profile_)); 222 extension_warning_service_->AddObserver( 223 extension_warning_badge_service_.get()); 224 error_console_.reset(new ErrorConsole(profile_)); 225 } 226 227 void ExtensionSystemImpl::Shared::Shutdown() { 228 if (extension_warning_service_) { 229 extension_warning_service_->RemoveObserver( 230 extension_warning_badge_service_.get()); 231 } 232 if (extension_service_) 233 extension_service_->Shutdown(); 234 } 235 236 StateStore* ExtensionSystemImpl::Shared::state_store() { 237 return state_store_.get(); 238 } 239 240 StateStore* ExtensionSystemImpl::Shared::rules_store() { 241 return rules_store_.get(); 242 } 243 244 ExtensionService* ExtensionSystemImpl::Shared::extension_service() { 245 return extension_service_.get(); 246 } 247 248 ManagementPolicy* ExtensionSystemImpl::Shared::management_policy() { 249 return management_policy_.get(); 250 } 251 252 UserScriptMaster* ExtensionSystemImpl::Shared::user_script_master() { 253 return user_script_master_.get(); 254 } 255 256 ExtensionInfoMap* ExtensionSystemImpl::Shared::info_map() { 257 if (!extension_info_map_.get()) 258 extension_info_map_ = new ExtensionInfoMap(); 259 return extension_info_map_.get(); 260 } 261 262 LazyBackgroundTaskQueue* 263 ExtensionSystemImpl::Shared::lazy_background_task_queue() { 264 return lazy_background_task_queue_.get(); 265 } 266 267 EventRouter* ExtensionSystemImpl::Shared::event_router() { 268 return event_router_.get(); 269 } 270 271 ExtensionWarningService* ExtensionSystemImpl::Shared::warning_service() { 272 return extension_warning_service_.get(); 273 } 274 275 Blacklist* ExtensionSystemImpl::Shared::blacklist() { 276 return blacklist_.get(); 277 } 278 279 ErrorConsole* ExtensionSystemImpl::Shared::error_console() { 280 return error_console_.get(); 281 } 282 283 // 284 // ExtensionSystemImpl 285 // 286 287 ExtensionSystemImpl::ExtensionSystemImpl(Profile* profile) 288 : profile_(profile) { 289 shared_ = ExtensionSystemSharedFactory::GetForProfile(profile); 290 291 if (profile->IsOffTheRecord()) { 292 extension_process_manager_.reset(ExtensionProcessManager::Create(profile)); 293 } else { 294 shared_->InitPrefs(); 295 } 296 } 297 298 ExtensionSystemImpl::~ExtensionSystemImpl() { 299 } 300 301 void ExtensionSystemImpl::Shutdown() { 302 extension_process_manager_.reset(); 303 } 304 305 void ExtensionSystemImpl::InitForRegularProfile(bool extensions_enabled) { 306 DCHECK(!profile_->IsOffTheRecord()); 307 if (user_script_master() || extension_service()) 308 return; // Already initialized. 309 310 // The ExtensionInfoMap needs to be created before the 311 // ExtensionProcessManager. 312 shared_->info_map(); 313 314 extension_process_manager_.reset(ExtensionProcessManager::Create(profile_)); 315 316 shared_->Init(extensions_enabled); 317 } 318 319 ExtensionService* ExtensionSystemImpl::extension_service() { 320 return shared_->extension_service(); 321 } 322 323 ManagementPolicy* ExtensionSystemImpl::management_policy() { 324 return shared_->management_policy(); 325 } 326 327 UserScriptMaster* ExtensionSystemImpl::user_script_master() { 328 return shared_->user_script_master(); 329 } 330 331 ExtensionProcessManager* ExtensionSystemImpl::process_manager() { 332 return extension_process_manager_.get(); 333 } 334 335 StateStore* ExtensionSystemImpl::state_store() { 336 return shared_->state_store(); 337 } 338 339 StateStore* ExtensionSystemImpl::rules_store() { 340 return shared_->rules_store(); 341 } 342 343 ExtensionInfoMap* ExtensionSystemImpl::info_map() { 344 return shared_->info_map(); 345 } 346 347 LazyBackgroundTaskQueue* ExtensionSystemImpl::lazy_background_task_queue() { 348 return shared_->lazy_background_task_queue(); 349 } 350 351 EventRouter* ExtensionSystemImpl::event_router() { 352 return shared_->event_router(); 353 } 354 355 ExtensionWarningService* ExtensionSystemImpl::warning_service() { 356 return shared_->warning_service(); 357 } 358 359 Blacklist* ExtensionSystemImpl::blacklist() { 360 return shared_->blacklist(); 361 } 362 363 const OneShotEvent& ExtensionSystemImpl::ready() const { 364 return shared_->ready(); 365 } 366 367 ErrorConsole* ExtensionSystemImpl::error_console() { 368 return shared_->error_console(); 369 } 370 371 void ExtensionSystemImpl::RegisterExtensionWithRequestContexts( 372 const Extension* extension) { 373 base::Time install_time; 374 if (extension->location() != Manifest::COMPONENT) { 375 install_time = ExtensionPrefs::Get(profile_)-> 376 GetInstallTime(extension->id()); 377 } 378 bool incognito_enabled = 379 extension_service()->IsIncognitoEnabled(extension->id()); 380 BrowserThread::PostTask( 381 BrowserThread::IO, FROM_HERE, 382 base::Bind(&ExtensionInfoMap::AddExtension, info_map(), 383 make_scoped_refptr(extension), install_time, 384 incognito_enabled)); 385 } 386 387 void ExtensionSystemImpl::UnregisterExtensionWithRequestContexts( 388 const std::string& extension_id, 389 const extension_misc::UnloadedExtensionReason reason) { 390 BrowserThread::PostTask( 391 BrowserThread::IO, FROM_HERE, 392 base::Bind(&ExtensionInfoMap::RemoveExtension, info_map(), 393 extension_id, reason)); 394 } 395 396 } // namespace extensions 397