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

Side by Side Diff: chrome/browser/extensions/extension_process_manager.cc

Issue 3210007: Add support for a "split" incognito behavior for extensions. (Closed)
Patch Set: latest Created 10 years, 3 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 (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "chrome/browser/extensions/extension_process_manager.h" 5 #include "chrome/browser/extensions/extension_process_manager.h"
6 6
7 #include "chrome/browser/browser.h" 7 #include "chrome/browser/browser.h"
8 #include "chrome/browser/browser_window.h" 8 #include "chrome/browser/browser_window.h"
9 #include "chrome/browser/browsing_instance.h" 9 #include "chrome/browser/browsing_instance.h"
10 #if defined(OS_MACOSX) 10 #if defined(OS_MACOSX)
11 #include "chrome/browser/extensions/extension_host_mac.h" 11 #include "chrome/browser/extensions/extension_host_mac.h"
12 #endif 12 #endif
13 #include "chrome/browser/extensions/extension_host.h" 13 #include "chrome/browser/extensions/extension_host.h"
14 #include "chrome/browser/extensions/extensions_service.h" 14 #include "chrome/browser/extensions/extensions_service.h"
15 #include "chrome/browser/profile.h" 15 #include "chrome/browser/profile.h"
16 #include "chrome/browser/renderer_host/site_instance.h" 16 #include "chrome/browser/renderer_host/site_instance.h"
17 #include "chrome/browser/renderer_host/render_view_host.h" 17 #include "chrome/browser/renderer_host/render_view_host.h"
18 #include "chrome/browser/tab_contents/tab_contents.h" 18 #include "chrome/browser/tab_contents/tab_contents.h"
19 #include "chrome/common/extensions/extension.h" 19 #include "chrome/common/extensions/extension.h"
20 #include "chrome/common/extensions/extension_action.h" 20 #include "chrome/common/extensions/extension_action.h"
21 #include "chrome/common/notification_service.h" 21 #include "chrome/common/notification_service.h"
22 #include "chrome/common/notification_type.h" 22 #include "chrome/common/notification_type.h"
23 #include "chrome/common/render_messages.h" 23 #include "chrome/common/render_messages.h"
24 #include "chrome/common/url_constants.h"
25
26 namespace {
27
28 // Incognito profiles use this process manager. It is mostly a shim that decides
29 // whether to fall back on the original profile's ExtensionProcessManager based
30 // on whether a given extension uses "split" or "spanning" incognito behavior.
31 class IncognitoExtensionProcessManager : public ExtensionProcessManager {
32 public:
33 explicit IncognitoExtensionProcessManager(Profile* profile);
34 virtual ~IncognitoExtensionProcessManager() {}
35 virtual ExtensionHost* CreateView(Extension* extension,
36 const GURL& url,
37 Browser* browser,
38 ViewType::Type view_type);
39 virtual void CreateBackgroundHost(Extension* extension, const GURL& url);
40 virtual SiteInstance* GetSiteInstanceForURL(const GURL& url);
41 virtual RenderProcessHost* GetExtensionProcess(const GURL& url);
42
43 private:
44 // NotificationObserver:
45 virtual void Observe(NotificationType type,
46 const NotificationSource& source,
47 const NotificationDetails& details);
48
49 // Returns the extension for an URL, which can either be a chrome-extension
50 // URL or a web app URL.
51 Extension* GetExtensionOrAppByURL(const GURL& url);
52
53 ExtensionProcessManager* original_manager_;
54 };
24 55
25 static void CreateBackgroundHost( 56 static void CreateBackgroundHost(
26 ExtensionProcessManager* manager, Extension* extension) { 57 ExtensionProcessManager* manager, Extension* extension) {
27 // Start the process for the master page, if it exists. 58 // Start the process for the master page, if it exists.
28 if (extension->background_url().is_valid()) 59 if (extension->background_url().is_valid())
29 manager->CreateBackgroundHost(extension, extension->background_url()); 60 manager->CreateBackgroundHost(extension, extension->background_url());
30 } 61 }
31 62
32 static void CreateBackgroundHosts( 63 static void CreateBackgroundHosts(
33 ExtensionProcessManager* manager, const ExtensionList* extensions) { 64 ExtensionProcessManager* manager, const ExtensionList* extensions) {
34 for (ExtensionList::const_iterator extension = extensions->begin(); 65 for (ExtensionList::const_iterator extension = extensions->begin();
35 extension != extensions->end(); ++extension) { 66 extension != extensions->end(); ++extension) {
36 CreateBackgroundHost(manager, *extension); 67 CreateBackgroundHost(manager, *extension);
37 } 68 }
38 } 69 }
39 70
71 } // namespace
72
73 //
74 // ExtensionProcessManager
75 //
76
77 // static
78 ExtensionProcessManager* ExtensionProcessManager::Create(Profile* profile) {
79 return (profile->IsOffTheRecord()) ?
80 new IncognitoExtensionProcessManager(profile) :
81 new ExtensionProcessManager(profile);
82 }
83
40 ExtensionProcessManager::ExtensionProcessManager(Profile* profile) 84 ExtensionProcessManager::ExtensionProcessManager(Profile* profile)
41 : browsing_instance_(new BrowsingInstance(profile)) { 85 : browsing_instance_(new BrowsingInstance(profile)) {
42 registrar_.Add(this, NotificationType::EXTENSIONS_READY, 86 registrar_.Add(this, NotificationType::EXTENSIONS_READY,
43 NotificationService::AllSources()); 87 NotificationService::AllSources());
44 registrar_.Add(this, NotificationType::EXTENSION_LOADED, 88 registrar_.Add(this, NotificationType::EXTENSION_LOADED,
45 NotificationService::AllSources()); 89 NotificationService::AllSources());
46 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, 90 registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
47 NotificationService::AllSources()); 91 NotificationService::AllSources());
48 registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED, 92 registrar_.Add(this, NotificationType::EXTENSION_HOST_DESTROYED,
49 Source<Profile>(profile)); 93 Source<Profile>(profile));
(...skipping 28 matching lines...) Expand all
78 OnExtensionHostCreated(host, false); 122 OnExtensionHostCreated(host, false);
79 return host; 123 return host;
80 } 124 }
81 125
82 ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url, 126 ExtensionHost* ExtensionProcessManager::CreateView(const GURL& url,
83 Browser* browser, 127 Browser* browser,
84 ViewType::Type view_type) { 128 ViewType::Type view_type) {
85 // A NULL browser may only be given for pop-up views. 129 // A NULL browser may only be given for pop-up views.
86 DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP)); 130 DCHECK(browser || (!browser && view_type == ViewType::EXTENSION_POPUP));
87 ExtensionsService* service = 131 ExtensionsService* service =
88 browsing_instance_->profile()->GetExtensionsService(); 132 browsing_instance_->profile()->GetExtensionsService();
89 if (service) { 133 if (service) {
90 Extension* extension = service->GetExtensionByURL(url); 134 Extension* extension = service->GetExtensionByURL(url);
91 if (extension) 135 if (extension)
92 return CreateView(extension, url, browser, view_type); 136 return CreateView(extension, url, browser, view_type);
93 } 137 }
94 return NULL; 138 return NULL;
95 } 139 }
96 140
97 ExtensionHost* ExtensionProcessManager::CreatePopup(Extension* extension, 141 ExtensionHost* ExtensionProcessManager::CreatePopup(Extension* extension,
98 const GURL& url, 142 const GURL& url,
(...skipping 10 matching lines...) Expand all
109 const GURL& url, 153 const GURL& url,
110 Browser* browser) { 154 Browser* browser) {
111 return CreateView(extension, url, browser, ViewType::EXTENSION_INFOBAR); 155 return CreateView(extension, url, browser, ViewType::EXTENSION_INFOBAR);
112 } 156 }
113 157
114 ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url, 158 ExtensionHost* ExtensionProcessManager::CreateInfobar(const GURL& url,
115 Browser* browser) { 159 Browser* browser) {
116 return CreateView(url, browser, ViewType::EXTENSION_INFOBAR); 160 return CreateView(url, browser, ViewType::EXTENSION_INFOBAR);
117 } 161 }
118 162
119 ExtensionHost* ExtensionProcessManager::CreateBackgroundHost( 163 void ExtensionProcessManager::CreateBackgroundHost(
120 Extension* extension, const GURL& url) { 164 Extension* extension, const GURL& url) {
165 // Don't create multiple background hosts for an extension.
166 if (GetBackgroundHostForExtension(extension))
167 return;
168
121 ExtensionHost* host = 169 ExtensionHost* host =
122 #if defined(OS_MACOSX) 170 #if defined(OS_MACOSX)
123 new ExtensionHostMac(extension, GetSiteInstanceForURL(url), url, 171 new ExtensionHostMac(extension, GetSiteInstanceForURL(url), url,
124 ViewType::EXTENSION_BACKGROUND_PAGE); 172 ViewType::EXTENSION_BACKGROUND_PAGE);
125 #else 173 #else
126 new ExtensionHost(extension, GetSiteInstanceForURL(url), url, 174 new ExtensionHost(extension, GetSiteInstanceForURL(url), url,
127 ViewType::EXTENSION_BACKGROUND_PAGE); 175 ViewType::EXTENSION_BACKGROUND_PAGE);
128 #endif 176 #endif
129 177
130 host->CreateRenderViewSoon(NULL); // create a RenderViewHost with no view 178 host->CreateRenderViewSoon(NULL); // create a RenderViewHost with no view
131 OnExtensionHostCreated(host, true); 179 OnExtensionHostCreated(host, true);
132 return host;
133 } 180 }
134 181
135 void ExtensionProcessManager::OpenOptionsPage(Extension* extension, 182 void ExtensionProcessManager::OpenOptionsPage(Extension* extension,
136 Browser* browser) { 183 Browser* browser) {
137 DCHECK(!extension->options_url().is_empty()); 184 DCHECK(!extension->options_url().is_empty());
138 185
139 // We can't open extensions URLs in incognito windows. 186 // We can't open extensions URLs in incognito windows, unless the extension
140 if (!browser || browser->profile()->IsOffTheRecord()) 187 // uses "split" incognito mode.
141 browser = Browser::GetOrCreateTabbedBrowser(browsing_instance_->profile()); 188 if (!browser || (browser->profile()->IsOffTheRecord() &&
189 !extension->incognito_split_mode())) {
190 browser = Browser::GetOrCreateTabbedBrowser(
191 browsing_instance_->profile()->GetOriginalProfile());
192 }
142 193
143 browser->OpenURL(extension->options_url(), GURL(), SINGLETON_TAB, 194 browser->OpenURL(extension->options_url(), GURL(), SINGLETON_TAB,
144 PageTransition::LINK); 195 PageTransition::LINK);
145 browser->window()->Show(); 196 browser->window()->Show();
146 browser->GetSelectedTabContents()->Activate(); 197 browser->GetSelectedTabContents()->Activate();
147 } 198 }
148 199
149 ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension( 200 ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension(
150 Extension* extension) { 201 Extension* extension) {
151 for (ExtensionHostSet::iterator iter = background_hosts_.begin(); 202 for (ExtensionHostSet::iterator iter = background_hosts_.begin();
152 iter != background_hosts_.end(); ++iter) { 203 iter != background_hosts_.end(); ++iter) {
153 ExtensionHost* host = *iter; 204 ExtensionHost* host = *iter;
154 if (host->extension() == extension) 205 if (host->extension() == extension)
155 return host; 206 return host;
156 } 207 }
157 return NULL; 208 return NULL;
158 } 209 }
159 210
160 void ExtensionProcessManager::RegisterExtensionProcess( 211 void ExtensionProcessManager::RegisterExtensionProcess(
161 const std::string& extension_id, int process_id) { 212 const std::string& extension_id, int process_id) {
213 // TODO(mpcomplete): This is the only place we actually read process_ids_.
214 // Is it necessary?
162 ProcessIDMap::const_iterator it = process_ids_.find(extension_id); 215 ProcessIDMap::const_iterator it = process_ids_.find(extension_id);
163 if (it != process_ids_.end() && (*it).second == process_id) 216 if (it != process_ids_.end() && (*it).second == process_id)
164 return; 217 return;
165 218
166 // Extension ids should get removed from the map before the process ids get 219 // Extension ids should get removed from the map before the process ids get
167 // reused from a dead renderer. 220 // reused from a dead renderer.
168 DCHECK(it == process_ids_.end()); 221 DCHECK(it == process_ids_.end());
169 process_ids_[extension_id] = process_id; 222 process_ids_[extension_id] = process_id;
170 223
171 ExtensionsService* extension_service = 224 ExtensionsService* extension_service =
(...skipping 18 matching lines...) Expand all
190 else 243 else
191 ++it; 244 ++it;
192 } 245 }
193 } 246 }
194 247
195 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( 248 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess(
196 const GURL& url) { 249 const GURL& url) {
197 if (!browsing_instance_->HasSiteInstance(url)) 250 if (!browsing_instance_->HasSiteInstance(url))
198 return NULL; 251 return NULL;
199 scoped_refptr<SiteInstance> site = 252 scoped_refptr<SiteInstance> site =
200 browsing_instance_->GetSiteInstanceForURL(url); 253 browsing_instance_->GetSiteInstanceForURL(url);
201 if (site->HasProcess()) 254 if (site->HasProcess())
202 return site->GetProcess(); 255 return site->GetProcess();
203 return NULL; 256 return NULL;
204 } 257 }
205 258
206 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess( 259 RenderProcessHost* ExtensionProcessManager::GetExtensionProcess(
207 const std::string& extension_id) { 260 const std::string& extension_id) {
208 ProcessIDMap::const_iterator it = process_ids_.find(extension_id); 261 return GetExtensionProcess(
209 if (it == process_ids_.end()) 262 Extension::GetBaseURLFromExtensionId(extension_id));
210 return NULL;
211
212 RenderProcessHost* rph = RenderProcessHost::FromID(it->second);
213 DCHECK(rph) << "We should have unregistered this host.";
214 return rph;
215 } 263 }
216 264
217 SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) { 265 SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) {
218 return browsing_instance_->GetSiteInstanceForURL(url); 266 return browsing_instance_->GetSiteInstanceForURL(url);
219 } 267 }
220 268
221 bool ExtensionProcessManager::HasExtensionHost(ExtensionHost* host) const { 269 bool ExtensionProcessManager::HasExtensionHost(ExtensionHost* host) const {
222 return all_hosts_.find(host) != all_hosts_.end(); 270 return all_hosts_.find(host) != all_hosts_.end();
223 } 271 }
224 272
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 break; 326 break;
279 } 327 }
280 328
281 default: 329 default:
282 NOTREACHED(); 330 NOTREACHED();
283 } 331 }
284 } 332 }
285 333
286 void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host, 334 void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host,
287 bool is_background) { 335 bool is_background) {
336 DCHECK_EQ(browsing_instance_->profile(), host->profile());
337
288 all_hosts_.insert(host); 338 all_hosts_.insert(host);
289 if (is_background) 339 if (is_background)
290 background_hosts_.insert(host); 340 background_hosts_.insert(host);
291 NotificationService::current()->Notify( 341 NotificationService::current()->Notify(
292 NotificationType::EXTENSION_HOST_CREATED, 342 NotificationType::EXTENSION_HOST_CREATED,
293 Source<ExtensionProcessManager>(this), 343 Source<ExtensionProcessManager>(this),
294 Details<ExtensionHost>(host)); 344 Details<ExtensionHost>(host));
295 } 345 }
296 346
297 void ExtensionProcessManager::CloseBackgroundHosts() { 347 void ExtensionProcessManager::CloseBackgroundHosts() {
298 for (ExtensionHostSet::iterator iter = background_hosts_.begin(); 348 for (ExtensionHostSet::iterator iter = background_hosts_.begin();
299 iter != background_hosts_.end(); ) { 349 iter != background_hosts_.end(); ) {
300 ExtensionHostSet::iterator current = iter++; 350 ExtensionHostSet::iterator current = iter++;
301 delete *current; 351 delete *current;
302 } 352 }
303 } 353 }
354
355 //
356 // IncognitoExtensionProcessManager
357 //
358
359 IncognitoExtensionProcessManager::IncognitoExtensionProcessManager(
360 Profile* profile)
361 : ExtensionProcessManager(profile),
362 original_manager_(profile->GetOriginalProfile()->
363 GetExtensionProcessManager()) {
364 DCHECK(profile->IsOffTheRecord());
365
366 registrar_.Add(this, NotificationType::BROWSER_WINDOW_READY,
367 NotificationService::AllSources());
368 }
369
370 ExtensionHost* IncognitoExtensionProcessManager::CreateView(
371 Extension* extension,
372 const GURL& url,
373 Browser* browser,
374 ViewType::Type view_type) {
375 if (extension->incognito_split_mode()) {
376 return ExtensionProcessManager::CreateView(extension, url,
377 browser, view_type);
378 } else {
379 return original_manager_->CreateView(extension, url, browser, view_type);
380 }
381 }
382
383 void IncognitoExtensionProcessManager::CreateBackgroundHost(
384 Extension* extension, const GURL& url) {
385 if (extension->incognito_split_mode()) {
386 ExtensionProcessManager::CreateBackgroundHost(extension, url);
387 } else {
388 // Do nothing. If an extension is spanning, then its original-profile
389 // background page is shared with incognito, so we don't create another.
390 }
391 }
392
393 SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL(
394 const GURL& url) {
395 Extension* extension = GetExtensionOrAppByURL(url);
396 if (!extension || extension->incognito_split_mode()) {
397 return ExtensionProcessManager::GetSiteInstanceForURL(url);
398 } else {
399 return original_manager_->GetSiteInstanceForURL(url);
400 }
401 }
402
403 RenderProcessHost* IncognitoExtensionProcessManager::GetExtensionProcess(
404 const GURL& url) {
405 Extension* extension = GetExtensionOrAppByURL(url);
406 if (!extension || extension->incognito_split_mode()) {
407 return ExtensionProcessManager::GetExtensionProcess(url);
408 } else {
409 return original_manager_->GetExtensionProcess(url);
410 }
411 }
412
413 Extension* IncognitoExtensionProcessManager::GetExtensionOrAppByURL(
414 const GURL& url) {
415 ExtensionsService* service =
416 browsing_instance_->profile()->GetExtensionsService();
417 return (url.SchemeIs(chrome::kExtensionScheme)) ?
418 service->GetExtensionByURL(url) : service->GetExtensionByWebExtent(url);
419 }
420
421 void IncognitoExtensionProcessManager::Observe(
422 NotificationType type,
423 const NotificationSource& source,
424 const NotificationDetails& details) {
425 switch (type.value) {
426 case NotificationType::BROWSER_WINDOW_READY: {
427 // We want to spawn our background hosts as soon as the user opens an
428 // incognito window. Watch for new browsers and create the hosts if
429 // it matches our profile.
430 Browser* browser = Source<Browser>(source).ptr();
431 if (browser->profile() == browsing_instance_->profile()) {
432 ExtensionsService* service =
433 browsing_instance_->profile()->GetExtensionsService();
434 if (service && service->is_ready())
435 CreateBackgroundHosts(this, service->extensions());
436 }
437 break;
438 }
439 default:
440 ExtensionProcessManager::Observe(type, source, details);
441 break;
442 }
443 }
OLDNEW
« no previous file with comments | « chrome/browser/extensions/extension_process_manager.h ('k') | chrome/browser/extensions/extension_process_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698