Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / extensions / browser / process_manager.cc
blob47f7b191e004da8dccf2a6179c9a17a73471752f
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/process_manager.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/stl_util.h"
12 #include "base/time/time.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/devtools_agent_host.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/render_frame_host.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/site_instance.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/url_constants.h"
22 #include "extensions/browser/extension_host.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/browser/extensions_browser_client.h"
26 #include "extensions/browser/notification_types.h"
27 #include "extensions/browser/process_manager_delegate.h"
28 #include "extensions/browser/process_manager_factory.h"
29 #include "extensions/browser/process_manager_observer.h"
30 #include "extensions/browser/view_type_utils.h"
31 #include "extensions/common/constants.h"
32 #include "extensions/common/extension.h"
33 #include "extensions/common/extension_messages.h"
34 #include "extensions/common/manifest_handlers/background_info.h"
35 #include "extensions/common/manifest_handlers/incognito_info.h"
36 #include "extensions/common/one_shot_event.h"
38 using content::BrowserContext;
40 namespace extensions {
42 namespace {
44 // The time to delay between an extension becoming idle and
45 // sending a ShouldSuspend message.
46 // Note: Must be sufficiently larger (e.g. 2x) than
47 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals.
48 unsigned g_event_page_idle_time_msec = 10000;
50 // The time to delay between sending a ShouldSuspend message and
51 // sending a Suspend message.
52 unsigned g_event_page_suspending_time_msec = 5000;
54 std::string GetExtensionIdForSiteInstance(
55 content::SiteInstance* site_instance) {
56 if (!site_instance)
57 return std::string();
59 // This works for both apps and extensions because the site has been
60 // normalized to the extension URL for hosted apps.
61 const GURL& site_url = site_instance->GetSiteURL();
63 if (!site_url.SchemeIs(kExtensionScheme) &&
64 !site_url.SchemeIs(content::kGuestScheme))
65 return std::string();
67 return site_url.host();
70 std::string GetExtensionID(content::RenderFrameHost* render_frame_host) {
71 CHECK(render_frame_host);
72 return GetExtensionIdForSiteInstance(render_frame_host->GetSiteInstance());
75 bool IsFrameInExtensionHost(ExtensionHost* extension_host,
76 content::RenderFrameHost* render_frame_host) {
77 return content::WebContents::FromRenderFrameHost(render_frame_host) ==
78 extension_host->host_contents();
81 // Incognito profiles use this process manager. It is mostly a shim that decides
82 // whether to fall back on the original profile's ProcessManager based
83 // on whether a given extension uses "split" or "spanning" incognito behavior.
84 // TODO(devlin): Given how little this does and the amount of cruft it adds to
85 // the .h file (in the form of protected members), we should consider just
86 // moving the incognito logic into the base class.
87 class IncognitoProcessManager : public ProcessManager {
88 public:
89 IncognitoProcessManager(BrowserContext* incognito_context,
90 BrowserContext* original_context,
91 ExtensionRegistry* extension_registry);
92 ~IncognitoProcessManager() override {}
93 bool CreateBackgroundHost(const Extension* extension,
94 const GURL& url) override;
95 scoped_refptr<content::SiteInstance> GetSiteInstanceForURL(const GURL& url)
96 override;
98 private:
99 DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager);
102 static void CreateBackgroundHostForExtensionLoad(
103 ProcessManager* manager, const Extension* extension) {
104 DVLOG(1) << "CreateBackgroundHostForExtensionLoad";
105 if (BackgroundInfo::HasPersistentBackgroundPage(extension))
106 manager->CreateBackgroundHost(extension,
107 BackgroundInfo::GetBackgroundURL(extension));
110 } // namespace
112 struct ProcessManager::BackgroundPageData {
113 // The count of things keeping the lazy background page alive.
114 int lazy_keepalive_count;
116 // Tracks if an impulse event has occured since the last polling check.
117 bool keepalive_impulse;
118 bool previous_keepalive_impulse;
120 // True if the page responded to the ShouldSuspend message and is currently
121 // dispatching the suspend event. During this time any events that arrive will
122 // cancel the suspend process and an onSuspendCanceled event will be
123 // dispatched to the page.
124 bool is_closing;
126 // Stores the value of the incremented
127 // ProcessManager::last_background_close_sequence_id_ whenever the extension
128 // is active. A copy of the ID is also passed in the callbacks and IPC
129 // messages leading up to CloseLazyBackgroundPageNow. The process is aborted
130 // if the IDs ever differ due to new activity.
131 uint64 close_sequence_id;
133 // Keeps track of when this page was last suspended. Used for perf metrics.
134 linked_ptr<base::ElapsedTimer> since_suspended;
136 BackgroundPageData()
137 : lazy_keepalive_count(0),
138 keepalive_impulse(false),
139 previous_keepalive_impulse(false),
140 is_closing(false),
141 close_sequence_id(0) {}
144 // Data of a RenderFrameHost associated with an extension.
145 struct ProcessManager::ExtensionRenderFrameData {
146 // The type of the view.
147 extensions::ViewType view_type;
149 // Whether the view is keeping the lazy background page alive or not.
150 bool has_keepalive;
152 ExtensionRenderFrameData()
153 : view_type(VIEW_TYPE_INVALID), has_keepalive(false) {}
155 // Returns whether the view can keep the lazy background page alive or not.
156 bool CanKeepalive() const {
157 switch (view_type) {
158 case VIEW_TYPE_APP_WINDOW:
159 case VIEW_TYPE_BACKGROUND_CONTENTS:
160 case VIEW_TYPE_EXTENSION_DIALOG:
161 case VIEW_TYPE_EXTENSION_POPUP:
162 case VIEW_TYPE_LAUNCHER_PAGE:
163 case VIEW_TYPE_PANEL:
164 case VIEW_TYPE_TAB_CONTENTS:
165 case VIEW_TYPE_VIRTUAL_KEYBOARD:
166 return true;
168 case VIEW_TYPE_INVALID:
169 case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE:
170 return false;
172 NOTREACHED();
173 return false;
178 // ProcessManager
181 // static
182 ProcessManager* ProcessManager::Get(BrowserContext* context) {
183 return ProcessManagerFactory::GetForBrowserContext(context);
186 // static
187 ProcessManager* ProcessManager::Create(BrowserContext* context) {
188 ExtensionRegistry* extension_registry = ExtensionRegistry::Get(context);
189 ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
190 if (client->IsGuestSession(context)) {
191 // In the guest session, there is a single off-the-record context. Unlike
192 // a regular incognito mode, background pages of extensions must be
193 // created regardless of whether extensions use "spanning" or "split"
194 // incognito behavior.
195 BrowserContext* original_context = client->GetOriginalContext(context);
196 return new ProcessManager(context, original_context, extension_registry);
199 if (context->IsOffTheRecord()) {
200 BrowserContext* original_context = client->GetOriginalContext(context);
201 return new IncognitoProcessManager(
202 context, original_context, extension_registry);
205 return new ProcessManager(context, context, extension_registry);
208 // static
209 ProcessManager* ProcessManager::CreateForTesting(
210 BrowserContext* context,
211 ExtensionRegistry* extension_registry) {
212 DCHECK(!context->IsOffTheRecord());
213 return new ProcessManager(context, context, extension_registry);
216 // static
217 ProcessManager* ProcessManager::CreateIncognitoForTesting(
218 BrowserContext* incognito_context,
219 BrowserContext* original_context,
220 ExtensionRegistry* extension_registry) {
221 DCHECK(incognito_context->IsOffTheRecord());
222 DCHECK(!original_context->IsOffTheRecord());
223 return new IncognitoProcessManager(incognito_context,
224 original_context,
225 extension_registry);
228 ProcessManager::ProcessManager(BrowserContext* context,
229 BrowserContext* original_context,
230 ExtensionRegistry* extension_registry)
231 : extension_registry_(extension_registry),
232 site_instance_(content::SiteInstance::Create(context)),
233 browser_context_(context),
234 startup_background_hosts_created_(false),
235 last_background_close_sequence_id_(0),
236 weak_ptr_factory_(this) {
237 // ExtensionRegistry is shared between incognito and regular contexts.
238 DCHECK_EQ(original_context, extension_registry_->browser_context());
239 extension_registry_->AddObserver(this);
241 if (!context->IsOffTheRecord()) {
242 // Only the original profile needs to listen for ready to create background
243 // pages for all spanning extensions.
244 registrar_.Add(this,
245 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
246 content::Source<BrowserContext>(original_context));
248 registrar_.Add(this,
249 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
250 content::Source<BrowserContext>(context));
251 registrar_.Add(this,
252 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
253 content::Source<BrowserContext>(context));
254 devtools_callback_ = base::Bind(&ProcessManager::OnDevToolsStateChanged,
255 weak_ptr_factory_.GetWeakPtr());
256 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_);
258 OnKeepaliveImpulseCheck();
261 ProcessManager::~ProcessManager() {
262 extension_registry_->RemoveObserver(this);
263 CloseBackgroundHosts();
264 DCHECK(background_hosts_.empty());
265 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_);
268 void ProcessManager::RegisterRenderFrameHost(
269 content::WebContents* web_contents,
270 content::RenderFrameHost* render_frame_host,
271 const Extension* extension) {
272 ExtensionRenderFrameData* data = &all_extension_frames_[render_frame_host];
273 data->view_type = GetViewType(web_contents);
275 // Keep the lazy background page alive as long as any non-background-page
276 // extension views are visible. Keepalive count balanced in
277 // UnregisterRenderFrame.
278 AcquireLazyKeepaliveCountForFrame(render_frame_host);
280 FOR_EACH_OBSERVER(ProcessManagerObserver,
281 observer_list_,
282 OnExtensionFrameRegistered(extension->id(),
283 render_frame_host));
286 void ProcessManager::UnregisterRenderFrameHost(
287 content::RenderFrameHost* render_frame_host) {
288 ExtensionRenderFrames::iterator frame =
289 all_extension_frames_.find(render_frame_host);
291 if (frame != all_extension_frames_.end()) {
292 std::string extension_id = GetExtensionID(render_frame_host);
293 // Keepalive count, balanced in RegisterRenderFrame.
294 ReleaseLazyKeepaliveCountForFrame(render_frame_host);
295 all_extension_frames_.erase(frame);
297 FOR_EACH_OBSERVER(ProcessManagerObserver,
298 observer_list_,
299 OnExtensionFrameUnregistered(extension_id,
300 render_frame_host));
304 scoped_refptr<content::SiteInstance> ProcessManager::GetSiteInstanceForURL(
305 const GURL& url) {
306 return make_scoped_refptr(site_instance_->GetRelatedSiteInstance(url));
309 const ProcessManager::FrameSet ProcessManager::GetAllFrames() const {
310 FrameSet result;
311 for (const auto& key_value : all_extension_frames_)
312 result.insert(key_value.first);
313 return result;
316 ProcessManager::FrameSet ProcessManager::GetRenderFrameHostsForExtension(
317 const std::string& extension_id) {
318 FrameSet result;
319 scoped_refptr<content::SiteInstance> site_instance(GetSiteInstanceForURL(
320 Extension::GetBaseURLFromExtensionId(extension_id)));
321 if (!site_instance.get())
322 return result;
324 // Gather up all the frames for that site.
325 for (const auto& key_value : all_extension_frames_) {
326 if (key_value.first->GetSiteInstance() == site_instance)
327 result.insert(key_value.first);
330 return result;
333 void ProcessManager::AddObserver(ProcessManagerObserver* observer) {
334 observer_list_.AddObserver(observer);
337 void ProcessManager::RemoveObserver(ProcessManagerObserver* observer) {
338 observer_list_.RemoveObserver(observer);
341 bool ProcessManager::CreateBackgroundHost(const Extension* extension,
342 const GURL& url) {
343 // Hosted apps are taken care of from BackgroundContentsService. Ignore them
344 // here.
345 if (extension->is_hosted_app())
346 return false;
348 // Don't create hosts if the embedder doesn't allow it.
349 ProcessManagerDelegate* delegate =
350 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
351 if (delegate && !delegate->IsBackgroundPageAllowed(browser_context_))
352 return false;
354 // Don't create multiple background hosts for an extension.
355 if (GetBackgroundHostForExtension(extension->id()))
356 return true; // TODO(kalman): return false here? It might break things...
358 ExtensionHost* host =
359 new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url,
360 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
361 host->CreateRenderViewSoon();
362 OnBackgroundHostCreated(host);
363 return true;
366 void ProcessManager::MaybeCreateStartupBackgroundHosts() {
367 if (startup_background_hosts_created_)
368 return;
370 // The embedder might disallow background pages entirely.
371 ProcessManagerDelegate* delegate =
372 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
373 if (delegate && !delegate->IsBackgroundPageAllowed(browser_context_))
374 return;
376 // The embedder might want to defer background page loading. For example,
377 // Chrome defers background page loading when it is launched to show the app
378 // list, then triggers a load later when a browser window opens.
379 if (delegate &&
380 delegate->DeferCreatingStartupBackgroundHosts(browser_context_))
381 return;
383 CreateStartupBackgroundHosts();
384 startup_background_hosts_created_ = true;
386 // Background pages should only be loaded once. To prevent any further loads
387 // occurring, we remove the notification listeners.
388 BrowserContext* original_context =
389 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context_);
390 if (registrar_.IsRegistered(
391 this,
392 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
393 content::Source<BrowserContext>(original_context))) {
394 registrar_.Remove(this,
395 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
396 content::Source<BrowserContext>(original_context));
400 ExtensionHost* ProcessManager::GetBackgroundHostForExtension(
401 const std::string& extension_id) {
402 for (ExtensionHost* host : background_hosts_) {
403 if (host->extension_id() == extension_id)
404 return host;
406 return nullptr;
409 bool ProcessManager::IsBackgroundHostClosing(const std::string& extension_id) {
410 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
411 return (host && background_page_data_[extension_id].is_closing);
414 const Extension* ProcessManager::GetExtensionForRenderFrameHost(
415 content::RenderFrameHost* render_frame_host) {
416 return extension_registry_->enabled_extensions().GetByID(
417 GetExtensionID(render_frame_host));
420 const Extension* ProcessManager::GetExtensionForWebContents(
421 content::WebContents* web_contents) {
422 if (!web_contents->GetSiteInstance())
423 return nullptr;
424 return extension_registry_->enabled_extensions().GetByID(
425 GetExtensionIdForSiteInstance(web_contents->GetSiteInstance()));
428 int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
429 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
430 return 0;
432 return background_page_data_[extension->id()].lazy_keepalive_count;
435 void ProcessManager::IncrementLazyKeepaliveCount(const Extension* extension) {
436 if (BackgroundInfo::HasLazyBackgroundPage(extension)) {
437 int& count = background_page_data_[extension->id()].lazy_keepalive_count;
438 if (++count == 1)
439 OnLazyBackgroundPageActive(extension->id());
443 void ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) {
444 if (BackgroundInfo::HasLazyBackgroundPage(extension))
445 DecrementLazyKeepaliveCount(extension->id());
448 // This implementation layers on top of the keepalive count. An impulse sets
449 // a per extension flag. On a regular interval that flag is checked. Changes
450 // from the flag not being set to set cause an IncrementLazyKeepaliveCount.
451 void ProcessManager::KeepaliveImpulse(const Extension* extension) {
452 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
453 return;
455 BackgroundPageData& bd = background_page_data_[extension->id()];
457 if (!bd.keepalive_impulse) {
458 bd.keepalive_impulse = true;
459 if (!bd.previous_keepalive_impulse) {
460 IncrementLazyKeepaliveCount(extension);
464 if (!keepalive_impulse_callback_for_testing_.is_null()) {
465 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
466 keepalive_impulse_callback_for_testing_;
467 callback_may_clear_callbacks_reentrantly.Run(extension->id());
471 // static
472 void ProcessManager::OnKeepaliveFromPlugin(int render_process_id,
473 int render_frame_id,
474 const std::string& extension_id) {
475 content::RenderFrameHost* render_frame_host =
476 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
477 if (!render_frame_host)
478 return;
480 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance();
481 if (!site_instance)
482 return;
484 BrowserContext* browser_context = site_instance->GetBrowserContext();
485 const Extension* extension =
486 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
487 extension_id);
488 if (!extension)
489 return;
491 ProcessManager::Get(browser_context)->KeepaliveImpulse(extension);
494 void ProcessManager::OnShouldSuspendAck(const std::string& extension_id,
495 uint64 sequence_id) {
496 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
497 if (host &&
498 sequence_id == background_page_data_[extension_id].close_sequence_id) {
499 host->render_process_host()->Send(new ExtensionMsg_Suspend(extension_id));
503 void ProcessManager::OnSuspendAck(const std::string& extension_id) {
504 background_page_data_[extension_id].is_closing = true;
505 uint64 sequence_id = background_page_data_[extension_id].close_sequence_id;
506 base::MessageLoop::current()->PostDelayedTask(
507 FROM_HERE,
508 base::Bind(&ProcessManager::CloseLazyBackgroundPageNow,
509 weak_ptr_factory_.GetWeakPtr(),
510 extension_id,
511 sequence_id),
512 base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec));
515 void ProcessManager::OnNetworkRequestStarted(
516 content::RenderFrameHost* render_frame_host,
517 uint64 request_id) {
518 ExtensionHost* host = GetBackgroundHostForExtension(
519 GetExtensionID(render_frame_host));
520 if (host && IsFrameInExtensionHost(host, render_frame_host)) {
521 IncrementLazyKeepaliveCount(host->extension());
522 host->OnNetworkRequestStarted(request_id);
526 void ProcessManager::OnNetworkRequestDone(
527 content::RenderFrameHost* render_frame_host,
528 uint64 request_id) {
529 ExtensionHost* host = GetBackgroundHostForExtension(
530 GetExtensionID(render_frame_host));
531 if (host && IsFrameInExtensionHost(host, render_frame_host)) {
532 host->OnNetworkRequestDone(request_id);
533 DecrementLazyKeepaliveCount(host->extension());
537 void ProcessManager::CancelSuspend(const Extension* extension) {
538 bool& is_closing = background_page_data_[extension->id()].is_closing;
539 ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
540 if (host && is_closing) {
541 is_closing = false;
542 host->render_process_host()->Send(
543 new ExtensionMsg_CancelSuspend(extension->id()));
544 // This increment / decrement is to simulate an instantaneous event. This
545 // has the effect of invalidating close_sequence_id, preventing any in
546 // progress closes from completing and starting a new close process if
547 // necessary.
548 IncrementLazyKeepaliveCount(extension);
549 DecrementLazyKeepaliveCount(extension);
553 void ProcessManager::CloseBackgroundHosts() {
554 STLDeleteElements(&background_hosts_);
557 void ProcessManager::SetKeepaliveImpulseCallbackForTesting(
558 const ImpulseCallbackForTesting& callback) {
559 keepalive_impulse_callback_for_testing_ = callback;
562 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting(
563 const ImpulseCallbackForTesting& callback) {
564 keepalive_impulse_decrement_callback_for_testing_ = callback;
567 // static
568 void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec) {
569 CHECK_GT(idle_time_msec, 0u); // OnKeepaliveImpulseCheck requires non zero.
570 g_event_page_idle_time_msec = idle_time_msec;
573 // static
574 void ProcessManager::SetEventPageSuspendingTimeForTesting(
575 unsigned suspending_time_msec) {
576 g_event_page_suspending_time_msec = suspending_time_msec;
579 ////////////////////////////////////////////////////////////////////////////////
580 // Private
582 void ProcessManager::Observe(int type,
583 const content::NotificationSource& source,
584 const content::NotificationDetails& details) {
585 TRACE_EVENT0("browser,startup", "ProcessManager::Observe");
586 switch (type) {
587 case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED: {
588 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead
589 // of a notification.
590 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.ProcessManagerStartupHostsTime");
591 MaybeCreateStartupBackgroundHosts();
592 break;
594 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
595 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
596 if (background_hosts_.erase(host)) {
597 ClearBackgroundPageData(host->extension()->id());
598 background_page_data_[host->extension()->id()].since_suspended.reset(
599 new base::ElapsedTimer());
601 break;
603 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
604 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
605 if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
606 CloseBackgroundHost(host);
608 break;
610 default:
611 NOTREACHED();
615 void ProcessManager::OnExtensionLoaded(BrowserContext* browser_context,
616 const Extension* extension) {
617 if (ExtensionSystem::Get(browser_context)->ready().is_signaled()) {
618 // The extension system is ready, so create the background host.
619 CreateBackgroundHostForExtensionLoad(this, extension);
623 void ProcessManager::OnExtensionUnloaded(
624 BrowserContext* browser_context,
625 const Extension* extension,
626 UnloadedExtensionInfo::Reason reason) {
627 ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
628 if (host != nullptr)
629 CloseBackgroundHost(host);
630 UnregisterExtension(extension->id());
633 void ProcessManager::CreateStartupBackgroundHosts() {
634 DCHECK(!startup_background_hosts_created_);
635 for (const scoped_refptr<const Extension>& extension :
636 extension_registry_->enabled_extensions()) {
637 CreateBackgroundHostForExtensionLoad(this, extension.get());
638 FOR_EACH_OBSERVER(ProcessManagerObserver,
639 observer_list_,
640 OnBackgroundHostStartup(extension.get()));
644 void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) {
645 DCHECK_EQ(browser_context_, host->browser_context());
646 background_hosts_.insert(host);
648 if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) {
649 linked_ptr<base::ElapsedTimer> since_suspended(
650 background_page_data_[host->extension()->id()].
651 since_suspended.release());
652 if (since_suspended.get()) {
653 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
654 since_suspended->Elapsed());
657 FOR_EACH_OBSERVER(ProcessManagerObserver, observer_list_,
658 OnBackgroundHostCreated(host));
661 void ProcessManager::CloseBackgroundHost(ExtensionHost* host) {
662 ExtensionId extension_id = host->extension_id();
663 CHECK(host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
664 delete host;
665 // |host| should deregister itself from our structures.
666 CHECK(background_hosts_.find(host) == background_hosts_.end());
668 FOR_EACH_OBSERVER(ProcessManagerObserver,
669 observer_list_,
670 OnBackgroundHostClose(extension_id));
673 void ProcessManager::AcquireLazyKeepaliveCountForFrame(
674 content::RenderFrameHost* render_frame_host) {
675 ExtensionRenderFrames::iterator it =
676 all_extension_frames_.find(render_frame_host);
677 if (it == all_extension_frames_.end())
678 return;
680 ExtensionRenderFrameData& data = it->second;
681 if (data.CanKeepalive() && !data.has_keepalive) {
682 const Extension* extension =
683 GetExtensionForRenderFrameHost(render_frame_host);
684 if (extension) {
685 IncrementLazyKeepaliveCount(extension);
686 data.has_keepalive = true;
691 void ProcessManager::ReleaseLazyKeepaliveCountForFrame(
692 content::RenderFrameHost* render_frame_host) {
693 ExtensionRenderFrames::iterator iter =
694 all_extension_frames_.find(render_frame_host);
695 if (iter == all_extension_frames_.end())
696 return;
698 ExtensionRenderFrameData& data = iter->second;
699 if (data.CanKeepalive() && data.has_keepalive) {
700 const Extension* extension =
701 GetExtensionForRenderFrameHost(render_frame_host);
702 if (extension) {
703 DecrementLazyKeepaliveCount(extension);
704 data.has_keepalive = false;
709 void ProcessManager::DecrementLazyKeepaliveCount(
710 const std::string& extension_id) {
711 int& count = background_page_data_[extension_id].lazy_keepalive_count;
712 DCHECK(count > 0 ||
713 !extension_registry_->enabled_extensions().Contains(extension_id));
715 // If we reach a zero keepalive count when the lazy background page is about
716 // to be closed, incrementing close_sequence_id will cancel the close
717 // sequence and cause the background page to linger. So check is_closing
718 // before initiating another close sequence.
719 if (--count == 0 && !background_page_data_[extension_id].is_closing) {
720 background_page_data_[extension_id].close_sequence_id =
721 ++last_background_close_sequence_id_;
722 base::MessageLoop::current()->PostDelayedTask(
723 FROM_HERE,
724 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle,
725 weak_ptr_factory_.GetWeakPtr(),
726 extension_id,
727 last_background_close_sequence_id_),
728 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec));
732 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse
733 // have been made for at least g_event_page_idle_time_msec. In the best case an
734 // impulse was made just before being cleared, and the decrement will occur
735 // g_event_page_idle_time_msec later, causing a 2 * g_event_page_idle_time_msec
736 // total time for extension to be shut down based on impulses. Worst case is
737 // an impulse just after a clear, adding one check cycle and resulting in 3x
738 // total time.
739 void ProcessManager::OnKeepaliveImpulseCheck() {
740 for (BackgroundPageDataMap::iterator i = background_page_data_.begin();
741 i != background_page_data_.end();
742 ++i) {
743 if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) {
744 DecrementLazyKeepaliveCount(i->first);
745 if (!keepalive_impulse_decrement_callback_for_testing_.is_null()) {
746 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
747 keepalive_impulse_decrement_callback_for_testing_;
748 callback_may_clear_callbacks_reentrantly.Run(i->first);
752 i->second.previous_keepalive_impulse = i->second.keepalive_impulse;
753 i->second.keepalive_impulse = false;
756 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit
757 // tests there will be no message loop. In that event don't schedule tasks.
758 if (base::MessageLoop::current()) {
759 base::MessageLoop::current()->PostDelayedTask(
760 FROM_HERE,
761 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck,
762 weak_ptr_factory_.GetWeakPtr()),
763 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec));
767 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id,
768 uint64 sequence_id) {
769 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
770 if (host && !background_page_data_[extension_id].is_closing &&
771 sequence_id == background_page_data_[extension_id].close_sequence_id) {
772 // Tell the renderer we are about to close. This is a simple ping that the
773 // renderer will respond to. The purpose is to control sequencing: if the
774 // extension remains idle until the renderer responds with an ACK, then we
775 // know that the extension process is ready to shut down. If our
776 // close_sequence_id has already changed, then we would ignore the
777 // ShouldSuspendAck, so we don't send the ping.
778 host->render_process_host()->Send(new ExtensionMsg_ShouldSuspend(
779 extension_id, sequence_id));
783 void ProcessManager::OnLazyBackgroundPageActive(
784 const std::string& extension_id) {
785 if (!background_page_data_[extension_id].is_closing) {
786 // Cancel the current close sequence by changing the close_sequence_id,
787 // which causes us to ignore the next ShouldSuspendAck.
788 background_page_data_[extension_id].close_sequence_id =
789 ++last_background_close_sequence_id_;
793 void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id,
794 uint64 sequence_id) {
795 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
796 if (host &&
797 sequence_id == background_page_data_[extension_id].close_sequence_id) {
798 // Close remaining views.
799 std::vector<content::RenderFrameHost*> frames_to_close;
800 for (const auto& key_value : all_extension_frames_) {
801 if (key_value.second.CanKeepalive() &&
802 GetExtensionID(key_value.first) == extension_id) {
803 DCHECK(!key_value.second.has_keepalive);
804 frames_to_close.push_back(key_value.first);
807 for (content::RenderFrameHost* frame : frames_to_close) {
808 frame->GetRenderViewHost()->ClosePage();
809 // RenderViewHost::ClosePage() may result in calling
810 // UnregisterRenderViewHost() asynchronously and may cause race conditions
811 // when the background page is reloaded.
812 // To avoid this, unregister the view now.
813 UnregisterRenderFrameHost(frame);
816 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
817 if (host)
818 CloseBackgroundHost(host);
822 void ProcessManager::OnDevToolsStateChanged(
823 content::DevToolsAgentHost* agent_host,
824 bool attached) {
825 content::WebContents* web_contents = agent_host->GetWebContents();
826 // Ignore unrelated notifications.
827 if (!web_contents || web_contents->GetBrowserContext() != browser_context_)
828 return;
829 if (GetViewType(web_contents) != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
830 return;
831 const Extension* extension =
832 extension_registry_->enabled_extensions().GetByID(
833 GetExtensionIdForSiteInstance(web_contents->GetSiteInstance()));
834 if (!extension)
835 return;
836 if (attached) {
837 // Keep the lazy background page alive while it's being inspected.
838 CancelSuspend(extension);
839 IncrementLazyKeepaliveCount(extension);
840 } else {
841 DecrementLazyKeepaliveCount(extension);
845 void ProcessManager::UnregisterExtension(const std::string& extension_id) {
846 // The lazy_keepalive_count may be greater than zero at this point because
847 // RenderFrameHosts are still alive. During extension reloading, they will
848 // decrement the lazy_keepalive_count to negative for the new extension
849 // instance when they are destroyed. Since we are erasing the background page
850 // data for the unloaded extension, unregister the RenderFrameHosts too.
851 for (ExtensionRenderFrames::iterator it = all_extension_frames_.begin();
852 it != all_extension_frames_.end(); ) {
853 content::RenderFrameHost* host = it->first;
854 if (GetExtensionID(host) == extension_id) {
855 all_extension_frames_.erase(it++);
856 FOR_EACH_OBSERVER(ProcessManagerObserver,
857 observer_list_,
858 OnExtensionFrameUnregistered(extension_id, host));
859 } else {
860 ++it;
864 background_page_data_.erase(extension_id);
867 void ProcessManager::ClearBackgroundPageData(const std::string& extension_id) {
868 background_page_data_.erase(extension_id);
870 // Re-register all RenderViews for this extension. We do this to restore
871 // the lazy_keepalive_count (if any) to properly reflect the number of open
872 // views.
873 for (const auto& key_value : all_extension_frames_) {
874 // Do not increment the count when |has_keepalive| is false
875 // (i.e. ReleaseLazyKeepaliveCountForView() was called).
876 if (GetExtensionID(key_value.first) == extension_id &&
877 key_value.second.has_keepalive) {
878 const Extension* extension =
879 GetExtensionForRenderFrameHost(key_value.first);
880 if (extension)
881 IncrementLazyKeepaliveCount(extension);
887 // IncognitoProcessManager
890 IncognitoProcessManager::IncognitoProcessManager(
891 BrowserContext* incognito_context,
892 BrowserContext* original_context,
893 ExtensionRegistry* extension_registry)
894 : ProcessManager(incognito_context, original_context, extension_registry) {
895 DCHECK(incognito_context->IsOffTheRecord());
898 bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension,
899 const GURL& url) {
900 if (IncognitoInfo::IsSplitMode(extension)) {
901 if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled(
902 extension->id(), browser_context()))
903 return ProcessManager::CreateBackgroundHost(extension, url);
904 } else {
905 // Do nothing. If an extension is spanning, then its original-profile
906 // background page is shared with incognito, so we don't create another.
908 return false;
911 scoped_refptr<content::SiteInstance>
912 IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) {
913 const Extension* extension =
914 extension_registry_->enabled_extensions().GetExtensionOrAppByURL(url);
915 if (extension && !IncognitoInfo::IsSplitMode(extension)) {
916 BrowserContext* original_context =
917 ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context());
918 return ProcessManager::Get(original_context)->GetSiteInstanceForURL(url);
921 return ProcessManager::GetSiteInstanceForURL(url);
924 } // namespace extensions