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