| Index: extensions/browser/renderer_startup_helper.cc
|
| diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
|
| index c200c27a2dd843ec4e6fa83d24ef74f875f9c21a..4a309faa66b52703b07cf139612d261f59dc6701 100644
|
| --- a/extensions/browser/renderer_startup_helper.cc
|
| +++ b/extensions/browser/renderer_startup_helper.cc
|
| @@ -4,6 +4,9 @@
|
|
|
| #include "extensions/browser/renderer_startup_helper.h"
|
|
|
| +#include "base/debug/dump_without_crashing.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/strings/string_util.h"
|
| #include "base/values.h"
|
| #include "components/keyed_service/content/browser_context_dependency_manager.h"
|
| #include "content/public/browser/notification_service.h"
|
| @@ -31,6 +34,8 @@ RendererStartupHelper::RendererStartupHelper(BrowserContext* browser_context)
|
| content::NotificationService::AllBrowserContextsAndSources());
|
| registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
|
| content::NotificationService::AllBrowserContextsAndSources());
|
| + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
|
| + content::NotificationService::AllBrowserContextsAndSources());
|
| }
|
|
|
| RendererStartupHelper::~RendererStartupHelper() {}
|
| @@ -45,6 +50,10 @@ void RendererStartupHelper::Observe(
|
| content::Source<content::RenderProcessHost>(source).ptr());
|
| break;
|
| case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
|
| + // Fall through.
|
| + case content::NOTIFICATION_RENDERER_PROCESS_CLOSED:
|
| + // This is needed to take care of the case when a RenderProcessHost is
|
| + // reused for a different renderer process.
|
| UntrackProcess(content::Source<content::RenderProcessHost>(source).ptr());
|
| break;
|
| default:
|
| @@ -96,6 +105,10 @@ void RendererStartupHelper::InitializeProcess(
|
| const ExtensionSet& extensions =
|
| ExtensionRegistry::Get(browser_context_)->enabled_extensions();
|
| for (const auto& ext : extensions) {
|
| + // OnLoadedExtension should have already been called for the extension.
|
| + DCHECK(base::ContainsKey(extension_process_map_, ext->id()));
|
| + DCHECK(!base::ContainsKey(extension_process_map_[ext->id()], process));
|
| +
|
| // Renderers don't need to know about themes.
|
| if (!ext->is_theme()) {
|
| // TODO(kalman): Only include tab specific permissions for extension
|
| @@ -105,18 +118,23 @@ void RendererStartupHelper::InitializeProcess(
|
| bool include_tab_permissions = true;
|
| loaded_extensions.push_back(
|
| ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions));
|
| + extension_process_map_[ext->id()].insert(process);
|
| }
|
| }
|
| 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) {
|
| + // The extension should be loaded in the process.
|
| DCHECK(extensions.Contains(id));
|
| + DCHECK(base::ContainsKey(extension_process_map_, id));
|
| + DCHECK(base::ContainsKey(extension_process_map_[id], process));
|
| process->Send(new ExtensionMsg_ActivateExtension(id));
|
| }
|
| }
|
|
|
| initialized_processes_.insert(process);
|
| + pending_active_extensions_.erase(process);
|
| }
|
|
|
| void RendererStartupHelper::UntrackProcess(
|
| @@ -128,24 +146,50 @@ void RendererStartupHelper::UntrackProcess(
|
|
|
| initialized_processes_.erase(process);
|
| pending_active_extensions_.erase(process);
|
| + for (auto& extension_process_pair : extension_process_map_)
|
| + extension_process_pair.second.erase(process);
|
| }
|
|
|
| void RendererStartupHelper::ActivateExtensionInProcess(
|
| const Extension& extension,
|
| content::RenderProcessHost* process) {
|
| + // The extension should have been loaded already. Dump without crashing to
|
| + // debug crbug.com/528026.
|
| + if (!base::ContainsKey(extension_process_map_, extension.id())) {
|
| +#if DCHECK_IS_ON()
|
| + NOTREACHED() << "Extension " << extension.id()
|
| + << "activated before loading";
|
| +#else
|
| + base::debug::DumpWithoutCrashing();
|
| + return;
|
| +#endif
|
| + }
|
| +
|
| // 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))
|
| + if (base::ContainsKey(initialized_processes_, process)) {
|
| + DCHECK(base::ContainsKey(extension_process_map_[extension.id()], process));
|
| process->Send(new ExtensionMsg_ActivateExtension(extension.id()));
|
| - else
|
| + } else {
|
| pending_active_extensions_[process].insert(extension.id());
|
| + }
|
| }
|
|
|
| void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) {
|
| + // Extension was already loaded.
|
| + // TODO(crbug.com/708230): Ensure that clients don't call this for an
|
| + // already loaded extension and change this to a DCHECK.
|
| + if (base::ContainsKey(extension_process_map_, extension.id()))
|
| + return;
|
| +
|
| + // Mark the extension as loaded.
|
| + std::set<content::RenderProcessHost*>& loaded_process_set =
|
| + extension_process_map_[extension.id()];
|
| +
|
| // Renderers don't need to know about themes.
|
| if (extension.is_theme())
|
| return;
|
| @@ -157,19 +201,31 @@ void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) {
|
| std::vector<ExtensionMsg_Loaded_Params> params(
|
| 1,
|
| ExtensionMsg_Loaded_Params(&extension, false /* no tab permissions */));
|
| - for (content::RenderProcessHost* process : initialized_processes_)
|
| + for (content::RenderProcessHost* process : initialized_processes_) {
|
| process->Send(new ExtensionMsg_Loaded(params));
|
| + loaded_process_set.insert(process);
|
| + }
|
| }
|
|
|
| void RendererStartupHelper::OnExtensionUnloaded(const Extension& extension) {
|
| - // Renderers don't need to know about themes.
|
| - if (extension.is_theme())
|
| + // Extension is not loaded.
|
| + // TODO(crbug.com/708230): Ensure that clients call this for a loaded
|
| + // extension only and change this to a DCHECK.
|
| + if (!base::ContainsKey(extension_process_map_, extension.id()))
|
| return;
|
|
|
| - for (content::RenderProcessHost* process : initialized_processes_)
|
| + const std::set<content::RenderProcessHost*>& loaded_process_set =
|
| + extension_process_map_[extension.id()];
|
| + for (content::RenderProcessHost* process : loaded_process_set) {
|
| + DCHECK(base::ContainsKey(initialized_processes_, process));
|
| process->Send(new ExtensionMsg_Unloaded(extension.id()));
|
| + }
|
| +
|
| for (auto& process_extensions_pair : pending_active_extensions_)
|
| process_extensions_pair.second.erase(extension.id());
|
| +
|
| + // Mark the extension as unloaded.
|
| + extension_process_map_.erase(extension.id());
|
| }
|
|
|
| //////////////////////////////////////////////////////////////////////////////
|
|
|