Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: extensions/browser/renderer_startup_helper.cc

Issue 2766063003: Extensions: Keep track of loaded extensions in RendererStartupHelper. (Closed)
Patch Set: Fix more tests.. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698