Home | History | Annotate | Download | only in browser
      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.
      4 
      5 #include "extensions/browser/process_manager.h"
      6 
      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.h"
     13 #include "base/stl_util.h"
     14 #include "base/strings/string_number_conversions.h"
     15 #include "base/time/time.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "content/public/browser/browser_context.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "content/public/browser/devtools_agent_host.h"
     20 #include "content/public/browser/devtools_manager.h"
     21 #include "content/public/browser/notification_service.h"
     22 #include "content/public/browser/render_frame_host.h"
     23 #include "content/public/browser/render_process_host.h"
     24 #include "content/public/browser/render_view_host.h"
     25 #include "content/public/browser/site_instance.h"
     26 #include "content/public/browser/web_contents.h"
     27 #include "content/public/browser/web_contents_delegate.h"
     28 #include "content/public/browser/web_contents_observer.h"
     29 #include "content/public/browser/web_contents_user_data.h"
     30 #include "content/public/common/renderer_preferences.h"
     31 #include "content/public/common/url_constants.h"
     32 #include "extensions/browser/extension_host.h"
     33 #include "extensions/browser/extension_registry.h"
     34 #include "extensions/browser/extension_system.h"
     35 #include "extensions/browser/extensions_browser_client.h"
     36 #include "extensions/browser/process_manager_observer.h"
     37 #include "extensions/browser/view_type_utils.h"
     38 #include "extensions/common/constants.h"
     39 #include "extensions/common/extension.h"
     40 #include "extensions/common/extension_messages.h"
     41 #include "extensions/common/manifest_handlers/background_info.h"
     42 #include "extensions/common/manifest_handlers/incognito_info.h"
     43 #include "extensions/common/one_shot_event.h"
     44 #include "extensions/common/switches.h"
     45 
     46 using content::BrowserContext;
     47 using content::RenderViewHost;
     48 using content::SiteInstance;
     49 using content::WebContents;
     50 
     51 namespace extensions {
     52 class RenderViewHostDestructionObserver;
     53 }
     54 DEFINE_WEB_CONTENTS_USER_DATA_KEY(
     55     extensions::RenderViewHostDestructionObserver);
     56 
     57 namespace extensions {
     58 
     59 namespace {
     60 
     61 std::string GetExtensionID(RenderViewHost* render_view_host) {
     62   // This works for both apps and extensions because the site has been
     63   // normalized to the extension URL for hosted apps.
     64   content::SiteInstance* site_instance = render_view_host->GetSiteInstance();
     65   if (!site_instance)
     66     return std::string();
     67 
     68   const GURL& site_url = site_instance->GetSiteURL();
     69 
     70   if (!site_url.SchemeIs(kExtensionScheme) &&
     71       !site_url.SchemeIs(content::kGuestScheme))
     72     return std::string();
     73 
     74   return site_url.host();
     75 }
     76 
     77 std::string GetExtensionIDFromFrame(
     78     content::RenderFrameHost* render_frame_host) {
     79   // This works for both apps and extensions because the site has been
     80   // normalized to the extension URL for apps.
     81   if (!render_frame_host->GetSiteInstance())
     82     return std::string();
     83 
     84   return render_frame_host->GetSiteInstance()->GetSiteURL().host();
     85 }
     86 
     87 bool IsFrameInExtensionHost(ExtensionHost* extension_host,
     88                             content::RenderFrameHost* render_frame_host) {
     89   return WebContents::FromRenderFrameHost(render_frame_host) ==
     90       extension_host->host_contents();
     91 }
     92 
     93 void OnRenderViewHostUnregistered(BrowserContext* context,
     94                                   RenderViewHost* render_view_host) {
     95   content::NotificationService::current()->Notify(
     96       chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
     97       content::Source<BrowserContext>(context),
     98       content::Details<RenderViewHost>(render_view_host));
     99 }
    100 
    101 // Incognito profiles use this process manager. It is mostly a shim that decides
    102 // whether to fall back on the original profile's ProcessManager based
    103 // on whether a given extension uses "split" or "spanning" incognito behavior.
    104 class IncognitoProcessManager : public ProcessManager {
    105  public:
    106   IncognitoProcessManager(BrowserContext* incognito_context,
    107                           BrowserContext* original_context,
    108                           ProcessManager* original_manager);
    109   virtual ~IncognitoProcessManager() {}
    110   virtual bool CreateBackgroundHost(const Extension* extension,
    111                                     const GURL& url) OVERRIDE;
    112   virtual SiteInstance* GetSiteInstanceForURL(const GURL& url) OVERRIDE;
    113 
    114  private:
    115   ProcessManager* original_manager_;
    116 
    117   DISALLOW_COPY_AND_ASSIGN(IncognitoProcessManager);
    118 };
    119 
    120 static void CreateBackgroundHostForExtensionLoad(
    121     ProcessManager* manager, const Extension* extension) {
    122   DVLOG(1) << "CreateBackgroundHostForExtensionLoad";
    123   if (BackgroundInfo::HasPersistentBackgroundPage(extension))
    124     manager->CreateBackgroundHost(extension,
    125                                   BackgroundInfo::GetBackgroundURL(extension));
    126 }
    127 
    128 }  // namespace
    129 
    130 class RenderViewHostDestructionObserver
    131     : public content::WebContentsObserver,
    132       public content::WebContentsUserData<RenderViewHostDestructionObserver> {
    133  public:
    134   virtual ~RenderViewHostDestructionObserver() {}
    135 
    136  private:
    137   explicit RenderViewHostDestructionObserver(WebContents* web_contents)
    138       : WebContentsObserver(web_contents) {
    139     BrowserContext* context = web_contents->GetBrowserContext();
    140     process_manager_ = ExtensionSystem::Get(context)->process_manager();
    141   }
    142 
    143   friend class content::WebContentsUserData<RenderViewHostDestructionObserver>;
    144 
    145   // content::WebContentsObserver overrides.
    146   virtual void RenderViewDeleted(RenderViewHost* render_view_host) OVERRIDE {
    147     process_manager_->UnregisterRenderViewHost(render_view_host);
    148   }
    149 
    150   ProcessManager* process_manager_;
    151 
    152   DISALLOW_COPY_AND_ASSIGN(RenderViewHostDestructionObserver);
    153 };
    154 
    155 struct ProcessManager::BackgroundPageData {
    156   // The count of things keeping the lazy background page alive.
    157   int lazy_keepalive_count;
    158 
    159   // Tracks if an impulse event has occured since the last polling check.
    160   bool keepalive_impulse;
    161   bool previous_keepalive_impulse;
    162 
    163   // This is used with the ShouldSuspend message, to ensure that the extension
    164   // remained idle between sending the message and receiving the ack.
    165   int close_sequence_id;
    166 
    167   // True if the page responded to the ShouldSuspend message and is currently
    168   // dispatching the suspend event. During this time any events that arrive will
    169   // cancel the suspend process and an onSuspendCanceled event will be
    170   // dispatched to the page.
    171   bool is_closing;
    172 
    173   // Keeps track of when this page was last suspended. Used for perf metrics.
    174   linked_ptr<base::ElapsedTimer> since_suspended;
    175 
    176   BackgroundPageData()
    177       : lazy_keepalive_count(0),
    178         keepalive_impulse(false),
    179         previous_keepalive_impulse(false),
    180         close_sequence_id(0),
    181         is_closing(false) {}
    182 };
    183 
    184 //
    185 // ProcessManager
    186 //
    187 
    188 // static
    189 ProcessManager* ProcessManager::Create(BrowserContext* context) {
    190   ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
    191   if (client->IsGuestSession(context)) {
    192     // In the guest session, there is a single off-the-record context.  Unlike
    193     // a regular incognito mode, background pages of extensions must be
    194     // created regardless of whether extensions use "spanning" or "split"
    195     // incognito behavior.
    196     BrowserContext* original_context = client->GetOriginalContext(context);
    197     return new ProcessManager(context, original_context);
    198   }
    199 
    200   if (context->IsOffTheRecord()) {
    201     BrowserContext* original_context = client->GetOriginalContext(context);
    202     ProcessManager* original_manager =
    203         ExtensionSystem::Get(original_context)->process_manager();
    204     return new IncognitoProcessManager(
    205         context, original_context, original_manager);
    206   }
    207 
    208   return new ProcessManager(context, context);
    209 }
    210 
    211 // static
    212 ProcessManager* ProcessManager::CreateIncognitoForTesting(
    213     BrowserContext* incognito_context,
    214     BrowserContext* original_context,
    215     ProcessManager* original_manager) {
    216   DCHECK(incognito_context->IsOffTheRecord());
    217   DCHECK(!original_context->IsOffTheRecord());
    218   return new IncognitoProcessManager(
    219       incognito_context, original_context, original_manager);
    220 }
    221 
    222 ProcessManager::ProcessManager(BrowserContext* context,
    223                                BrowserContext* original_context)
    224   : site_instance_(SiteInstance::Create(context)),
    225     startup_background_hosts_created_(false),
    226     devtools_callback_(base::Bind(
    227         &ProcessManager::OnDevToolsStateChanged,
    228         base::Unretained(this))),
    229     weak_ptr_factory_(this) {
    230   registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
    231                  content::Source<BrowserContext>(original_context));
    232   registrar_.Add(this,
    233                  chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
    234                  content::Source<BrowserContext>(original_context));
    235   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
    236                  content::Source<BrowserContext>(original_context));
    237   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
    238                  content::Source<BrowserContext>(context));
    239   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
    240                  content::Source<BrowserContext>(context));
    241   registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
    242                  content::NotificationService::AllSources());
    243   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
    244                  content::NotificationService::AllSources());
    245   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
    246                  content::Source<BrowserContext>(original_context));
    247   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
    248                  content::Source<BrowserContext>(context));
    249   if (context->IsOffTheRecord()) {
    250     registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
    251                    content::Source<BrowserContext>(original_context));
    252   }
    253 
    254   // Note: event_page_idle_time_ must be sufficiently larger (e.g. 2x) than
    255   // kKeepaliveThrottleIntervalInSeconds in ppapi/proxy/plugin_globals.
    256   event_page_idle_time_ = base::TimeDelta::FromSeconds(10);
    257   unsigned idle_time_msec = 0;
    258   if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    259           extensions::switches::kEventPageIdleTime), &idle_time_msec)) {
    260     CHECK_GT(idle_time_msec, 0u);  // OnKeepaliveImpulseCheck requires non zero.
    261     event_page_idle_time_ = base::TimeDelta::FromMilliseconds(idle_time_msec);
    262   }
    263   event_page_suspending_time_ = base::TimeDelta::FromSeconds(5);
    264   unsigned suspending_time_msec = 0;
    265   if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    266                              extensions::switches::kEventPageSuspendingTime),
    267                          &suspending_time_msec)) {
    268     event_page_suspending_time_ =
    269         base::TimeDelta::FromMilliseconds(suspending_time_msec);
    270   }
    271 
    272   content::DevToolsManager::GetInstance()->AddAgentStateCallback(
    273       devtools_callback_);
    274 
    275   OnKeepaliveImpulseCheck();
    276 }
    277 
    278 ProcessManager::~ProcessManager() {
    279   CloseBackgroundHosts();
    280   DCHECK(background_hosts_.empty());
    281   content::DevToolsManager::GetInstance()->RemoveAgentStateCallback(
    282       devtools_callback_);
    283 }
    284 
    285 const ProcessManager::ViewSet ProcessManager::GetAllViews() const {
    286   ViewSet result;
    287   for (ExtensionRenderViews::const_iterator iter =
    288            all_extension_views_.begin();
    289        iter != all_extension_views_.end(); ++iter) {
    290     result.insert(iter->first);
    291   }
    292   return result;
    293 }
    294 
    295 void ProcessManager::AddObserver(ProcessManagerObserver* observer) {
    296   observer_list_.AddObserver(observer);
    297 }
    298 
    299 void ProcessManager::RemoveObserver(ProcessManagerObserver* observer) {
    300   observer_list_.RemoveObserver(observer);
    301 }
    302 
    303 bool ProcessManager::CreateBackgroundHost(const Extension* extension,
    304                                           const GURL& url) {
    305   // Hosted apps are taken care of from BackgroundContentsService. Ignore them
    306   // here.
    307   if (extension->is_hosted_app() ||
    308       !ExtensionsBrowserClient::Get()->
    309           IsBackgroundPageAllowed(GetBrowserContext())) {
    310     return false;
    311   }
    312 
    313   // Don't create multiple background hosts for an extension.
    314   if (GetBackgroundHostForExtension(extension->id()))
    315     return true;  // TODO(kalman): return false here? It might break things...
    316 
    317   ExtensionHost* host =
    318       new ExtensionHost(extension, GetSiteInstanceForURL(url), url,
    319                         VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
    320   host->CreateRenderViewSoon();
    321   OnBackgroundHostCreated(host);
    322   return true;
    323 }
    324 
    325 ExtensionHost* ProcessManager::GetBackgroundHostForExtension(
    326     const std::string& extension_id) {
    327   for (ExtensionHostSet::iterator iter = background_hosts_.begin();
    328        iter != background_hosts_.end(); ++iter) {
    329     ExtensionHost* host = *iter;
    330     if (host->extension_id() == extension_id)
    331       return host;
    332   }
    333   return NULL;
    334 }
    335 
    336 std::set<RenderViewHost*> ProcessManager::GetRenderViewHostsForExtension(
    337     const std::string& extension_id) {
    338   std::set<RenderViewHost*> result;
    339 
    340   SiteInstance* site_instance = GetSiteInstanceForURL(
    341       Extension::GetBaseURLFromExtensionId(extension_id));
    342   if (!site_instance)
    343     return result;
    344 
    345   // Gather up all the views for that site.
    346   for (ExtensionRenderViews::iterator view = all_extension_views_.begin();
    347        view != all_extension_views_.end(); ++view) {
    348     if (view->first->GetSiteInstance() == site_instance)
    349       result.insert(view->first);
    350   }
    351 
    352   return result;
    353 }
    354 
    355 const Extension* ProcessManager::GetExtensionForRenderViewHost(
    356     RenderViewHost* render_view_host) {
    357   if (!render_view_host->GetSiteInstance())
    358     return NULL;
    359 
    360   ExtensionRegistry* registry = ExtensionRegistry::Get(GetBrowserContext());
    361   if (!registry)
    362     return NULL;
    363 
    364   return registry->enabled_extensions().GetByID(
    365       GetExtensionID(render_view_host));
    366 }
    367 
    368 void ProcessManager::UnregisterRenderViewHost(
    369     RenderViewHost* render_view_host) {
    370   ExtensionRenderViews::iterator view =
    371       all_extension_views_.find(render_view_host);
    372   if (view == all_extension_views_.end())
    373     return;
    374 
    375   OnRenderViewHostUnregistered(GetBrowserContext(), render_view_host);
    376   ViewType view_type = view->second;
    377   all_extension_views_.erase(view);
    378 
    379   // Keepalive count, balanced in RegisterRenderViewHost.
    380   if (view_type != VIEW_TYPE_INVALID &&
    381       view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
    382     const Extension* extension = GetExtensionForRenderViewHost(
    383         render_view_host);
    384     if (extension)
    385       DecrementLazyKeepaliveCount(extension);
    386   }
    387 }
    388 
    389 bool ProcessManager::RegisterRenderViewHost(RenderViewHost* render_view_host) {
    390   const Extension* extension = GetExtensionForRenderViewHost(
    391       render_view_host);
    392   if (!extension)
    393     return false;
    394 
    395   WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host);
    396   all_extension_views_[render_view_host] = GetViewType(web_contents);
    397 
    398   // Keep the lazy background page alive as long as any non-background-page
    399   // extension views are visible. Keepalive count balanced in
    400   // UnregisterRenderViewHost.
    401   IncrementLazyKeepaliveCountForView(render_view_host);
    402   return true;
    403 }
    404 
    405 SiteInstance* ProcessManager::GetSiteInstanceForURL(const GURL& url) {
    406   return site_instance_->GetRelatedSiteInstance(url);
    407 }
    408 
    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);
    412 }
    413 
    414 int ProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
    415   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    416     return 0;
    417 
    418   return background_page_data_[extension->id()].lazy_keepalive_count;
    419 }
    420 
    421 void ProcessManager::IncrementLazyKeepaliveCount(const Extension* extension) {
    422   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    423     return;
    424 
    425   int& count = background_page_data_[extension->id()].lazy_keepalive_count;
    426   if (++count == 1)
    427     OnLazyBackgroundPageActive(extension->id());
    428 }
    429 
    430 void ProcessManager::DecrementLazyKeepaliveCount(const Extension* extension) {
    431   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    432     return;
    433   DecrementLazyKeepaliveCount(extension->id());
    434 }
    435 
    436 void ProcessManager::DecrementLazyKeepaliveCount(
    437     const std::string& extension_id) {
    438   int& count = background_page_data_[extension_id].lazy_keepalive_count;
    439   DCHECK(count > 0 ||
    440          !ExtensionRegistry::Get(GetBrowserContext())
    441               ->enabled_extensions()
    442               .Contains(extension_id));
    443 
    444   // If we reach a zero keepalive count when the lazy background page is about
    445   // to be closed, incrementing close_sequence_id will cancel the close
    446   // sequence and cause the background page to linger. So check is_closing
    447   // before initiating another close sequence.
    448   if (--count == 0 && !background_page_data_[extension_id].is_closing) {
    449     base::MessageLoop::current()->PostDelayedTask(
    450         FROM_HERE,
    451         base::Bind(&ProcessManager::OnLazyBackgroundPageIdle,
    452                    weak_ptr_factory_.GetWeakPtr(), extension_id,
    453                    ++background_page_data_[extension_id].close_sequence_id),
    454         event_page_idle_time_);
    455   }
    456 }
    457 
    458 void ProcessManager::IncrementLazyKeepaliveCountForView(
    459     RenderViewHost* render_view_host) {
    460   WebContents* web_contents =
    461       WebContents::FromRenderViewHost(render_view_host);
    462   ViewType view_type = GetViewType(web_contents);
    463   if (view_type != VIEW_TYPE_INVALID &&
    464       view_type != VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
    465     const Extension* extension = GetExtensionForRenderViewHost(
    466         render_view_host);
    467     if (extension)
    468       IncrementLazyKeepaliveCount(extension);
    469   }
    470 }
    471 
    472 // This implementation layers on top of the keepalive count. An impulse sets
    473 // a per extension flag. On a regular interval that flag is checked. Changes
    474 // from the flag not being set to set cause an IncrementLazyKeepaliveCount.
    475 void ProcessManager::KeepaliveImpulse(const Extension* extension) {
    476   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    477     return;
    478 
    479   BackgroundPageData& bd = background_page_data_[extension->id()];
    480 
    481   if (!bd.keepalive_impulse) {
    482     bd.keepalive_impulse = true;
    483     if (!bd.previous_keepalive_impulse) {
    484       IncrementLazyKeepaliveCount(extension);
    485     }
    486   }
    487 
    488   if (!keepalive_impulse_callback_for_testing_.is_null()) {
    489     ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
    490       keepalive_impulse_callback_for_testing_;
    491     callback_may_clear_callbacks_reentrantly.Run(extension->id());
    492   }
    493 }
    494 
    495 // DecrementLazyKeepaliveCount is called when no calls to KeepaliveImpulse
    496 // have been made for at least event_page_idle_time_. In the best case an
    497 // impulse was made just before being cleared, and the decrement will occur
    498 // event_page_idle_time_ later, causing a 2 * event_page_idle_time_ total time
    499 // for extension to be shut down based on impulses. Worst case is an impulse
    500 // just after a clear, adding one check cycle and resulting in 3x total time.
    501 void ProcessManager::OnKeepaliveImpulseCheck() {
    502   for (BackgroundPageDataMap::iterator i = background_page_data_.begin();
    503        i != background_page_data_.end();
    504        ++i) {
    505     if (i->second.previous_keepalive_impulse && !i->second.keepalive_impulse) {
    506       DecrementLazyKeepaliveCount(i->first);
    507       if (!keepalive_impulse_decrement_callback_for_testing_.is_null()) {
    508         ImpulseCallbackForTesting callback_may_clear_callbacks_reentrantly =
    509           keepalive_impulse_decrement_callback_for_testing_;
    510         callback_may_clear_callbacks_reentrantly.Run(i->first);
    511       }
    512     }
    513 
    514     i->second.previous_keepalive_impulse = i->second.keepalive_impulse;
    515     i->second.keepalive_impulse = false;
    516   }
    517 
    518   // OnKeepaliveImpulseCheck() is always called in constructor, but in unit
    519   // tests there will be no message loop. In that event don't schedule tasks.
    520   if (base::MessageLoop::current()) {
    521     base::MessageLoop::current()->PostDelayedTask(
    522         FROM_HERE,
    523         base::Bind(&ProcessManager::OnKeepaliveImpulseCheck,
    524                    weak_ptr_factory_.GetWeakPtr()),
    525         event_page_idle_time_);
    526   }
    527 }
    528 
    529 void ProcessManager::OnLazyBackgroundPageIdle(const std::string& extension_id,
    530                                               int sequence_id) {
    531   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    532   if (host && !background_page_data_[extension_id].is_closing &&
    533       sequence_id == background_page_data_[extension_id].close_sequence_id) {
    534     // Tell the renderer we are about to close. This is a simple ping that the
    535     // renderer will respond to. The purpose is to control sequencing: if the
    536     // extension remains idle until the renderer responds with an ACK, then we
    537     // know that the extension process is ready to shut down. If our
    538     // close_sequence_id has already changed, then we would ignore the
    539     // ShouldSuspendAck, so we don't send the ping.
    540     host->render_view_host()->Send(new ExtensionMsg_ShouldSuspend(
    541         extension_id, sequence_id));
    542   }
    543 }
    544 
    545 void ProcessManager::OnLazyBackgroundPageActive(
    546     const std::string& extension_id) {
    547   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    548   if (host && !background_page_data_[extension_id].is_closing) {
    549     // Cancel the current close sequence by changing the close_sequence_id,
    550     // which causes us to ignore the next ShouldSuspendAck.
    551     ++background_page_data_[extension_id].close_sequence_id;
    552   }
    553 }
    554 
    555 void ProcessManager::OnShouldSuspendAck(const std::string& extension_id,
    556                                         int sequence_id) {
    557   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    558   if (host &&
    559       sequence_id == background_page_data_[extension_id].close_sequence_id) {
    560     host->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id));
    561   }
    562 }
    563 
    564 void ProcessManager::OnSuspendAck(const std::string& extension_id) {
    565   background_page_data_[extension_id].is_closing = true;
    566   int sequence_id = background_page_data_[extension_id].close_sequence_id;
    567   base::MessageLoop::current()->PostDelayedTask(
    568       FROM_HERE,
    569       base::Bind(&ProcessManager::CloseLazyBackgroundPageNow,
    570                  weak_ptr_factory_.GetWeakPtr(), extension_id, sequence_id),
    571       event_page_suspending_time_);
    572 }
    573 
    574 void ProcessManager::CloseLazyBackgroundPageNow(const std::string& extension_id,
    575                                                 int sequence_id) {
    576   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    577   if (host &&
    578       sequence_id == background_page_data_[extension_id].close_sequence_id) {
    579     ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    580     if (host)
    581       CloseBackgroundHost(host);
    582   }
    583 }
    584 
    585 void ProcessManager::OnNetworkRequestStarted(
    586     content::RenderFrameHost* render_frame_host) {
    587   ExtensionHost* host = GetBackgroundHostForExtension(
    588       GetExtensionIDFromFrame(render_frame_host));
    589   if (host && IsFrameInExtensionHost(host, render_frame_host))
    590     IncrementLazyKeepaliveCount(host->extension());
    591 }
    592 
    593 void ProcessManager::OnNetworkRequestDone(
    594     content::RenderFrameHost* render_frame_host) {
    595   ExtensionHost* host = GetBackgroundHostForExtension(
    596       GetExtensionIDFromFrame(render_frame_host));
    597   if (host && IsFrameInExtensionHost(host, render_frame_host))
    598     DecrementLazyKeepaliveCount(host->extension());
    599 }
    600 
    601 void ProcessManager::CancelSuspend(const Extension* extension) {
    602   bool& is_closing = background_page_data_[extension->id()].is_closing;
    603   ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
    604   if (host && is_closing) {
    605     is_closing = false;
    606     host->render_view_host()->Send(
    607         new ExtensionMsg_CancelSuspend(extension->id()));
    608     // This increment / decrement is to simulate an instantaneous event. This
    609     // has the effect of invalidating close_sequence_id, preventing any in
    610     // progress closes from completing and starting a new close process if
    611     // necessary.
    612     IncrementLazyKeepaliveCount(extension);
    613     DecrementLazyKeepaliveCount(extension);
    614   }
    615 }
    616 
    617 void ProcessManager::OnBrowserWindowReady() {
    618   // If the extension system isn't ready yet the background hosts will be
    619   // created via NOTIFICATION_EXTENSIONS_READY below.
    620   ExtensionSystem* system = ExtensionSystem::Get(GetBrowserContext());
    621   if (!system->ready().is_signaled())
    622     return;
    623 
    624   CreateBackgroundHostsForProfileStartup();
    625 }
    626 
    627 content::BrowserContext* ProcessManager::GetBrowserContext() const {
    628   return site_instance_->GetBrowserContext();
    629 }
    630 
    631 void ProcessManager::SetKeepaliveImpulseCallbackForTesting(
    632     const ImpulseCallbackForTesting& callback) {
    633   keepalive_impulse_callback_for_testing_ = callback;
    634 }
    635 
    636 void ProcessManager::SetKeepaliveImpulseDecrementCallbackForTesting(
    637     const ImpulseCallbackForTesting& callback) {
    638   keepalive_impulse_decrement_callback_for_testing_ = callback;
    639 }
    640 
    641 void ProcessManager::Observe(int type,
    642                              const content::NotificationSource& source,
    643                              const content::NotificationDetails& details) {
    644   switch (type) {
    645     case chrome::NOTIFICATION_EXTENSIONS_READY:
    646     case chrome::NOTIFICATION_PROFILE_CREATED: {
    647        // Don't load background hosts now if the loading should be deferred.
    648        // Instead they will be loaded when a browser window for this profile
    649        // (or an incognito profile from this profile) is ready.
    650        if (DeferLoadingBackgroundHosts())
    651          break;
    652 
    653       CreateBackgroundHostsForProfileStartup();
    654       break;
    655     }
    656 
    657     case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: {
    658       BrowserContext* context = content::Source<BrowserContext>(source).ptr();
    659       ExtensionSystem* system = ExtensionSystem::Get(context);
    660       if (system->ready().is_signaled()) {
    661         // The extension system is ready, so create the background host.
    662         const Extension* extension =
    663             content::Details<const Extension>(details).ptr();
    664         CreateBackgroundHostForExtensionLoad(this, extension);
    665       }
    666       break;
    667     }
    668 
    669     case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
    670       const Extension* extension =
    671           content::Details<UnloadedExtensionInfo>(details)->extension;
    672       for (ExtensionHostSet::iterator iter = background_hosts_.begin();
    673            iter != background_hosts_.end(); ++iter) {
    674         ExtensionHost* host = *iter;
    675         if (host->extension_id() == extension->id()) {
    676           CloseBackgroundHost(host);
    677           break;
    678         }
    679       }
    680       UnregisterExtension(extension->id());
    681       break;
    682     }
    683 
    684     case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
    685       ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
    686       if (background_hosts_.erase(host)) {
    687         ClearBackgroundPageData(host->extension()->id());
    688         background_page_data_[host->extension()->id()].since_suspended.reset(
    689             new base::ElapsedTimer());
    690       }
    691       break;
    692     }
    693 
    694     case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
    695       ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
    696       if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
    697         CloseBackgroundHost(host);
    698       }
    699       break;
    700     }
    701 
    702     case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
    703       // We get this notification both for new WebContents and when one
    704       // has its RenderViewHost replaced (e.g. when a user does a cross-site
    705       // navigation away from an extension URL). For the replaced case, we must
    706       // unregister the old RVH so it doesn't count as an active view that would
    707       // keep the event page alive.
    708       WebContents* contents = content::Source<WebContents>(source).ptr();
    709       if (contents->GetBrowserContext() != GetBrowserContext())
    710         break;
    711 
    712       typedef std::pair<RenderViewHost*, RenderViewHost*> RVHPair;
    713       RVHPair* switched_details = content::Details<RVHPair>(details).ptr();
    714       if (switched_details->first)
    715         UnregisterRenderViewHost(switched_details->first);
    716 
    717       // The above will unregister a RVH when it gets swapped out with a new
    718       // one. However we need to watch the WebContents to know when a RVH is
    719       // deleted because the WebContents has gone away.
    720       if (RegisterRenderViewHost(switched_details->second)) {
    721         RenderViewHostDestructionObserver::CreateForWebContents(contents);
    722       }
    723       break;
    724     }
    725 
    726     case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: {
    727       WebContents* contents = content::Source<WebContents>(source).ptr();
    728       if (contents->GetBrowserContext() != GetBrowserContext())
    729         break;
    730       const Extension* extension = GetExtensionForRenderViewHost(
    731           contents->GetRenderViewHost());
    732       if (!extension)
    733         return;
    734 
    735       // RegisterRenderViewHost is called too early (before the process is
    736       // available), so we need to wait until now to notify.
    737       content::NotificationService::current()->Notify(
    738           chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
    739           content::Source<BrowserContext>(GetBrowserContext()),
    740           content::Details<RenderViewHost>(contents->GetRenderViewHost()));
    741       break;
    742     }
    743 
    744     case chrome::NOTIFICATION_PROFILE_DESTROYED: {
    745       // Close background hosts when the last browser is closed so that they
    746       // have time to shutdown various objects on different threads. Our
    747       // destructor is called too late in the shutdown sequence.
    748       CloseBackgroundHosts();
    749       break;
    750     }
    751 
    752     default:
    753       NOTREACHED();
    754   }
    755 }
    756 
    757 void ProcessManager::OnDevToolsStateChanged(
    758     content::DevToolsAgentHost* agent_host,
    759     bool attached) {
    760   RenderViewHost* rvh = agent_host->GetRenderViewHost();
    761   // Ignore unrelated notifications.
    762   if (!rvh ||
    763       rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() !=
    764           GetBrowserContext())
    765     return;
    766   if (GetViewType(WebContents::FromRenderViewHost(rvh)) !=
    767       VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
    768     return;
    769   const Extension* extension = GetExtensionForRenderViewHost(rvh);
    770   if (!extension)
    771     return;
    772   if (attached) {
    773     // Keep the lazy background page alive while it's being inspected.
    774     CancelSuspend(extension);
    775     IncrementLazyKeepaliveCount(extension);
    776   } else {
    777     DecrementLazyKeepaliveCount(extension);
    778   }
    779 }
    780 
    781 void ProcessManager::CreateBackgroundHostsForProfileStartup() {
    782   if (startup_background_hosts_created_ ||
    783       !ExtensionsBrowserClient::Get()->
    784           IsBackgroundPageAllowed(GetBrowserContext())) {
    785     return;
    786   }
    787 
    788   const ExtensionSet& enabled_extensions =
    789       ExtensionRegistry::Get(GetBrowserContext())->enabled_extensions();
    790   for (ExtensionSet::const_iterator extension = enabled_extensions.begin();
    791        extension != enabled_extensions.end();
    792        ++extension) {
    793     CreateBackgroundHostForExtensionLoad(this, extension->get());
    794 
    795     FOR_EACH_OBSERVER(ProcessManagerObserver,
    796                       observer_list_,
    797                       OnBackgroundHostStartup(*extension));
    798   }
    799   startup_background_hosts_created_ = true;
    800 
    801   // Background pages should only be loaded once. To prevent any further loads
    802   // occurring, we remove the notification listeners.
    803   BrowserContext* original_context =
    804       ExtensionsBrowserClient::Get()->GetOriginalContext(GetBrowserContext());
    805   if (registrar_.IsRegistered(
    806           this,
    807           chrome::NOTIFICATION_PROFILE_CREATED,
    808           content::Source<BrowserContext>(original_context))) {
    809     registrar_.Remove(this,
    810                       chrome::NOTIFICATION_PROFILE_CREATED,
    811                       content::Source<BrowserContext>(original_context));
    812   }
    813   if (registrar_.IsRegistered(
    814           this,
    815           chrome::NOTIFICATION_EXTENSIONS_READY,
    816           content::Source<BrowserContext>(original_context))) {
    817     registrar_.Remove(this,
    818                       chrome::NOTIFICATION_EXTENSIONS_READY,
    819                       content::Source<BrowserContext>(original_context));
    820   }
    821 }
    822 
    823 void ProcessManager::OnBackgroundHostCreated(ExtensionHost* host) {
    824   DCHECK_EQ(GetBrowserContext(), host->browser_context());
    825   background_hosts_.insert(host);
    826 
    827   if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) {
    828     linked_ptr<base::ElapsedTimer> since_suspended(
    829         background_page_data_[host->extension()->id()].
    830             since_suspended.release());
    831     if (since_suspended.get()) {
    832       UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
    833                                since_suspended->Elapsed());
    834     }
    835   }
    836 }
    837 
    838 void ProcessManager::CloseBackgroundHost(ExtensionHost* host) {
    839   CHECK(host->extension_host_type() ==
    840         VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
    841   delete host;
    842   // |host| should deregister itself from our structures.
    843   CHECK(background_hosts_.find(host) == background_hosts_.end());
    844 }
    845 
    846 void ProcessManager::CloseBackgroundHosts() {
    847   for (ExtensionHostSet::iterator iter = background_hosts_.begin();
    848        iter != background_hosts_.end(); ) {
    849     ExtensionHostSet::iterator current = iter++;
    850     delete *current;
    851   }
    852 }
    853 
    854 void ProcessManager::UnregisterExtension(const std::string& extension_id) {
    855   // The lazy_keepalive_count may be greater than zero at this point because
    856   // RenderViewHosts are still alive. During extension reloading, they will
    857   // decrement the lazy_keepalive_count to negative for the new extension
    858   // instance when they are destroyed. Since we are erasing the background page
    859   // data for the unloaded extension, unregister the RenderViewHosts too.
    860   BrowserContext* context = GetBrowserContext();
    861   for (ExtensionRenderViews::iterator it = all_extension_views_.begin();
    862        it != all_extension_views_.end(); ) {
    863     if (GetExtensionID(it->first) == extension_id) {
    864       OnRenderViewHostUnregistered(context, it->first);
    865       all_extension_views_.erase(it++);
    866     } else {
    867       ++it;
    868     }
    869   }
    870 
    871   background_page_data_.erase(extension_id);
    872 }
    873 
    874 void ProcessManager::ClearBackgroundPageData(const std::string& extension_id) {
    875   background_page_data_.erase(extension_id);
    876 
    877   // Re-register all RenderViews for this extension. We do this to restore
    878   // the lazy_keepalive_count (if any) to properly reflect the number of open
    879   // views.
    880   for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin();
    881        it != all_extension_views_.end(); ++it) {
    882     if (GetExtensionID(it->first) == extension_id)
    883       IncrementLazyKeepaliveCountForView(it->first);
    884   }
    885 }
    886 
    887 bool ProcessManager::DeferLoadingBackgroundHosts() const {
    888   // The extensions embedder may have special rules about background hosts.
    889   return ExtensionsBrowserClient::Get()->DeferLoadingBackgroundHosts(
    890       GetBrowserContext());
    891 }
    892 
    893 //
    894 // IncognitoProcessManager
    895 //
    896 
    897 IncognitoProcessManager::IncognitoProcessManager(
    898     BrowserContext* incognito_context,
    899     BrowserContext* original_context,
    900     ProcessManager* original_manager)
    901     : ProcessManager(incognito_context, original_context),
    902       original_manager_(original_manager) {
    903   DCHECK(incognito_context->IsOffTheRecord());
    904 
    905   // The original profile will have its own ProcessManager to
    906   // load the background pages of the spanning extensions. This process
    907   // manager need only worry about the split mode extensions, which is handled
    908   // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler.
    909   registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
    910                     content::Source<BrowserContext>(original_context));
    911   registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CREATED,
    912                     content::Source<BrowserContext>(original_context));
    913 }
    914 
    915 bool IncognitoProcessManager::CreateBackgroundHost(const Extension* extension,
    916                                                    const GURL& url) {
    917   if (IncognitoInfo::IsSplitMode(extension)) {
    918     if (ExtensionsBrowserClient::Get()->IsExtensionIncognitoEnabled(
    919             extension->id(), GetBrowserContext()))
    920       return ProcessManager::CreateBackgroundHost(extension, url);
    921   } else {
    922     // Do nothing. If an extension is spanning, then its original-profile
    923     // background page is shared with incognito, so we don't create another.
    924   }
    925   return false;
    926 }
    927 
    928 SiteInstance* IncognitoProcessManager::GetSiteInstanceForURL(const GURL& url) {
    929   ExtensionRegistry* registry = ExtensionRegistry::Get(GetBrowserContext());
    930   if (registry) {
    931     const Extension* extension =
    932         registry->enabled_extensions().GetExtensionOrAppByURL(url);
    933     if (extension && !IncognitoInfo::IsSplitMode(extension)) {
    934       return original_manager_->GetSiteInstanceForURL(url);
    935     }
    936   }
    937   return ProcessManager::GetSiteInstanceForURL(url);
    938 }
    939 
    940 }  // namespace extensions
    941