Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/browser/renderer_startup_helper.h" | 5 #include "extensions/browser/renderer_startup_helper.h" |
| 6 | 6 |
| 7 #include "base/debug/alias.h" | |
| 8 #include "base/debug/dump_without_crashing.h" | |
| 9 #include "base/strings/string_util.h" | |
| 7 #include "base/values.h" | 10 #include "base/values.h" |
| 8 #include "components/keyed_service/content/browser_context_dependency_manager.h" | 11 #include "components/keyed_service/content/browser_context_dependency_manager.h" |
| 9 #include "content/public/browser/notification_service.h" | 12 #include "content/public/browser/notification_service.h" |
| 10 #include "content/public/browser/notification_types.h" | 13 #include "content/public/browser/notification_types.h" |
| 11 #include "content/public/browser/render_process_host.h" | 14 #include "content/public/browser/render_process_host.h" |
| 12 #include "extensions/browser/extension_function_dispatcher.h" | 15 #include "extensions/browser/extension_function_dispatcher.h" |
| 13 #include "extensions/browser/extension_registry.h" | 16 #include "extensions/browser/extension_registry.h" |
| 14 #include "extensions/browser/extensions_browser_client.h" | 17 #include "extensions/browser/extensions_browser_client.h" |
| 15 #include "extensions/browser/guest_view/web_view/web_view_guest.h" | 18 #include "extensions/browser/guest_view/web_view/web_view_guest.h" |
| 16 #include "extensions/common/extension_messages.h" | 19 #include "extensions/common/extension_messages.h" |
| 17 #include "extensions/common/extension_set.h" | 20 #include "extensions/common/extension_set.h" |
| 18 #include "extensions/common/extensions_client.h" | 21 #include "extensions/common/extensions_client.h" |
| 19 #include "extensions/common/features/feature_channel.h" | 22 #include "extensions/common/features/feature_channel.h" |
| 20 #include "extensions/common/features/feature_session_type.h" | 23 #include "extensions/common/features/feature_session_type.h" |
| 21 #include "ui/base/webui/web_ui_util.h" | 24 #include "ui/base/webui/web_ui_util.h" |
| 22 | 25 |
| 23 using content::BrowserContext; | 26 using content::BrowserContext; |
| 24 | 27 |
| 25 namespace extensions { | 28 namespace extensions { |
| 26 | 29 |
| 27 RendererStartupHelper::RendererStartupHelper(BrowserContext* browser_context) | 30 RendererStartupHelper::RendererStartupHelper(BrowserContext* browser_context) |
| 28 : browser_context_(browser_context) { | 31 : browser_context_(browser_context) { |
| 29 DCHECK(browser_context); | 32 DCHECK(browser_context); |
| 30 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 33 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
| 31 content::NotificationService::AllBrowserContextsAndSources()); | 34 content::NotificationService::AllBrowserContextsAndSources()); |
| 32 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 35 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
| 33 content::NotificationService::AllBrowserContextsAndSources()); | 36 content::NotificationService::AllBrowserContextsAndSources()); |
| 37 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
| 38 content::NotificationService::AllBrowserContextsAndSources()); | |
| 34 } | 39 } |
| 35 | 40 |
| 36 RendererStartupHelper::~RendererStartupHelper() {} | 41 RendererStartupHelper::~RendererStartupHelper() {} |
| 37 | 42 |
| 38 void RendererStartupHelper::Observe( | 43 void RendererStartupHelper::Observe( |
| 39 int type, | 44 int type, |
| 40 const content::NotificationSource& source, | 45 const content::NotificationSource& source, |
| 41 const content::NotificationDetails& details) { | 46 const content::NotificationDetails& details) { |
| 42 switch (type) { | 47 switch (type) { |
| 43 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: | 48 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: |
| 44 InitializeProcess( | 49 InitializeProcess( |
| 45 content::Source<content::RenderProcessHost>(source).ptr()); | 50 content::Source<content::RenderProcessHost>(source).ptr()); |
| 46 break; | 51 break; |
| 47 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: | 52 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: |
| 53 // Fall through. | |
| 54 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: | |
|
karandeepb
2017/04/04 00:49:42
So there were cases where InitializeProcess was be
Devlin
2017/04/04 15:25:00
Wild! Good find. We should add a comment for thi
karandeepb
2017/04/04 18:22:25
Done.
| |
| 48 UntrackProcess(content::Source<content::RenderProcessHost>(source).ptr()); | 55 UntrackProcess(content::Source<content::RenderProcessHost>(source).ptr()); |
| 49 break; | 56 break; |
| 50 default: | 57 default: |
| 51 NOTREACHED() << "Unexpected notification: " << type; | 58 NOTREACHED() << "Unexpected notification: " << type; |
| 52 } | 59 } |
| 53 } | 60 } |
| 54 | 61 |
| 55 void RendererStartupHelper::InitializeProcess( | 62 void RendererStartupHelper::InitializeProcess( |
| 56 content::RenderProcessHost* process) { | 63 content::RenderProcessHost* process) { |
| 57 ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get(); | 64 ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 if (!webview_partition_id.empty()) { | 96 if (!webview_partition_id.empty()) { |
| 90 process->Send(new ExtensionMsg_SetWebViewPartitionID( | 97 process->Send(new ExtensionMsg_SetWebViewPartitionID( |
| 91 WebViewGuest::GetPartitionID(process))); | 98 WebViewGuest::GetPartitionID(process))); |
| 92 } | 99 } |
| 93 | 100 |
| 94 // Loaded extensions. | 101 // Loaded extensions. |
| 95 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; | 102 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; |
| 96 const ExtensionSet& extensions = | 103 const ExtensionSet& extensions = |
| 97 ExtensionRegistry::Get(browser_context_)->enabled_extensions(); | 104 ExtensionRegistry::Get(browser_context_)->enabled_extensions(); |
| 98 for (const auto& ext : extensions) { | 105 for (const auto& ext : extensions) { |
| 106 // OnLoadedExtension should have already been called for the extension. | |
|
karandeepb
2017/04/04 00:49:42
This was not true for extensions loaded through Sh
| |
| 107 DCHECK(base::ContainsKey(extension_process_map_, ext->id())); | |
| 108 DCHECK(!base::ContainsKey(extension_process_map_[ext->id()], process)); | |
| 109 | |
| 99 // Renderers don't need to know about themes. | 110 // Renderers don't need to know about themes. |
| 100 if (!ext->is_theme()) { | 111 if (!ext->is_theme()) { |
| 101 // TODO(kalman): Only include tab specific permissions for extension | 112 // TODO(kalman): Only include tab specific permissions for extension |
| 102 // processes, no other process needs it, so it's mildly wasteful. | 113 // processes, no other process needs it, so it's mildly wasteful. |
| 103 // I am not sure this is possible to know this here, at such a low | 114 // I am not sure this is possible to know this here, at such a low |
| 104 // level of the stack. Perhaps site isolation can help. | 115 // level of the stack. Perhaps site isolation can help. |
| 105 bool include_tab_permissions = true; | 116 bool include_tab_permissions = true; |
| 106 loaded_extensions.push_back( | 117 loaded_extensions.push_back( |
| 107 ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions)); | 118 ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions)); |
| 119 extension_process_map_[ext->id()].insert(process); | |
| 108 } | 120 } |
| 109 } | 121 } |
| 110 process->Send(new ExtensionMsg_Loaded(loaded_extensions)); | 122 process->Send(new ExtensionMsg_Loaded(loaded_extensions)); |
| 111 auto iter = pending_active_extensions_.find(process); | 123 auto iter = pending_active_extensions_.find(process); |
| 112 if (iter != pending_active_extensions_.end()) { | 124 if (iter != pending_active_extensions_.end()) { |
| 113 for (const ExtensionId& id : iter->second) { | 125 for (const ExtensionId& id : iter->second) { |
| 126 // The extension should be loaded in the process. | |
| 114 DCHECK(extensions.Contains(id)); | 127 DCHECK(extensions.Contains(id)); |
| 128 DCHECK(base::ContainsKey(extension_process_map_, id)); | |
| 129 DCHECK(base::ContainsKey(extension_process_map_[id], process)); | |
| 115 process->Send(new ExtensionMsg_ActivateExtension(id)); | 130 process->Send(new ExtensionMsg_ActivateExtension(id)); |
| 116 } | 131 } |
| 117 } | 132 } |
| 118 | 133 |
| 119 initialized_processes_.insert(process); | 134 initialized_processes_.insert(process); |
| 135 pending_active_extensions_.erase(process); | |
| 120 } | 136 } |
| 121 | 137 |
| 122 void RendererStartupHelper::UntrackProcess( | 138 void RendererStartupHelper::UntrackProcess( |
| 123 content::RenderProcessHost* process) { | 139 content::RenderProcessHost* process) { |
| 124 if (!ExtensionsBrowserClient::Get()->IsSameContext( | 140 if (!ExtensionsBrowserClient::Get()->IsSameContext( |
| 125 browser_context_, process->GetBrowserContext())) { | 141 browser_context_, process->GetBrowserContext())) { |
| 126 return; | 142 return; |
| 127 } | 143 } |
| 128 | 144 |
| 129 initialized_processes_.erase(process); | 145 initialized_processes_.erase(process); |
| 130 pending_active_extensions_.erase(process); | 146 pending_active_extensions_.erase(process); |
| 147 for (auto& extension_process_pair : extension_process_map_) | |
| 148 extension_process_pair.second.erase(process); | |
| 131 } | 149 } |
| 132 | 150 |
| 133 void RendererStartupHelper::ActivateExtensionInProcess( | 151 void RendererStartupHelper::ActivateExtensionInProcess( |
| 134 const Extension& extension, | 152 const Extension& extension, |
| 135 content::RenderProcessHost* process) { | 153 content::RenderProcessHost* process) { |
| 154 // The extension should have been loaded already. Dump without crashing to | |
| 155 // debug crbug.com/528026. | |
| 156 if (!base::ContainsKey(extension_process_map_, extension.id())) { | |
| 157 #if DCHECK_IS_ON() | |
| 158 NOTREACHED() << "Extension " << extension.id() | |
| 159 << "activated before loading"; | |
| 160 #else | |
| 161 char extension_id_copy[33]; | |
|
Devlin
2017/04/04 15:25:00
Do you think the extension id help us debug the cr
karandeepb
2017/04/04 18:22:25
Removed.
| |
| 162 base::strlcpy(extension_id_copy, extension.id().c_str(), | |
| 163 arraysize(extension_id_copy)); | |
| 164 base::debug::Alias(extension_id_copy); | |
| 165 base::debug::DumpWithoutCrashing(); | |
| 166 return; | |
| 167 #endif | |
| 168 } | |
| 169 | |
| 136 // Renderers don't need to know about themes. We also don't normally | 170 // Renderers don't need to know about themes. We also don't normally |
| 137 // "activate" themes, but this could happen if someone tries to open a tab | 171 // "activate" themes, but this could happen if someone tries to open a tab |
| 138 // to the e.g. theme's manifest. | 172 // to the e.g. theme's manifest. |
| 139 if (extension.is_theme()) | 173 if (extension.is_theme()) |
| 140 return; | 174 return; |
| 141 | 175 |
| 142 if (initialized_processes_.count(process)) | 176 if (base::ContainsKey(initialized_processes_, process)) { |
| 177 DCHECK(base::ContainsKey(extension_process_map_[extension.id()], process)); | |
| 143 process->Send(new ExtensionMsg_ActivateExtension(extension.id())); | 178 process->Send(new ExtensionMsg_ActivateExtension(extension.id())); |
| 144 else | 179 } else { |
| 145 pending_active_extensions_[process].insert(extension.id()); | 180 pending_active_extensions_[process].insert(extension.id()); |
| 181 } | |
| 146 } | 182 } |
| 147 | 183 |
| 148 void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) { | 184 void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) { |
| 185 // Extension was already loaded. | |
| 186 if (base::ContainsKey(extension_process_map_, extension.id())) | |
| 187 return; | |
| 188 | |
| 189 // Mark the extension as loaded. | |
| 190 std::set<content::RenderProcessHost*>& loaded_process_set = | |
| 191 extension_process_map_[extension.id()]; | |
| 192 | |
| 149 // Renderers don't need to know about themes. | 193 // Renderers don't need to know about themes. |
| 150 if (extension.is_theme()) | 194 if (extension.is_theme()) |
| 151 return; | 195 return; |
| 152 | 196 |
| 153 // We don't need to include tab permisisons here, since the extension | 197 // We don't need to include tab permisisons here, since the extension |
| 154 // was just loaded. | 198 // was just loaded. |
| 155 // Uninitialized renderers will be informed of the extension load during the | 199 // Uninitialized renderers will be informed of the extension load during the |
| 156 // first batch of messages. | 200 // first batch of messages. |
| 157 std::vector<ExtensionMsg_Loaded_Params> params( | 201 std::vector<ExtensionMsg_Loaded_Params> params( |
| 158 1, | 202 1, |
| 159 ExtensionMsg_Loaded_Params(&extension, false /* no tab permissions */)); | 203 ExtensionMsg_Loaded_Params(&extension, false /* no tab permissions */)); |
| 160 for (content::RenderProcessHost* process : initialized_processes_) | 204 for (content::RenderProcessHost* process : initialized_processes_) { |
| 161 process->Send(new ExtensionMsg_Loaded(params)); | 205 process->Send(new ExtensionMsg_Loaded(params)); |
| 206 loaded_process_set.insert(process); | |
| 207 } | |
| 162 } | 208 } |
| 163 | 209 |
| 164 void RendererStartupHelper::OnExtensionUnloaded(const Extension& extension) { | 210 void RendererStartupHelper::OnExtensionUnloaded(const Extension& extension) { |
| 165 // Renderers don't need to know about themes. | 211 // Extension is not loaded. |
| 166 if (extension.is_theme()) | 212 if (!base::ContainsKey(extension_process_map_, extension.id())) |
|
karandeepb
2017/04/04 00:49:42
I was DCHECKing this (and the corresponding check
Devlin
2017/04/04 15:25:00
I think this should be fixed. Mind filing a bug o
karandeepb
2017/04/04 18:22:25
Done.
| |
| 167 return; | 213 return; |
| 168 | 214 |
| 169 for (content::RenderProcessHost* process : initialized_processes_) | 215 const std::set<content::RenderProcessHost*>& loaded_process_set = |
| 216 extension_process_map_[extension.id()]; | |
| 217 for (content::RenderProcessHost* process : loaded_process_set) { | |
| 218 DCHECK(base::ContainsKey(initialized_processes_, process)); | |
| 170 process->Send(new ExtensionMsg_Unloaded(extension.id())); | 219 process->Send(new ExtensionMsg_Unloaded(extension.id())); |
| 220 } | |
| 221 | |
| 171 for (auto& process_extensions_pair : pending_active_extensions_) | 222 for (auto& process_extensions_pair : pending_active_extensions_) |
| 172 process_extensions_pair.second.erase(extension.id()); | 223 process_extensions_pair.second.erase(extension.id()); |
| 224 | |
| 225 // Mark the extension as unloaded. | |
| 226 extension_process_map_.erase(extension.id()); | |
| 173 } | 227 } |
| 174 | 228 |
| 175 ////////////////////////////////////////////////////////////////////////////// | 229 ////////////////////////////////////////////////////////////////////////////// |
| 176 | 230 |
| 177 // static | 231 // static |
| 178 RendererStartupHelper* RendererStartupHelperFactory::GetForBrowserContext( | 232 RendererStartupHelper* RendererStartupHelperFactory::GetForBrowserContext( |
| 179 BrowserContext* context) { | 233 BrowserContext* context) { |
| 180 return static_cast<RendererStartupHelper*>( | 234 return static_cast<RendererStartupHelper*>( |
| 181 GetInstance()->GetServiceForBrowserContext(context, true)); | 235 GetInstance()->GetServiceForBrowserContext(context, true)); |
| 182 } | 236 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 204 BrowserContext* context) const { | 258 BrowserContext* context) const { |
| 205 // Redirected in incognito. | 259 // Redirected in incognito. |
| 206 return ExtensionsBrowserClient::Get()->GetOriginalContext(context); | 260 return ExtensionsBrowserClient::Get()->GetOriginalContext(context); |
| 207 } | 261 } |
| 208 | 262 |
| 209 bool RendererStartupHelperFactory::ServiceIsCreatedWithBrowserContext() const { | 263 bool RendererStartupHelperFactory::ServiceIsCreatedWithBrowserContext() const { |
| 210 return true; | 264 return true; |
| 211 } | 265 } |
| 212 | 266 |
| 213 } // namespace extensions | 267 } // namespace extensions |
| OLD | NEW |