[Extensions] Propagate activeTab hosts to extension background pages
[chromium-blink-merge.git] / extensions / browser / process_manager.cc
blob449e33c75c1134bb12caf2f4625e564023d1ba29
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/command_line.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/time/time.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/devtools_agent_host.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/site_instance.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/browser/web_contents_delegate.h"
26 #include "content/public/browser/web_contents_observer.h"
27 #include "content/public/browser/web_contents_user_data.h"
28 #include "content/public/common/renderer_preferences.h"
29 #include "content/public/common/url_constants.h"
30 #include "extensions/browser/extension_host.h"
31 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_system.h"
33 #include "extensions/browser/extensions_browser_client.h"
34 #include "extensions/browser/notification_types.h"
35 #include "extensions/browser/process_manager_delegate.h"
36 #include "extensions/browser/process_manager_factory.h"
37 #include "extensions/browser/process_manager_observer.h"
38 #include "extensions/browser/view_type_utils.h"
39 #include "extensions/common/constants.h"
40 #include "extensions/common/extension.h"
41 #include "extensions/common/extension_messages.h"
42 #include "extensions/common/manifest_handlers/background_info.h"
43 #include "extensions/common/manifest_handlers/incognito_info.h"
44 #include "extensions/common/one_shot_event.h"
46 using content::BrowserContext;
47 using content::RenderViewHost;
48 using content::SiteInstance;
49 using content::WebContents;
51 namespace extensions {
52 class RenderViewHostDestructionObserver;
54 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
55 extensions::RenderViewHostDestructionObserver);
57 namespace extensions {
59 namespace {
61 // The time to delay between an extension becoming idle and
62 // sending a ShouldSuspend message.
63 // Note: Must be sufficiently larger (e.g. 2x) than
64 // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals.
65 unsigned g_event_page_idle_time_msec = 10000;
67 // The time to delay between sending a ShouldSuspend message and
68 // sending a Suspend message.
69 unsigned g_event_page_suspending_time_msec = 5000;
71 std::string GetExtensionID(RenderViewHost* render_view_host) {
72 // This works for both apps and extensions because the site has been
73 // normalized to the extension URL for hosted apps.
74 content::SiteInstance* site_instance = render_view_host->GetSiteInstance();
75 if (!site_instance)
76 return std::string();
78 const GURL& site_url = site_instance->GetSiteURL();
80 if (!site_url.SchemeIs(kExtensionScheme) &&
81 !site_url.SchemeIs(content::kGuestScheme))
82 return std::string();
84 return site_url.host();
87 std::string GetExtensionIDFromFrame(
88 content::RenderFrameHost* render_frame_host) {
89 // This works for both apps and extensions because the site has been
90 // normalized to the extension URL for apps.
91 if (!render_frame_host->GetSiteInstance())
92 return std::string();
94 return render_frame_host->GetSiteInstance()->GetSiteURL().host();
97 bool IsFrameInExtensionHost(ExtensionHost* extension_host,
98 content::RenderFrameHost* render_frame_host) {
99 return WebContents::FromRenderFrameHost(render_frame_host) ==
100 extension_host->host_contents();
103 void OnRenderViewHostUnregistered(BrowserContext* context,
104 RenderViewHost* render_view_host) {
105 content::NotificationService::current()->Notify(
106 extensions::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
107 content::Source<BrowserContext>(context),
108 content::Details<RenderViewHost>(render_view_host));
111 // Incognito profiles use this process manager. It is mostly a shim that decides
112 // whether to fall back on the original profile's ProcessManager based
113 // on whether a given extension uses "split" or "spanning" incognito behavior.
114 class IncognitoProcessManager : public ProcessManager {
115 public:
116 IncognitoProcessManager(BrowserContext* incognito_context,
117 BrowserContext* original_context,
118 ExtensionRegistry* extension_registry);
119 ~IncognitoProcessManager() override {}
120 bool CreateBackgroundHost(const Extension* extension,
121 const GURL& url) override;
122 SiteInstance* GetSiteInstanceForURL(const GURL& url) override;
124 private:
125 DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager);
128 static void CreateBackgroundHostForExtensionLoad(
129 ProcessManager* manager, const Extension* extension) {
130 DVLOG(1) << "CreateBackgroundHostForExtensionLoad";
131 if (BackgroundInfo::HasPersistentBackgroundPage(extension))
132 manager->CreateBackgroundHost(extension,
133 BackgroundInfo::GetBackgroundURL(extension));
136 } // namespace
138 class RenderViewHostDestructionObserver
139 : public content::WebContentsObserver,
140 public content::WebContentsUserData<RenderViewHostDestructionObserver> {
141 public:
142 ~RenderViewHostDestructionObserver() override {}
144 private:
145 explicit RenderViewHostDestructionObserver(WebContents* web_contents)
146 : WebContentsObserver(web_contents) {
147 BrowserContext* context = web_contents->GetBrowserContext();
148 process_manager_ = ProcessManager::Get(context);
151 friend class content::WebContentsUserData<RenderViewHostDestructionObserver>;
153 // content::WebContentsObserver overrides.
154 void RenderViewDeleted(RenderViewHost* render_view_host) override {
155 process_manager_->UnregisterRenderViewHost(render_view_host);
158 ProcessManager* process_manager_;
160 DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver);
163 struct ProcessManager::BackgroundPageData {
164 // The count of things keeping the lazy background page alive.
165 int lazy_keepalive_count;
167 // Tracks if an impulse event has occured since the last polling check.
168 bool keepalive_impulse;
169 bool previous_keepalive_impulse;
171 // True if the page responded to the ShouldSuspend message and is currently
172 // dispatching the suspend event. During this time any events that arrive will
173 // cancel the suspend process and an onSuspendCanceled event will be
174 // dispatched to the page.
175 bool is_closing;
177 // Stores the value of the incremented
178 // ProcessManager::last_background_close_sequence_id_ whenever the extension
179 // is active. A copy of the ID is also passed in the callbacks and IPC
180 // messages leading up to CloseLazyBackgroundPageNow. The process is aborted
181 // if the IDs ever differ due to new activity.
182 uint64 close_sequence_id;
184 // Keeps track of when this page was last suspended. Used for perf metrics.
185 linked_ptr<base::ElapsedTimer> since_suspended;
187 BackgroundPageData()
188 : lazy_keepalive_count(0),
189 keepalive_impulse(false),
190 previous_keepalive_impulse(false),
191 is_closing(false),
192 close_sequence_id(0) {}
195 // Data of a RenderViewHost associated with an extension.
196 struct ProcessManager::ExtensionRenderViewData {
197 // The type of the view.
198 extensions::ViewType view_type;
200 // Whether the view is keeping the lazy background page alive or not.
201 bool has_keepalive;
203 ExtensionRenderViewData()
204 : view_type(VIEW_TYPE_INVALID), has_keepalive(false) {}
206 // Returns whether the view can keep the lazy background page alive or not.
207 bool CanKeepalive() const {
208 switch (view_type) {
209 case VIEW_TYPE_APP_WINDOW:
210 case VIEW_TYPE_BACKGROUND_CONTENTS:
211 case VIEW_TYPE_EXTENSION_DIALOG:
212 case VIEW_TYPE_EXTENSION_INFOBAR:
213 case VIEW_TYPE_EXTENSION_POPUP:
214 case VIEW_TYPE_LAUNCHER_PAGE:
215 case VIEW_TYPE_PANEL:
216 case VIEW_TYPE_TAB_CONTENTS:
217 case VIEW_TYPE_VIRTUAL_KEYBOARD:
218 return true;
220 case VIEW_TYPE_INVALID:
221 case VIEW_TYPE_EXTENSION_BACKGROUND_PAGE:
222 return false;
224 NOTREACHED();
225 return false;
230 // ProcessManager
233 // static
234 ProcessManager* ProcessManager::Get(BrowserContext* context) {
235 return ProcessManagerFactory::GetForBrowserContext(context);
238 // static
239 ProcessManager* ProcessManager::Create(BrowserContext* context) {
240 ExtensionRegistry* extension_registry = ExtensionRegistry::Get(context);
241 ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
242 if (client->IsGuestSession(context)) {
243 // In the guest session, there is a single off-the-record context. Unlike
244 // a regular incognito mode, background pages of extensions must be
245 // created regardless of whether extensions use "spanning" or "split"
246 // incognito behavior.
247 BrowserContext* original_context = client->GetOriginalContext(context);
248 return new ProcessManager(context, original_context, extension_registry);
251 if (context->IsOffTheRecord()) {
252 BrowserContext* original_context = client->GetOriginalContext(context);
253 return new IncognitoProcessManager(
254 context, original_context, extension_registry);
257 return new ProcessManager(context, context, extension_registry);
260 // static
261 ProcessManager* ProcessManager::CreateForTesting(
262 BrowserContext* context,
263 ExtensionRegistry* extension_registry) {
264 DCHECK(!context->IsOffTheRecord());
265 return new ProcessManager(context, context, extension_registry);
268 // static
269 ProcessManager* ProcessManager::CreateIncognitoForTesting(
270 BrowserContext* incognito_context,
271 BrowserContext* original_context,
272 ExtensionRegistry* extension_registry) {
273 DCHECK(incognito_context->IsOffTheRecord());
274 DCHECK(!original_context->IsOffTheRecord());
275 return new IncognitoProcessManager(incognito_context,
276 original_context,
277 extension_registry);
280 ProcessManager::ProcessManager(BrowserContext* context,
281 BrowserContext* original_context,
282 ExtensionRegistry* extension_registry)
283 : site_instance_(SiteInstance::Create(context)),
284 extension_registry_(extension_registry),
285 startup_background_hosts_created_(false),
286 devtools_callback_(base::Bind(&ProcessManager::OnDevToolsStateChanged,
287 base::Unretained(this))),
288 last_background_close_sequence_id_(0),
289 weak_ptr_factory_(this) {
290 // ExtensionRegistry is shared between incognito and regular contexts.
291 DCHECK_EQ(original_context, extension_registry_->browser_context());
292 registrar_.Add(this,
293 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
294 content::Source<BrowserContext>(original_context));
295 registrar_.Add(this,
296 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
297 content::Source<BrowserContext>(original_context));
298 registrar_.Add(this,
299 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
300 content::Source<BrowserContext>(original_context));
301 registrar_.Add(this,
302 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
303 content::Source<BrowserContext>(context));
304 registrar_.Add(this,
305 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
306 content::Source<BrowserContext>(context));
307 registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
308 content::NotificationService::AllSources());
309 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
310 content::NotificationService::AllSources());
312 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_);
314 OnKeepaliveImpulseCheck();
317 ProcessManager::~ProcessManager() {
318 CloseBackgroundHosts();
319 DCHECK(background_hosts_.empty());
320 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_);
323 const ProcessManager::ViewSet ProcessManager::GetAllViews() const {
324 ViewSet result;
325 for (ExtensionRenderViews::const_iterator iter =
326 all_extension_views_.begin();
327 iter != all_extension_views_.end(); ++iter) {
328 result.insert(iter->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(GetBrowserContext()))
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), url,
360 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
361 host->CreateRenderViewSoon();
362 OnBackgroundHostCreated(host);
363 return true;
366 ExtensionHost* ProcessManager::GetBackgroundHostForExtension(
367 const std::string& extension_id) {
368 for (ExtensionHostSet::iterator iter = background_hosts_.begin();
369 iter != background_hosts_.end(); ++iter) {
370 ExtensionHost* host = *iter;
371 if (host->extension_id() == extension_id)
372 return host;
374 return NULL;
377 std::set<RenderViewHost*> ProcessManager::GetRenderViewHostsForExtension(
378 const std::string& extension_id) {
379 std::set<RenderViewHost*> result;
381 scoped_refptr<SiteInstance> site_instance(GetSiteInstanceForURL(
382 Extension::GetBaseURLFromExtensionId(extension_id)));
383 if (!site_instance.get())
384 return result;
386 // Gather up all the views for that site.
387 for (ExtensionRenderViews::iterator view = all_extension_views_.begin();
388 view != all_extension_views_.end(); ++view) {
389 if (view->first->GetSiteInstance() == site_instance)
390 result.insert(view->first);
393 return result;
396 const Extension* ProcessManager::GetExtensionForRenderViewHost(
397 RenderViewHost* render_view_host) {
398 if (!render_view_host->GetSiteInstance())
399 return NULL;
401 return extension_registry_->enabled_extensions().GetByID(
402 GetExtensionID(render_view_host));
405 void ProcessManager::AcquireLazyKeepaliveCountForView(
406 content::RenderViewHost* render_view_host) {
407 auto it = all_extension_views_.find(render_view_host);
408 if (it == all_extension_views_.end())
409 return;
411 ExtensionRenderViewData* data = &it->second;
412 if (data->CanKeepalive() && !data->has_keepalive) {
413 const Extension* extension =
414 GetExtensionForRenderViewHost(render_view_host);
415 if (extension) {
416 IncrementLazyKeepaliveCount(extension);
417 data->has_keepalive = true;
422 void ProcessManager::ReleaseLazyKeepaliveCountForView(
423 content::RenderViewHost* render_view_host) {
424 auto it = all_extension_views_.find(render_view_host);
425 if (it == all_extension_views_.end())
426 return;
428 ExtensionRenderViewData* data = &it->second;
429 if (data->CanKeepalive() && data->has_keepalive) {
430 const Extension* extension =
431 GetExtensionForRenderViewHost(render_view_host);
432 if (extension) {
433 DecrementLazyKeepaliveCount(extension);
434 data->has_keepalive = false;
439 void ProcessManager::UnregisterRenderViewHost(
440 RenderViewHost* render_view_host) {
441 ExtensionRenderViews::iterator view =
442 all_extension_views_.find(render_view_host);
443 if (view == all_extension_views_.end())
444 return;
446 OnRenderViewHostUnregistered(GetBrowserContext(), render_view_host);
448 // Keepalive count, balanced in RegisterRenderViewHost.
449 ReleaseLazyKeepaliveCountForView(render_view_host);
450 all_extension_views_.erase(view);
453 bool ProcessManager::RegisterRenderViewHost(RenderViewHost* render_view_host) {
454 const Extension* extension = GetExtensionForRenderViewHost(
455 render_view_host);
456 if (!extension)
457 return false;
459 WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host);
460 ExtensionRenderViewData* data = &all_extension_views_[render_view_host];
461 data->view_type = GetViewType(web_contents);
463 // Keep the lazy background page alive as long as any non-background-page
464 // extension views are visible. Keepalive count balanced in
465 // UnregisterRenderViewHost.
466 AcquireLazyKeepaliveCountForView(render_view_host);
467 return true;
470 SiteInstance* ProcessManager::GetSiteInstanceForURL(const GURL& url) {
471 return site_instance_->GetRelatedSiteInstance(url);
474 bool ProcessManager::IsBackgroundHostClosing(const std::string& extension_id) {
475 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
476 return (host && background_page_data_[extension_id].is_closing);
479 int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
480 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
481 return 0;
483 return background_page_data_[extension->id()].lazy_keepalive_count;
486 void ProcessManager::IncrementLazyKeepaliveCount(const Extension* extension) {
487 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
488 return;
490 int& count = background_page_data_[extension->id()].lazy_keepalive_count;
491 if (++count == 1)
492 OnLazyBackgroundPageActive(extension->id());
495 void ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) {
496 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
497 return;
498 DecrementLazyKeepaliveCount(extension->id());
501 void ProcessManager::DecrementLazyKeepaliveCount(
502 const std::string& extension_id) {
503 int& count = background_page_data_[extension_id].lazy_keepalive_count;
504 DCHECK(count > 0 ||
505 !extension_registry_->enabled_extensions().Contains(extension_id));
507 // If we reach a zero keepalive count when the lazy background page is about
508 // to be closed, incrementing close_sequence_id will cancel the close
509 // sequence and cause the background page to linger. So check is_closing
510 // before initiating another close sequence.
511 if (--count == 0 && !background_page_data_[extension_id].is_closing) {
512 background_page_data_[extension_id].close_sequence_id =
513 ++last_background_close_sequence_id_;
514 base::MessageLoop::current()->PostDelayedTask(
515 FROM_HERE,
516 base::Bind(&ProcessManager::OnLazyBackgroundPageIdle,
517 weak_ptr_factory_.GetWeakPtr(),
518 extension_id,
519 last_background_close_sequence_id_),
520 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec));
524 // This implementation layers on top of the keepalive count. An impulse sets
525 // a per extension flag. On a regular interval that flag is checked. Changes
526 // from the flag not being set to set cause an IncrementLazyKeepaliveCount.
527 void ProcessManager::KeepaliveImpulse(const Extension* extension) {
528 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
529 return;
531 BackgroundPageData& bd = background_page_data_[extension->id()];
533 if (!bd.keepalive_impulse) {
534 bd.keepalive_impulse = true;
535 if (!bd.previous_keepalive_impulse) {
536 IncrementLazyKeepaliveCount(extension);
540 if (!keepalive_impulse_callback_for_testing_.is_null()) {
541 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
542 keepalive_impulse_callback_for_testing_;
543 callback_may_clear_callbacks_reentrantly.Run(extension->id());
547 // static
548 void ProcessManager::OnKeepaliveFromPlugin(int render_process_id,
549 int render_frame_id,
550 const std::string& extension_id) {
551 content::RenderFrameHost* render_frame_host =
552 content::RenderFrameHost::FromID(render_process_id, render_frame_id);
553 if (!render_frame_host)
554 return;
556 content::SiteInstance* site_instance = render_frame_host->GetSiteInstance();
557 if (!site_instance)
558 return;
560 BrowserContext* browser_context = site_instance->GetBrowserContext();
561 const Extension* extension =
562 ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID(
563 extension_id);
564 if (!extension)
565 return;
567 ProcessManager::Get(browser_context)->KeepaliveImpulse(extension);
570 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse
571 // have been made for at least g_event_page_idle_time_msec. In the best case an
572 // impulse was made just before being cleared, and the decrement will occur
573 // g_event_page_idle_time_msec later, causing a 2 * g_event_page_idle_time_msec
574 // total time for extension to be shut down based on impulses. Worst case is
575 // an impulse just after a clear, adding one check cycle and resulting in 3x
576 // total time.
577 void ProcessManager::OnKeepaliveImpulseCheck() {
578 for (BackgroundPageDataMap::iterator i = background_page_data_.begin();
579 i != background_page_data_.end();
580 ++i) {
581 if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) {
582 DecrementLazyKeepaliveCount(i->first);
583 if (!keepalive_impulse_decrement_callback_for_testing_.is_null()) {
584 ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
585 keepalive_impulse_decrement_callback_for_testing_;
586 callback_may_clear_callbacks_reentrantly.Run(i->first);
590 i->second.previous_keepalive_impulse = i->second.keepalive_impulse;
591 i->second.keepalive_impulse = false;
594 // OnKeepaliveImpulseCheck() is always called in constructor, but in unit
595 // tests there will be no message loop. In that event don't schedule tasks.
596 if (base::MessageLoop::current()) {
597 base::MessageLoop::current()->PostDelayedTask(
598 FROM_HERE,
599 base::Bind(&ProcessManager::OnKeepaliveImpulseCheck,
600 weak_ptr_factory_.GetWeakPtr()),
601 base::TimeDelta::FromMilliseconds(g_event_page_idle_time_msec));
605 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id,
606 uint64 sequence_id) {
607 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
608 if (host && !background_page_data_[extension_id].is_closing &&
609 sequence_id == background_page_data_[extension_id].close_sequence_id) {
610 // Tell the renderer we are about to close. This is a simple ping that the
611 // renderer will respond to. The purpose is to control sequencing: if the
612 // extension remains idle until the renderer responds with an ACK, then we
613 // know that the extension process is ready to shut down. If our
614 // close_sequence_id has already changed, then we would ignore the
615 // ShouldSuspendAck, so we don't send the ping.
616 host->render_view_host()->Send(new ExtensionMsg_ShouldSuspend(
617 extension_id, sequence_id));
621 void ProcessManager::OnLazyBackgroundPageActive(
622 const std::string& extension_id) {
623 if (!background_page_data_[extension_id].is_closing) {
624 // Cancel the current close sequence by changing the close_sequence_id,
625 // which causes us to ignore the next ShouldSuspendAck.
626 background_page_data_[extension_id].close_sequence_id =
627 ++last_background_close_sequence_id_;
631 void ProcessManager::OnShouldSuspendAck(const std::string& extension_id,
632 uint64 sequence_id) {
633 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
634 if (host &&
635 sequence_id == background_page_data_[extension_id].close_sequence_id) {
636 host->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id));
640 void ProcessManager::OnSuspendAck(const std::string& extension_id) {
641 background_page_data_[extension_id].is_closing = true;
642 uint64 sequence_id = background_page_data_[extension_id].close_sequence_id;
643 base::MessageLoop::current()->PostDelayedTask(
644 FROM_HERE,
645 base::Bind(&ProcessManager::CloseLazyBackgroundPageNow,
646 weak_ptr_factory_.GetWeakPtr(),
647 extension_id,
648 sequence_id),
649 base::TimeDelta::FromMilliseconds(g_event_page_suspending_time_msec));
652 void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id,
653 uint64 sequence_id) {
654 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
655 if (host &&
656 sequence_id == background_page_data_[extension_id].close_sequence_id) {
657 // Close remaining views.
658 std::vector<RenderViewHost*> views_to_close;
659 for (const auto& view : all_extension_views_) {
660 if (view.second.CanKeepalive() &&
661 GetExtensionID(view.first) == extension_id) {
662 DCHECK(!view.second.has_keepalive);
663 views_to_close.push_back(view.first);
666 for (auto view : views_to_close) {
667 view->ClosePage();
668 // RenderViewHost::ClosePage() may result in calling
669 // UnregisterRenderViewHost() asynchronously and may cause race conditions
670 // when the background page is reloaded.
671 // To avoid this, unregister the view now.
672 UnregisterRenderViewHost(view);
675 ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
676 if (host)
677 CloseBackgroundHost(host);
681 void ProcessManager::OnNetworkRequestStarted(
682 content::RenderFrameHost* render_frame_host,
683 uint64 request_id) {
684 ExtensionHost* host = GetBackgroundHostForExtension(
685 GetExtensionIDFromFrame(render_frame_host));
686 if (host && IsFrameInExtensionHost(host, render_frame_host)) {
687 IncrementLazyKeepaliveCount(host->extension());
688 host->OnNetworkRequestStarted(request_id);
692 void ProcessManager::OnNetworkRequestDone(
693 content::RenderFrameHost* render_frame_host,
694 uint64 request_id) {
695 ExtensionHost* host = GetBackgroundHostForExtension(
696 GetExtensionIDFromFrame(render_frame_host));
697 if (host && IsFrameInExtensionHost(host, render_frame_host)) {
698 host->OnNetworkRequestDone(request_id);
699 DecrementLazyKeepaliveCount(host->extension());
703 void ProcessManager::CancelSuspend(const Extension* extension) {
704 bool& is_closing = background_page_data_[extension->id()].is_closing;
705 ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
706 if (host && is_closing) {
707 is_closing = false;
708 host->render_view_host()->Send(
709 new ExtensionMsg_CancelSuspend(extension->id()));
710 // This increment / decrement is to simulate an instantaneous event. This
711 // has the effect of invalidating close_sequence_id, preventing any in
712 // progress closes from completing and starting a new close process if
713 // necessary.
714 IncrementLazyKeepaliveCount(extension);
715 DecrementLazyKeepaliveCount(extension);
719 void ProcessManager::CloseBackgroundHosts() {
720 for (ExtensionHostSet::iterator iter = background_hosts_.begin();
721 iter != background_hosts_.end();) {
722 ExtensionHostSet::iterator current = iter++;
723 delete *current;
727 content::BrowserContext* ProcessManager::GetBrowserContext() const {
728 return site_instance_->GetBrowserContext();
731 void ProcessManager::SetKeepaliveImpulseCallbackForTesting(
732 const ImpulseCallbackForTesting& callback) {
733 keepalive_impulse_callback_for_testing_ = callback;
736 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting(
737 const ImpulseCallbackForTesting& callback) {
738 keepalive_impulse_decrement_callback_for_testing_ = callback;
741 // static
742 void ProcessManager::SetEventPageIdleTimeForTesting(unsigned idle_time_msec) {
743 CHECK_GT(idle_time_msec, 0u); // OnKeepaliveImpulseCheck requires non zero.
744 g_event_page_idle_time_msec = idle_time_msec;
747 // static
748 void ProcessManager::SetEventPageSuspendingTimeForTesting(
749 unsigned suspending_time_msec) {
750 g_event_page_suspending_time_msec = suspending_time_msec;
753 void ProcessManager::Observe(int type,
754 const content::NotificationSource& source,
755 const content::NotificationDetails& details) {
756 switch (type) {
757 case extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED: {
758 // TODO(jamescook): Convert this to use ExtensionSystem::ready() instead
759 // of a notification.
760 const base::TimeTicks start_time = base::TimeTicks::Now();
761 MaybeCreateStartupBackgroundHosts();
762 UMA_HISTOGRAM_TIMES("Extensions.ProcessManagerStartupHostsTime",
763 base::TimeTicks::Now() - start_time);
764 break;
767 case extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
768 BrowserContext* context = content::Source<BrowserContext>(source).ptr();
769 ExtensionSystem* system = ExtensionSystem::Get(context);
770 if (system->ready().is_signaled()) {
771 // The extension system is ready, so create the background host.
772 const Extension* extension =
773 content::Details<const Extension>(details).ptr();
774 CreateBackgroundHostForExtensionLoad(this, extension);
776 break;
779 case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
780 const Extension* extension =
781 content::Details<UnloadedExtensionInfo>(details)->extension;
782 for (ExtensionHostSet::iterator iter = background_hosts_.begin();
783 iter != background_hosts_.end(); ++iter) {
784 ExtensionHost* host = *iter;
785 if (host->extension_id() == extension->id()) {
786 CloseBackgroundHost(host);
787 break;
790 UnregisterExtension(extension->id());
791 break;
794 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
795 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
796 if (background_hosts_.erase(host)) {
797 ClearBackgroundPageData(host->extension()->id());
798 background_page_data_[host->extension()->id()].since_suspended.reset(
799 new base::ElapsedTimer());
801 break;
804 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
805 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
806 if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
807 CloseBackgroundHost(host);
809 break;
812 case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
813 // We get this notification both for new WebContents and when one
814 // has its RenderViewHost replaced (e.g. when a user does a cross-site
815 // navigation away from an extension URL). For the replaced case, we must
816 // unregister the old RVH so it doesn't count as an active view that would
817 // keep the event page alive.
818 WebContents* contents = content::Source<WebContents>(source).ptr();
819 if (contents->GetBrowserContext() != GetBrowserContext())
820 break;
822 typedef std::pair<RenderViewHost*, RenderViewHost*> RVHPair;
823 RVHPair* switched_details = content::Details<RVHPair>(details).ptr();
824 if (switched_details->first)
825 UnregisterRenderViewHost(switched_details->first);
827 // The above will unregister a RVH when it gets swapped out with a new
828 // one. However we need to watch the WebContents to know when a RVH is
829 // deleted because the WebContents has gone away.
830 if (RegisterRenderViewHost(switched_details->second)) {
831 RenderViewHostDestructionObserver::CreateForWebContents(contents);
833 break;
836 case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: {
837 WebContents* contents = content::Source<WebContents>(source).ptr();
838 if (contents->GetBrowserContext() != GetBrowserContext())
839 break;
840 const Extension* extension = GetExtensionForRenderViewHost(
841 contents->GetRenderViewHost());
842 if (!extension)
843 return;
845 // RegisterRenderViewHost is called too early (before the process is
846 // available), so we need to wait until now to notify.
847 content::NotificationService::current()->Notify(
848 extensions::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
849 content::Source<BrowserContext>(GetBrowserContext()),
850 content::Details<RenderViewHost>(contents->GetRenderViewHost()));
851 break;
854 default:
855 NOTREACHED();
859 void ProcessManager::OnDevToolsStateChanged(
860 content::DevToolsAgentHost* agent_host,
861 bool attached) {
862 WebContents* web_contents = agent_host->GetWebContents();
863 // Ignore unrelated notifications.
864 if (!web_contents || web_contents->GetBrowserContext() != GetBrowserContext())
865 return;
866 if (GetViewType(web_contents) != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
867 return;
868 const Extension* extension =
869 GetExtensionForRenderViewHost(web_contents->GetRenderViewHost());
870 if (!extension)
871 return;
872 if (attached) {
873 // Keep the lazy background page alive while it's being inspected.
874 CancelSuspend(extension);
875 IncrementLazyKeepaliveCount(extension);
876 } else {
877 DecrementLazyKeepaliveCount(extension);
881 void ProcessManager::MaybeCreateStartupBackgroundHosts() {
882 if (startup_background_hosts_created_)
883 return;
885 // The embedder might disallow background pages entirely.
886 ProcessManagerDelegate* delegate =
887 ExtensionsBrowserClient::Get()->GetProcessManagerDelegate();
888 if (delegate && !delegate->IsBackgroundPageAllowed(GetBrowserContext()))
889 return;
891 // The embedder might want to defer background page loading. For example,
892 // Chrome defers background page loading when it is launched to show the app
893 // list, then triggers a load later when a browser window opens.
894 if (delegate &&
895 delegate->DeferCreatingStartupBackgroundHosts(GetBrowserContext()))
896 return;
898 CreateStartupBackgroundHosts();
899 startup_background_hosts_created_ = true;
901 // Background pages should only be loaded once. To prevent any further loads
902 // occurring, we remove the notification listeners.
903 BrowserContext* original_context =
904 ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext());
905 if (registrar_.IsRegistered(
906 this,
907 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
908 content::Source<BrowserContext>(original_context))) {
909 registrar_.Remove(this,
910 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
911 content::Source<BrowserContext>(original_context));
915 void ProcessManager::CreateStartupBackgroundHosts() {
916 DCHECK(!startup_background_hosts_created_);
917 const ExtensionSet& enabled_extensions =
918 extension_registry_->enabled_extensions();
919 for (ExtensionSet::const_iterator extension = enabled_extensions.begin();
920 extension != enabled_extensions.end();
921 ++extension) {
922 CreateBackgroundHostForExtensionLoad(this, extension->get());
924 FOR_EACH_OBSERVER(ProcessManagerObserver,
925 observer_list_,
926 OnBackgroundHostStartup(extension->get()));
930 void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) {
931 DCHECK_EQ(GetBrowserContext(), host->browser_context());
932 background_hosts_.insert(host);
934 if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) {
935 linked_ptr<base::ElapsedTimer> since_suspended(
936 background_page_data_[host->extension()->id()].
937 since_suspended.release());
938 if (since_suspended.get()) {
939 UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
940 since_suspended->Elapsed());
943 FOR_EACH_OBSERVER(ProcessManagerObserver, observer_list_,
944 OnBackgroundHostCreated(host));
947 void ProcessManager::CloseBackgroundHost(ExtensionHost* host) {
948 ExtensionId extension_id = host->extension_id();
949 CHECK(host->extension_host_type() ==
950 VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
951 delete host;
952 // |host| should deregister itself from our structures.
953 CHECK(background_hosts_.find(host) == background_hosts_.end());
955 FOR_EACH_OBSERVER(ProcessManagerObserver,
956 observer_list_,
957 OnBackgroundHostClose(extension_id));
960 void ProcessManager::UnregisterExtension(const std::string& extension_id) {
961 // The lazy_keepalive_count may be greater than zero at this point because
962 // RenderViewHosts are still alive. During extension reloading, they will
963 // decrement the lazy_keepalive_count to negative for the new extension
964 // instance when they are destroyed. Since we are erasing the background page
965 // data for the unloaded extension, unregister the RenderViewHosts too.
966 BrowserContext* context = GetBrowserContext();
967 for (ExtensionRenderViews::iterator it = all_extension_views_.begin();
968 it != all_extension_views_.end(); ) {
969 if (GetExtensionID(it->first) == extension_id) {
970 OnRenderViewHostUnregistered(context, it->first);
971 all_extension_views_.erase(it++);
972 } else {
973 ++it;
977 background_page_data_.erase(extension_id);
980 void ProcessManager::ClearBackgroundPageData(const std::string& extension_id) {
981 background_page_data_.erase(extension_id);
983 // Re-register all RenderViews for this extension. We do this to restore
984 // the lazy_keepalive_count (if any) to properly reflect the number of open
985 // views.
986 for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin();
987 it != all_extension_views_.end(); ++it) {
988 RenderViewHost* view = it->first;
989 const ExtensionRenderViewData& data = it->second;
990 // Do not increment the count when |has_keepalive| is false
991 // (i.e. ReleaseLazyKeepaliveCountForView() was called).
992 if (GetExtensionID(view) == extension_id && data.has_keepalive) {
993 const Extension* extension = GetExtensionForRenderViewHost(view);
994 if (extension)
995 IncrementLazyKeepaliveCount(extension);
1001 // IncognitoProcessManager
1004 IncognitoProcessManager::IncognitoProcessManager(
1005 BrowserContext* incognito_context,
1006 BrowserContext* original_context,
1007 ExtensionRegistry* extension_registry)
1008 : ProcessManager(incognito_context, original_context, extension_registry) {
1009 DCHECK(incognito_context->IsOffTheRecord());
1011 // The original profile will have its own ProcessManager to
1012 // load the background pages of the spanning extensions. This process
1013 // manager need only worry about the split mode extensions, which is handled
1014 // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler.
1015 registrar_.Remove(this,
1016 extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED,
1017 content::Source<BrowserContext>(original_context));
1020 bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension,
1021 const GURL& url) {
1022 if (IncognitoInfo::IsSplitMode(extension)) {
1023 if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled(
1024 extension->id(), GetBrowserContext()))
1025 return ProcessManager::CreateBackgroundHost(extension, url);
1026 } else {
1027 // Do nothing. If an extension is spanning, then its original-profile
1028 // background page is shared with incognito, so we don't create another.
1030 return false;
1033 SiteInstance* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) {
1034 const Extension* extension =
1035 extension_registry_->enabled_extensions().GetExtensionOrAppByURL(url);
1036 if (extension && !IncognitoInfo::IsSplitMode(extension)) {
1037 BrowserContext* original_context =
1038 ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext());
1039 return ProcessManager::Get(original_context)->GetSiteInstanceForURL(url);
1042 return ProcessManager::GetSiteInstanceForURL(url);
1045 } // namespace extensions