// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "extensions/browser/renderer_startup_helper.h" #include "base/values.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "extensions/browser/extension_function_dispatcher.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/common/extension_messages.h" #include "extensions/common/extension_set.h" #include "extensions/common/extensions_client.h" #include "extensions/common/features/feature_channel.h" #include "extensions/common/features/feature_session_type.h" #include "ui/base/webui/web_ui_util.h" using content::BrowserContext; namespace extensions { RendererStartupHelper::RendererStartupHelper(BrowserContext* browser_context) : browser_context_(browser_context) { DCHECK(browser_context); registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, content::NotificationService::AllBrowserContextsAndSources()); registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, content::NotificationService::AllBrowserContextsAndSources()); } RendererStartupHelper::~RendererStartupHelper() {} void RendererStartupHelper::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case content::NOTIFICATION_RENDERER_PROCESS_CREATED: InitializeProcess( content::Source(source).ptr()); break; case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: UntrackProcess(content::Source(source).ptr()); break; default: NOTREACHED() << "Unexpected notification: " << type; } } void RendererStartupHelper::InitializeProcess( content::RenderProcessHost* process) { ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get(); if (!client->IsSameContext(browser_context_, process->GetBrowserContext())) return; bool activity_logging_enabled = client->IsActivityLoggingEnabled(process->GetBrowserContext()); // We only send the ActivityLoggingEnabled message if it is enabled; otherwise // the default (not enabled) is correct. if (activity_logging_enabled) { process->Send( new ExtensionMsg_SetActivityLoggingEnabled(activity_logging_enabled)); } // Extensions need to know the channel and the session type for API // restrictions. The values are sent to all renderers, as the non-extension // renderers may have content scripts. process->Send(new ExtensionMsg_SetSessionInfo( GetCurrentChannel(), GetCurrentFeatureSessionType())); // Platform apps need to know the system font. // TODO(dbeam): this is not the system font in all cases. process->Send(new ExtensionMsg_SetSystemFont(webui::GetFontFamily(), webui::GetFontSize())); // Scripting whitelist. This is modified by tests and must be communicated // to renderers. process->Send(new ExtensionMsg_SetScriptingWhitelist( extensions::ExtensionsClient::Get()->GetScriptingWhitelist())); // If the new render process is a WebView guest process, propagate the WebView // partition ID to it. std::string webview_partition_id = WebViewGuest::GetPartitionID(process); if (!webview_partition_id.empty()) { process->Send(new ExtensionMsg_SetWebViewPartitionID( WebViewGuest::GetPartitionID(process))); } // Loaded extensions. std::vector loaded_extensions; const ExtensionSet& extensions = ExtensionRegistry::Get(browser_context_)->enabled_extensions(); for (const auto& ext : extensions) { // Renderers don't need to know about themes. if (!ext->is_theme()) { // TODO(kalman): Only include tab specific permissions for extension // processes, no other process needs it, so it's mildly wasteful. // I am not sure this is possible to know this here, at such a low // level of the stack. Perhaps site isolation can help. bool include_tab_permissions = true; loaded_extensions.push_back( ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions)); } } process->Send(new ExtensionMsg_Loaded(loaded_extensions)); auto iter = pending_active_extensions_.find(process); if (iter != pending_active_extensions_.end()) { for (const ExtensionId& id : iter->second) { DCHECK(extensions.Contains(id)); process->Send(new ExtensionMsg_ActivateExtension(id)); } } initialized_processes_.insert(process); } void RendererStartupHelper::UntrackProcess( content::RenderProcessHost* process) { if (!ExtensionsBrowserClient::Get()->IsSameContext( browser_context_, process->GetBrowserContext())) { return; } initialized_processes_.erase(process); pending_active_extensions_.erase(process); } void RendererStartupHelper::ActivateExtensionInProcess( const Extension& extension, content::RenderProcessHost* process) { // Renderers don't need to know about themes. We also don't normally // "activate" themes, but this could happen if someone tries to open a tab // to the e.g. theme's manifest. if (extension.is_theme()) return; if (initialized_processes_.count(process)) process->Send(new ExtensionMsg_ActivateExtension(extension.id())); else pending_active_extensions_[process].insert(extension.id()); } void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) { // Renderers don't need to know about themes. if (extension.is_theme()) return; // We don't need to include tab permisisons here, since the extension // was just loaded. // Uninitialized renderers will be informed of the extension load during the // first batch of messages. std::vector params( 1, ExtensionMsg_Loaded_Params(&extension, false /* no tab permissions */)); for (content::RenderProcessHost* process : initialized_processes_) process->Send(new ExtensionMsg_Loaded(params)); } void RendererStartupHelper::OnExtensionUnloaded(const Extension& extension) { // Renderers don't need to know about themes. if (extension.is_theme()) return; for (content::RenderProcessHost* process : initialized_processes_) process->Send(new ExtensionMsg_Unloaded(extension.id())); for (auto& process_extensions_pair : pending_active_extensions_) process_extensions_pair.second.erase(extension.id()); } ////////////////////////////////////////////////////////////////////////////// // static RendererStartupHelper* RendererStartupHelperFactory::GetForBrowserContext( BrowserContext* context) { return static_cast( GetInstance()->GetServiceForBrowserContext(context, true)); } // static RendererStartupHelperFactory* RendererStartupHelperFactory::GetInstance() { return base::Singleton::get(); } RendererStartupHelperFactory::RendererStartupHelperFactory() : BrowserContextKeyedServiceFactory( "RendererStartupHelper", BrowserContextDependencyManager::GetInstance()) { // No dependencies on other services. } RendererStartupHelperFactory::~RendererStartupHelperFactory() {} KeyedService* RendererStartupHelperFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { return new RendererStartupHelper(context); } BrowserContext* RendererStartupHelperFactory::GetBrowserContextToUse( BrowserContext* context) const { // Redirected in incognito. return ExtensionsBrowserClient::Get()->GetOriginalContext(context); } bool RendererStartupHelperFactory::ServiceIsCreatedWithBrowserContext() const { return true; } } // namespace extensions