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/dump_without_crashing.h" |
| 8 #include "base/stl_util.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: |
| 55 // This is needed to take care of the case when a RenderProcessHost is |
| 56 // reused for a different renderer process. |
48 UntrackProcess(content::Source<content::RenderProcessHost>(source).ptr()); | 57 UntrackProcess(content::Source<content::RenderProcessHost>(source).ptr()); |
49 break; | 58 break; |
50 default: | 59 default: |
51 NOTREACHED() << "Unexpected notification: " << type; | 60 NOTREACHED() << "Unexpected notification: " << type; |
52 } | 61 } |
53 } | 62 } |
54 | 63 |
55 void RendererStartupHelper::InitializeProcess( | 64 void RendererStartupHelper::InitializeProcess( |
56 content::RenderProcessHost* process) { | 65 content::RenderProcessHost* process) { |
57 ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get(); | 66 ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 if (!webview_partition_id.empty()) { | 98 if (!webview_partition_id.empty()) { |
90 process->Send(new ExtensionMsg_SetWebViewPartitionID( | 99 process->Send(new ExtensionMsg_SetWebViewPartitionID( |
91 WebViewGuest::GetPartitionID(process))); | 100 WebViewGuest::GetPartitionID(process))); |
92 } | 101 } |
93 | 102 |
94 // Loaded extensions. | 103 // Loaded extensions. |
95 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; | 104 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; |
96 const ExtensionSet& extensions = | 105 const ExtensionSet& extensions = |
97 ExtensionRegistry::Get(browser_context_)->enabled_extensions(); | 106 ExtensionRegistry::Get(browser_context_)->enabled_extensions(); |
98 for (const auto& ext : extensions) { | 107 for (const auto& ext : extensions) { |
| 108 // OnLoadedExtension should have already been called for the extension. |
| 109 DCHECK(base::ContainsKey(extension_process_map_, ext->id())); |
| 110 DCHECK(!base::ContainsKey(extension_process_map_[ext->id()], process)); |
| 111 |
99 // Renderers don't need to know about themes. | 112 // Renderers don't need to know about themes. |
100 if (!ext->is_theme()) { | 113 if (!ext->is_theme()) { |
101 // TODO(kalman): Only include tab specific permissions for extension | 114 // TODO(kalman): Only include tab specific permissions for extension |
102 // processes, no other process needs it, so it's mildly wasteful. | 115 // 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 | 116 // 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. | 117 // level of the stack. Perhaps site isolation can help. |
105 bool include_tab_permissions = true; | 118 bool include_tab_permissions = true; |
106 loaded_extensions.push_back( | 119 loaded_extensions.push_back( |
107 ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions)); | 120 ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions)); |
| 121 extension_process_map_[ext->id()].insert(process); |
108 } | 122 } |
109 } | 123 } |
110 process->Send(new ExtensionMsg_Loaded(loaded_extensions)); | 124 process->Send(new ExtensionMsg_Loaded(loaded_extensions)); |
111 auto iter = pending_active_extensions_.find(process); | 125 auto iter = pending_active_extensions_.find(process); |
112 if (iter != pending_active_extensions_.end()) { | 126 if (iter != pending_active_extensions_.end()) { |
113 for (const ExtensionId& id : iter->second) { | 127 for (const ExtensionId& id : iter->second) { |
| 128 // The extension should be loaded in the process. |
114 DCHECK(extensions.Contains(id)); | 129 DCHECK(extensions.Contains(id)); |
| 130 DCHECK(base::ContainsKey(extension_process_map_, id)); |
| 131 DCHECK(base::ContainsKey(extension_process_map_[id], process)); |
115 process->Send(new ExtensionMsg_ActivateExtension(id)); | 132 process->Send(new ExtensionMsg_ActivateExtension(id)); |
116 } | 133 } |
117 } | 134 } |
118 | 135 |
119 initialized_processes_.insert(process); | 136 initialized_processes_.insert(process); |
| 137 pending_active_extensions_.erase(process); |
120 } | 138 } |
121 | 139 |
122 void RendererStartupHelper::UntrackProcess( | 140 void RendererStartupHelper::UntrackProcess( |
123 content::RenderProcessHost* process) { | 141 content::RenderProcessHost* process) { |
124 if (!ExtensionsBrowserClient::Get()->IsSameContext( | 142 if (!ExtensionsBrowserClient::Get()->IsSameContext( |
125 browser_context_, process->GetBrowserContext())) { | 143 browser_context_, process->GetBrowserContext())) { |
126 return; | 144 return; |
127 } | 145 } |
128 | 146 |
129 initialized_processes_.erase(process); | 147 initialized_processes_.erase(process); |
130 pending_active_extensions_.erase(process); | 148 pending_active_extensions_.erase(process); |
| 149 for (auto& extension_process_pair : extension_process_map_) |
| 150 extension_process_pair.second.erase(process); |
131 } | 151 } |
132 | 152 |
133 void RendererStartupHelper::ActivateExtensionInProcess( | 153 void RendererStartupHelper::ActivateExtensionInProcess( |
134 const Extension& extension, | 154 const Extension& extension, |
135 content::RenderProcessHost* process) { | 155 content::RenderProcessHost* process) { |
| 156 // The extension should have been loaded already. Dump without crashing to |
| 157 // debug crbug.com/528026. |
| 158 if (!base::ContainsKey(extension_process_map_, extension.id())) { |
| 159 #if DCHECK_IS_ON() |
| 160 NOTREACHED() << "Extension " << extension.id() |
| 161 << "activated before loading"; |
| 162 #else |
| 163 base::debug::DumpWithoutCrashing(); |
| 164 return; |
| 165 #endif |
| 166 } |
| 167 |
136 // Renderers don't need to know about themes. We also don't normally | 168 // 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 | 169 // "activate" themes, but this could happen if someone tries to open a tab |
138 // to the e.g. theme's manifest. | 170 // to the e.g. theme's manifest. |
139 if (extension.is_theme()) | 171 if (extension.is_theme()) |
140 return; | 172 return; |
141 | 173 |
142 if (initialized_processes_.count(process)) | 174 if (base::ContainsKey(initialized_processes_, process)) { |
| 175 DCHECK(base::ContainsKey(extension_process_map_[extension.id()], process)); |
143 process->Send(new ExtensionMsg_ActivateExtension(extension.id())); | 176 process->Send(new ExtensionMsg_ActivateExtension(extension.id())); |
144 else | 177 } else { |
145 pending_active_extensions_[process].insert(extension.id()); | 178 pending_active_extensions_[process].insert(extension.id()); |
| 179 } |
146 } | 180 } |
147 | 181 |
148 void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) { | 182 void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) { |
| 183 // Extension was already loaded. |
| 184 // TODO(crbug.com/708230): Ensure that clients don't call this for an |
| 185 // already loaded extension and change this to a DCHECK. |
| 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 // TODO(crbug.com/708230): Ensure that clients call this for a loaded |
| 213 // extension only and change this to a DCHECK. |
| 214 if (!base::ContainsKey(extension_process_map_, extension.id())) |
167 return; | 215 return; |
168 | 216 |
169 for (content::RenderProcessHost* process : initialized_processes_) | 217 const std::set<content::RenderProcessHost*>& loaded_process_set = |
| 218 extension_process_map_[extension.id()]; |
| 219 for (content::RenderProcessHost* process : loaded_process_set) { |
| 220 DCHECK(base::ContainsKey(initialized_processes_, process)); |
170 process->Send(new ExtensionMsg_Unloaded(extension.id())); | 221 process->Send(new ExtensionMsg_Unloaded(extension.id())); |
| 222 } |
| 223 |
171 for (auto& process_extensions_pair : pending_active_extensions_) | 224 for (auto& process_extensions_pair : pending_active_extensions_) |
172 process_extensions_pair.second.erase(extension.id()); | 225 process_extensions_pair.second.erase(extension.id()); |
| 226 |
| 227 // Mark the extension as unloaded. |
| 228 extension_process_map_.erase(extension.id()); |
173 } | 229 } |
174 | 230 |
175 ////////////////////////////////////////////////////////////////////////////// | 231 ////////////////////////////////////////////////////////////////////////////// |
176 | 232 |
177 // static | 233 // static |
178 RendererStartupHelper* RendererStartupHelperFactory::GetForBrowserContext( | 234 RendererStartupHelper* RendererStartupHelperFactory::GetForBrowserContext( |
179 BrowserContext* context) { | 235 BrowserContext* context) { |
180 return static_cast<RendererStartupHelper*>( | 236 return static_cast<RendererStartupHelper*>( |
181 GetInstance()->GetServiceForBrowserContext(context, true)); | 237 GetInstance()->GetServiceForBrowserContext(context, true)); |
182 } | 238 } |
(...skipping 21 matching lines...) Expand all Loading... |
204 BrowserContext* context) const { | 260 BrowserContext* context) const { |
205 // Redirected in incognito. | 261 // Redirected in incognito. |
206 return ExtensionsBrowserClient::Get()->GetOriginalContext(context); | 262 return ExtensionsBrowserClient::Get()->GetOriginalContext(context); |
207 } | 263 } |
208 | 264 |
209 bool RendererStartupHelperFactory::ServiceIsCreatedWithBrowserContext() const { | 265 bool RendererStartupHelperFactory::ServiceIsCreatedWithBrowserContext() const { |
210 return true; | 266 return true; |
211 } | 267 } |
212 | 268 |
213 } // namespace extensions | 269 } // namespace extensions |
OLD | NEW |