Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 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 "chrome/browser/extensions/extension_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/browser_process.h"
     17 #include "chrome/browser/chrome_notification_types.h"
     18 #include "chrome/browser/extensions/api/runtime/runtime_api.h"
     19 #include "chrome/browser/extensions/extension_host.h"
     20 #include "chrome/browser/extensions/extension_info_map.h"
     21 #include "chrome/browser/extensions/extension_service.h"
     22 #include "chrome/browser/extensions/extension_system.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/browser/profiles/profile_manager.h"
     25 #include "chrome/browser/ui/browser.h"
     26 #include "chrome/browser/ui/browser_finder.h"
     27 #include "chrome/common/chrome_switches.h"
     28 #include "chrome/common/extensions/background_info.h"
     29 #include "chrome/common/extensions/extension.h"
     30 #include "chrome/common/extensions/extension_messages.h"
     31 #include "chrome/common/extensions/incognito_handler.h"
     32 #include "chrome/common/extensions/manifest_url_handler.h"
     33 #include "chrome/common/url_constants.h"
     34 #include "content/public/browser/browser_thread.h"
     35 #include "content/public/browser/devtools_agent_host.h"
     36 #include "content/public/browser/devtools_manager.h"
     37 #include "content/public/browser/notification_service.h"
     38 #include "content/public/browser/render_process_host.h"
     39 #include "content/public/browser/render_view_host.h"
     40 #include "content/public/browser/site_instance.h"
     41 #include "content/public/browser/web_contents.h"
     42 #include "content/public/browser/web_contents_delegate.h"
     43 #include "content/public/common/renderer_preferences.h"
     44 #include "extensions/browser/view_type_utils.h"
     45 
     46 #if defined(OS_MACOSX)
     47 #include "chrome/browser/extensions/extension_host_mac.h"
     48 #endif
     49 
     50 using content::RenderViewHost;
     51 using content::SiteInstance;
     52 using content::WebContents;
     53 using extensions::BackgroundInfo;
     54 using extensions::BackgroundManifestHandler;
     55 using extensions::Extension;
     56 using extensions::ExtensionHost;
     57 
     58 namespace {
     59 
     60 std::string GetExtensionID(RenderViewHost* render_view_host) {
     61   // This works for both apps and extensions because the site has been
     62   // normalized to the extension URL for apps.
     63   if (!render_view_host->GetSiteInstance())
     64     return std::string();
     65 
     66   return render_view_host->GetSiteInstance()->GetSiteURL().host();
     67 }
     68 
     69 // Incognito profiles use this process manager. It is mostly a shim that decides
     70 // whether to fall back on the original profile's ExtensionProcessManager based
     71 // on whether a given extension uses "split" or "spanning" incognito behavior.
     72 class IncognitoExtensionProcessManager : public ExtensionProcessManager {
     73  public:
     74   explicit IncognitoExtensionProcessManager(Profile* profile);
     75   virtual ~IncognitoExtensionProcessManager();
     76   virtual ExtensionHost* CreateViewHost(
     77       const Extension* extension,
     78       const GURL& url,
     79       Browser* browser,
     80       extensions::ViewType view_type) OVERRIDE;
     81   virtual void CreateBackgroundHost(const Extension* extension,
     82                                     const GURL& url) OVERRIDE;
     83   virtual SiteInstance* GetSiteInstanceForURL(const GURL& url) OVERRIDE;
     84 
     85  private:
     86   // content::NotificationObserver:
     87   virtual void Observe(int type,
     88                        const content::NotificationSource& source,
     89                        const content::NotificationDetails& details) OVERRIDE;
     90 
     91   // Returns true if the extension is allowed to run in incognito mode.
     92   bool IsIncognitoEnabled(const Extension* extension);
     93 
     94   ExtensionProcessManager* original_manager_;
     95 };
     96 
     97 static void CreateBackgroundHostForExtensionLoad(
     98     ExtensionProcessManager* manager, const Extension* extension) {
     99   if (BackgroundInfo::HasPersistentBackgroundPage(extension))
    100     manager->CreateBackgroundHost(extension,
    101                                   BackgroundInfo::GetBackgroundURL(extension));
    102 }
    103 
    104 }  // namespace
    105 
    106 struct ExtensionProcessManager::BackgroundPageData {
    107   // The count of things keeping the lazy background page alive.
    108   int lazy_keepalive_count;
    109 
    110   // This is used with the ShouldSuspend message, to ensure that the extension
    111   // remained idle between sending the message and receiving the ack.
    112   int close_sequence_id;
    113 
    114   // True if the page responded to the ShouldSuspend message and is currently
    115   // dispatching the suspend event. During this time any events that arrive will
    116   // cancel the suspend process and an onSuspendCanceled event will be
    117   // dispatched to the page.
    118   bool is_closing;
    119 
    120   // Keeps track of when this page was last suspended. Used for perf metrics.
    121   linked_ptr<PerfTimer> since_suspended;
    122 
    123   BackgroundPageData()
    124       : lazy_keepalive_count(0), close_sequence_id(0), is_closing(false) {}
    125 };
    126 
    127 //
    128 // ExtensionProcessManager
    129 //
    130 
    131 // static
    132 ExtensionProcessManager* ExtensionProcessManager::Create(Profile* profile) {
    133   return (profile->IsOffTheRecord()) ?
    134       new IncognitoExtensionProcessManager(profile) :
    135       new ExtensionProcessManager(profile);
    136 }
    137 
    138 ExtensionProcessManager::ExtensionProcessManager(Profile* profile)
    139   : site_instance_(SiteInstance::Create(profile)),
    140     weak_ptr_factory_(this),
    141     devtools_callback_(base::Bind(
    142         &ExtensionProcessManager::OnDevToolsStateChanged,
    143         base::Unretained(this))) {
    144   Profile* original_profile = profile->GetOriginalProfile();
    145   registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
    146                  content::NotificationService::AllSources());
    147   registrar_.Add(this, chrome::NOTIFICATION_EXTENSIONS_READY,
    148                  content::Source<Profile>(original_profile));
    149   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
    150                  content::Source<Profile>(original_profile));
    151   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
    152                  content::Source<Profile>(original_profile));
    153   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
    154                  content::Source<Profile>(profile));
    155   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
    156                  content::Source<Profile>(profile));
    157   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_SWAPPED,
    158                  content::NotificationService::AllSources());
    159   registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_CONNECTED,
    160                  content::NotificationService::AllSources());
    161   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
    162                  content::Source<Profile>(original_profile));
    163   registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
    164                  content::Source<Profile>(profile));
    165   if (profile->IsOffTheRecord()) {
    166     registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
    167                    content::Source<Profile>(original_profile));
    168   }
    169 
    170   event_page_idle_time_ = base::TimeDelta::FromSeconds(10);
    171   unsigned idle_time_sec = 0;
    172   if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    173           switches::kEventPageIdleTime), &idle_time_sec)) {
    174     event_page_idle_time_ = base::TimeDelta::FromSeconds(idle_time_sec);
    175   }
    176   event_page_suspending_time_ = base::TimeDelta::FromSeconds(5);
    177   unsigned suspending_time_sec = 0;
    178   if (base::StringToUint(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    179           switches::kEventPageSuspendingTime), &suspending_time_sec)) {
    180     event_page_suspending_time_ = base::TimeDelta::FromSeconds(
    181         suspending_time_sec);
    182   }
    183 
    184   content::DevToolsManager::GetInstance()->AddAgentStateCallback(
    185       devtools_callback_);
    186 }
    187 
    188 ExtensionProcessManager::~ExtensionProcessManager() {
    189   CloseBackgroundHosts();
    190   DCHECK(background_hosts_.empty());
    191   content::DevToolsManager::GetInstance()->RemoveAgentStateCallback(
    192       devtools_callback_);
    193 }
    194 
    195 const ExtensionProcessManager::ViewSet
    196 ExtensionProcessManager::GetAllViews() const {
    197   ViewSet result;
    198   for (ExtensionRenderViews::const_iterator iter =
    199            all_extension_views_.begin();
    200        iter != all_extension_views_.end(); ++iter) {
    201     result.insert(iter->first);
    202   }
    203   return result;
    204 }
    205 
    206 void ExtensionProcessManager::EnsureBrowserWhenRequired(
    207     Browser* browser,
    208     extensions::ViewType view_type) {
    209   if (!browser) {
    210 #if defined (OS_CHROMEOS)
    211   // On ChromeOS we'll only use ExtensionView, which
    212   // does not use the browser parameter.
    213   // TODO(rkc): Remove all this once we create a new host for
    214   // screensaver extensions (crosbug.com/28211).
    215   DCHECK(view_type == extensions::VIEW_TYPE_EXTENSION_POPUP ||
    216          view_type == extensions::VIEW_TYPE_EXTENSION_DIALOG);
    217 #else
    218   // A NULL browser may only be given for pop-up views.
    219   DCHECK(view_type == extensions::VIEW_TYPE_EXTENSION_POPUP);
    220 #endif
    221   }
    222 }
    223 
    224 ExtensionHost* ExtensionProcessManager::CreateViewHost(
    225     const Extension* extension,
    226     const GURL& url,
    227     Browser* browser,
    228     extensions::ViewType view_type) {
    229   DCHECK(extension);
    230   EnsureBrowserWhenRequired(browser, view_type);
    231   ExtensionHost* host =
    232 #if defined(OS_MACOSX)
    233       new extensions::ExtensionHostMac(
    234           extension, GetSiteInstanceForURL(url), url, view_type);
    235 #else
    236       new ExtensionHost(extension, GetSiteInstanceForURL(url), url, view_type);
    237 #endif
    238   host->CreateView(browser);
    239   OnExtensionHostCreated(host, false);
    240   return host;
    241 }
    242 
    243 ExtensionHost* ExtensionProcessManager::CreateViewHost(
    244     const GURL& url, Browser* browser, extensions::ViewType view_type) {
    245   EnsureBrowserWhenRequired(browser, view_type);
    246   ExtensionService* service = GetProfile()->GetExtensionService();
    247   if (service) {
    248     std::string extension_id = url.host();
    249     if (url.SchemeIs(chrome::kChromeUIScheme) &&
    250         url.host() == chrome::kChromeUIExtensionInfoHost)
    251       extension_id = url.path().substr(1);
    252     const Extension* extension =
    253         service->extensions()->GetByID(extension_id);
    254     if (extension)
    255       return CreateViewHost(extension, url, browser, view_type);
    256   }
    257   return NULL;
    258 }
    259 
    260 ExtensionHost* ExtensionProcessManager::CreatePopupHost(
    261     const Extension* extension, const GURL& url, Browser* browser) {
    262   return CreateViewHost(
    263       extension, url, browser, extensions::VIEW_TYPE_EXTENSION_POPUP);
    264 }
    265 
    266 ExtensionHost* ExtensionProcessManager::CreatePopupHost(
    267     const GURL& url, Browser* browser) {
    268   return CreateViewHost(url, browser, extensions::VIEW_TYPE_EXTENSION_POPUP);
    269 }
    270 
    271 ExtensionHost* ExtensionProcessManager::CreateDialogHost(const GURL& url) {
    272   return CreateViewHost(url, NULL, extensions::VIEW_TYPE_EXTENSION_DIALOG);
    273 }
    274 
    275 ExtensionHost* ExtensionProcessManager::CreateInfobarHost(
    276     const Extension* extension, const GURL& url, Browser* browser) {
    277   return CreateViewHost(
    278       extension, url, browser, extensions::VIEW_TYPE_EXTENSION_INFOBAR);
    279 }
    280 
    281 ExtensionHost* ExtensionProcessManager::CreateInfobarHost(
    282     const GURL& url, Browser* browser) {
    283   return CreateViewHost(url, browser, extensions::VIEW_TYPE_EXTENSION_INFOBAR);
    284 }
    285 
    286 void ExtensionProcessManager::CreateBackgroundHost(
    287     const Extension* extension, const GURL& url) {
    288   // Hosted apps are taken care of from BackgroundContentsService. Ignore them
    289   // here.
    290   if (extension->is_hosted_app())
    291     return;
    292 
    293   // Don't create multiple background hosts for an extension.
    294   if (GetBackgroundHostForExtension(extension->id()))
    295     return;
    296 
    297   ExtensionHost* host =
    298 #if defined(OS_MACOSX)
    299       new extensions::ExtensionHostMac(
    300           extension, GetSiteInstanceForURL(url), url,
    301           extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
    302 #else
    303       new ExtensionHost(extension, GetSiteInstanceForURL(url), url,
    304                         extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
    305 #endif
    306 
    307   host->CreateRenderViewSoon();
    308   OnExtensionHostCreated(host, true);
    309 }
    310 
    311 ExtensionHost* ExtensionProcessManager::GetBackgroundHostForExtension(
    312     const std::string& extension_id) {
    313   for (ExtensionHostSet::iterator iter = background_hosts_.begin();
    314        iter != background_hosts_.end(); ++iter) {
    315     ExtensionHost* host = *iter;
    316     if (host->extension_id() == extension_id)
    317       return host;
    318   }
    319   return NULL;
    320 }
    321 
    322 std::set<RenderViewHost*>
    323     ExtensionProcessManager::GetRenderViewHostsForExtension(
    324         const std::string& extension_id) {
    325   std::set<RenderViewHost*> result;
    326 
    327   SiteInstance* site_instance = GetSiteInstanceForURL(
    328       Extension::GetBaseURLFromExtensionId(extension_id));
    329   if (!site_instance)
    330     return result;
    331 
    332   // Gather up all the views for that site.
    333   for (ExtensionRenderViews::iterator view = all_extension_views_.begin();
    334        view != all_extension_views_.end(); ++view) {
    335     if (view->first->GetSiteInstance() == site_instance)
    336       result.insert(view->first);
    337   }
    338 
    339   return result;
    340 }
    341 
    342 const Extension* ExtensionProcessManager::GetExtensionForRenderViewHost(
    343     content::RenderViewHost* render_view_host) {
    344   if (!render_view_host->GetSiteInstance())
    345     return NULL;
    346 
    347   ExtensionService* service =
    348       extensions::ExtensionSystem::Get(GetProfile())->extension_service();
    349   if (!service)
    350     return NULL;
    351 
    352   return service->extensions()->GetByID(GetExtensionID(render_view_host));
    353 }
    354 
    355 void ExtensionProcessManager::UnregisterRenderViewHost(
    356     RenderViewHost* render_view_host) {
    357   ExtensionRenderViews::iterator view =
    358       all_extension_views_.find(render_view_host);
    359   if (view == all_extension_views_.end())
    360     return;
    361 
    362   content::NotificationService::current()->Notify(
    363       chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
    364       content::Source<Profile>(GetProfile()),
    365       content::Details<RenderViewHost>(render_view_host));
    366 
    367   extensions::ViewType view_type = view->second;
    368   all_extension_views_.erase(view);
    369 
    370   // Keepalive count, balanced in RegisterRenderViewHost.
    371   if (view_type != extensions::VIEW_TYPE_INVALID &&
    372       view_type != extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
    373     const Extension* extension = GetExtensionForRenderViewHost(
    374         render_view_host);
    375     if (extension)
    376       DecrementLazyKeepaliveCount(extension);
    377   }
    378 }
    379 
    380 void ExtensionProcessManager::RegisterRenderViewHost(
    381     RenderViewHost* render_view_host) {
    382   const Extension* extension = GetExtensionForRenderViewHost(
    383       render_view_host);
    384   if (!extension)
    385     return;
    386 
    387   WebContents* web_contents = WebContents::FromRenderViewHost(render_view_host);
    388   all_extension_views_[render_view_host] =
    389       extensions::GetViewType(web_contents);
    390 
    391   // Keep the lazy background page alive as long as any non-background-page
    392   // extension views are visible. Keepalive count balanced in
    393   // UnregisterRenderViewHost.
    394   IncrementLazyKeepaliveCountForView(render_view_host);
    395 }
    396 
    397 SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) {
    398   return site_instance_->GetRelatedSiteInstance(url);
    399 }
    400 
    401 bool ExtensionProcessManager::IsBackgroundHostClosing(
    402     const std::string& extension_id) {
    403   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    404   return (host && background_page_data_[extension_id].is_closing);
    405 }
    406 
    407 int ExtensionProcessManager::GetLazyKeepaliveCount(const Extension* extension) {
    408   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    409     return 0;
    410 
    411   return background_page_data_[extension->id()].lazy_keepalive_count;
    412 }
    413 
    414 int ExtensionProcessManager::IncrementLazyKeepaliveCount(
    415      const Extension* extension) {
    416   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    417     return 0;
    418 
    419   int& count = background_page_data_[extension->id()].lazy_keepalive_count;
    420   if (++count == 1)
    421     OnLazyBackgroundPageActive(extension->id());
    422 
    423   return count;
    424 }
    425 
    426 int ExtensionProcessManager::DecrementLazyKeepaliveCount(
    427      const Extension* extension) {
    428   if (!BackgroundInfo::HasLazyBackgroundPage(extension))
    429     return 0;
    430 
    431   int& count = background_page_data_[extension->id()].lazy_keepalive_count;
    432   DCHECK_GT(count, 0);
    433   if (--count == 0) {
    434     base::MessageLoop::current()->PostDelayedTask(
    435         FROM_HERE,
    436         base::Bind(&ExtensionProcessManager::OnLazyBackgroundPageIdle,
    437                    weak_ptr_factory_.GetWeakPtr(), extension->id(),
    438                    ++background_page_data_[extension->id()].close_sequence_id),
    439         event_page_idle_time_);
    440   }
    441 
    442   return count;
    443 }
    444 
    445 void ExtensionProcessManager::IncrementLazyKeepaliveCountForView(
    446     RenderViewHost* render_view_host) {
    447   WebContents* web_contents =
    448       WebContents::FromRenderViewHost(render_view_host);
    449   extensions::ViewType view_type = extensions::GetViewType(web_contents);
    450   if (view_type != extensions::VIEW_TYPE_INVALID &&
    451       view_type != extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
    452     const Extension* extension = GetExtensionForRenderViewHost(
    453         render_view_host);
    454     if (extension)
    455       IncrementLazyKeepaliveCount(extension);
    456   }
    457 }
    458 
    459 void ExtensionProcessManager::OnLazyBackgroundPageIdle(
    460     const std::string& extension_id, int sequence_id) {
    461   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    462   if (host && !background_page_data_[extension_id].is_closing &&
    463       sequence_id == background_page_data_[extension_id].close_sequence_id) {
    464     // Tell the renderer we are about to close. This is a simple ping that the
    465     // renderer will respond to. The purpose is to control sequencing: if the
    466     // extension remains idle until the renderer responds with an ACK, then we
    467     // know that the extension process is ready to shut down. If our
    468     // close_sequence_id has already changed, then we would ignore the
    469     // ShouldSuspendAck, so we don't send the ping.
    470     host->render_view_host()->Send(new ExtensionMsg_ShouldSuspend(
    471         extension_id, sequence_id));
    472   }
    473 }
    474 
    475 void ExtensionProcessManager::OnLazyBackgroundPageActive(
    476     const std::string& extension_id) {
    477   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    478   if (host && !background_page_data_[extension_id].is_closing) {
    479     // Cancel the current close sequence by changing the close_sequence_id,
    480     // which causes us to ignore the next ShouldSuspendAck.
    481     ++background_page_data_[extension_id].close_sequence_id;
    482   }
    483 }
    484 
    485 void ExtensionProcessManager::OnShouldSuspendAck(
    486      const std::string& extension_id, int sequence_id) {
    487   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    488   if (host &&
    489       sequence_id == background_page_data_[extension_id].close_sequence_id) {
    490     host->render_view_host()->Send(new ExtensionMsg_Suspend(extension_id));
    491   }
    492 }
    493 
    494 void ExtensionProcessManager::OnSuspendAck(const std::string& extension_id) {
    495   background_page_data_[extension_id].is_closing = true;
    496   int sequence_id = background_page_data_[extension_id].close_sequence_id;
    497   base::MessageLoop::current()->PostDelayedTask(
    498       FROM_HERE,
    499       base::Bind(&ExtensionProcessManager::CloseLazyBackgroundPageNow,
    500                  weak_ptr_factory_.GetWeakPtr(), extension_id, sequence_id),
    501       event_page_suspending_time_);
    502 }
    503 
    504 void ExtensionProcessManager::CloseLazyBackgroundPageNow(
    505     const std::string& extension_id, int sequence_id) {
    506   ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    507   if (host &&
    508       sequence_id == background_page_data_[extension_id].close_sequence_id) {
    509     ExtensionHost* host = GetBackgroundHostForExtension(extension_id);
    510     if (host)
    511       CloseBackgroundHost(host);
    512   }
    513 }
    514 
    515 void ExtensionProcessManager::OnNetworkRequestStarted(
    516     RenderViewHost* render_view_host) {
    517   ExtensionHost* host = GetBackgroundHostForExtension(
    518       GetExtensionID(render_view_host));
    519   if (host && host->render_view_host() == render_view_host)
    520     IncrementLazyKeepaliveCount(host->extension());
    521 }
    522 
    523 void ExtensionProcessManager::OnNetworkRequestDone(
    524     RenderViewHost* render_view_host) {
    525   ExtensionHost* host = GetBackgroundHostForExtension(
    526       GetExtensionID(render_view_host));
    527   if (host && host->render_view_host() == render_view_host)
    528     DecrementLazyKeepaliveCount(host->extension());
    529 }
    530 
    531 void ExtensionProcessManager::CancelSuspend(const Extension* extension) {
    532   bool& is_closing = background_page_data_[extension->id()].is_closing;
    533   ExtensionHost* host = GetBackgroundHostForExtension(extension->id());
    534   if (host && is_closing) {
    535     is_closing = false;
    536     host->render_view_host()->Send(
    537         new ExtensionMsg_CancelSuspend(extension->id()));
    538     // This increment / decrement is to simulate an instantaneous event. This
    539     // has the effect of invalidating close_sequence_id, preventing any in
    540     // progress closes from completing and starting a new close process if
    541     // necessary.
    542     IncrementLazyKeepaliveCount(extension);
    543     DecrementLazyKeepaliveCount(extension);
    544   }
    545 }
    546 
    547 void ExtensionProcessManager::Observe(
    548     int type,
    549     const content::NotificationSource& source,
    550     const content::NotificationDetails& details) {
    551   switch (type) {
    552     case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
    553       // If a window for this profile, or this profile's incognito profile,
    554       // has been opened, make sure this profile's background hosts have
    555       // been loaded.
    556       Browser* browser = content::Source<Browser>(source).ptr();
    557       if (browser->profile() != GetProfile() &&
    558           !(GetProfile()->HasOffTheRecordProfile() &&
    559             browser->profile() == GetProfile()->GetOffTheRecordProfile()))
    560         break;
    561 
    562       ExtensionService* service = GetProfile()->GetExtensionService();
    563       if (!service || !service->is_ready())
    564         break;
    565 
    566       CreateBackgroundHostsForProfileStartup();
    567       break;
    568     }
    569     case chrome::NOTIFICATION_EXTENSIONS_READY:
    570     case chrome::NOTIFICATION_PROFILE_CREATED: {
    571       // Don't load background hosts now if the loading should be deferred.
    572       // Instead they will be loaded when a browser window for this profile
    573       // (or an incognito profile from this profile) is ready.
    574       if (DeferLoadingBackgroundHosts())
    575         break;
    576 
    577       CreateBackgroundHostsForProfileStartup();
    578       break;
    579     }
    580 
    581     case chrome::NOTIFICATION_EXTENSION_LOADED: {
    582       Profile* profile = content::Source<Profile>(source).ptr();
    583       ExtensionService* service =
    584           extensions::ExtensionSystem::Get(profile)->extension_service();
    585       if (service->is_ready()) {
    586         const Extension* extension =
    587             content::Details<const Extension>(details).ptr();
    588         CreateBackgroundHostForExtensionLoad(this, extension);
    589       }
    590       break;
    591     }
    592 
    593     case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
    594       const Extension* extension =
    595           content::Details<extensions::UnloadedExtensionInfo>(
    596               details)->extension;
    597       for (ExtensionHostSet::iterator iter = background_hosts_.begin();
    598            iter != background_hosts_.end(); ++iter) {
    599         ExtensionHost* host = *iter;
    600         if (host->extension_id() == extension->id()) {
    601           CloseBackgroundHost(host);
    602           break;
    603         }
    604       }
    605       background_page_data_.erase(extension->id());
    606       break;
    607     }
    608 
    609     case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
    610       ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
    611       if (background_hosts_.erase(host)) {
    612         ClearBackgroundPageData(host->extension()->id());
    613         background_page_data_[host->extension()->id()].since_suspended.reset(
    614             new PerfTimer());
    615       }
    616       break;
    617     }
    618 
    619     case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
    620       ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
    621       if (host->extension_host_type() ==
    622           extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
    623         CloseBackgroundHost(host);
    624       }
    625       break;
    626     }
    627 
    628     case content::NOTIFICATION_WEB_CONTENTS_SWAPPED: {
    629       // We get this notification both for new WebContents and when one
    630       // has its RenderViewHost replaced (e.g. when a user does a cross-site
    631       // navigation away from an extension URL). For the replaced case, we must
    632       // unregister the old RVH so it doesn't count as an active view that would
    633       // keep the event page alive.
    634       content::WebContents* contents =
    635           content::Source<content::WebContents>(source).ptr();
    636       if (contents->GetBrowserContext() != GetProfile())
    637         break;
    638 
    639       content::RenderViewHost* old_render_view_host =
    640           content::Details<content::RenderViewHost>(details).ptr();
    641       if (old_render_view_host)
    642         UnregisterRenderViewHost(old_render_view_host);
    643       RegisterRenderViewHost(contents->GetRenderViewHost());
    644       break;
    645     }
    646 
    647     case content::NOTIFICATION_WEB_CONTENTS_CONNECTED: {
    648       content::WebContents* contents =
    649           content::Source<content::WebContents>(source).ptr();
    650       if (contents->GetBrowserContext() != GetProfile())
    651         break;
    652       const Extension* extension = GetExtensionForRenderViewHost(
    653           contents->GetRenderViewHost());
    654       if (!extension)
    655         return;
    656 
    657       // RegisterRenderViewHost is called too early (before the process is
    658       // available), so we need to wait until now to notify.
    659       content::NotificationService::current()->Notify(
    660           chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
    661           content::Source<Profile>(GetProfile()),
    662           content::Details<RenderViewHost>(contents->GetRenderViewHost()));
    663       break;
    664     }
    665 
    666     case chrome::NOTIFICATION_PROFILE_DESTROYED: {
    667       // Close background hosts when the last browser is closed so that they
    668       // have time to shutdown various objects on different threads. Our
    669       // destructor is called too late in the shutdown sequence.
    670       CloseBackgroundHosts();
    671       break;
    672     }
    673 
    674     default:
    675       NOTREACHED();
    676   }
    677 }
    678 
    679 void ExtensionProcessManager::OnDevToolsStateChanged(
    680     content::DevToolsAgentHost* agent_host, bool attached) {
    681   content::RenderViewHost* rvh = agent_host->GetRenderViewHost();
    682   // Ignore unrelated notifications.
    683   if (!rvh ||
    684       rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != GetProfile())
    685     return;
    686   if (extensions::GetViewType(WebContents::FromRenderViewHost(rvh)) !=
    687       extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE)
    688     return;
    689   const Extension* extension = GetExtensionForRenderViewHost(rvh);
    690   if (!extension)
    691     return;
    692   if (attached) {
    693     // Keep the lazy background page alive while it's being inspected.
    694     CancelSuspend(extension);
    695     IncrementLazyKeepaliveCount(extension);
    696   } else {
    697     DecrementLazyKeepaliveCount(extension);
    698   }
    699 }
    700 
    701 void ExtensionProcessManager::CreateBackgroundHostsForProfileStartup() {
    702   ExtensionService* service = GetProfile()->GetExtensionService();
    703   for (ExtensionSet::const_iterator extension = service->extensions()->begin();
    704        extension != service->extensions()->end(); ++extension) {
    705     CreateBackgroundHostForExtensionLoad(this, extension->get());
    706 
    707     extensions::RuntimeEventRouter::DispatchOnStartupEvent(
    708         GetProfile(), (*extension)->id());
    709   }
    710 
    711   // Background pages should only be loaded once. To prevent any further loads
    712   // occurring, we remove the notification listeners.
    713   Profile* original_profile = GetProfile()->GetOriginalProfile();
    714   registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
    715                     content::NotificationService::AllSources());
    716   if (registrar_.IsRegistered(this, chrome::NOTIFICATION_PROFILE_CREATED,
    717                               content::Source<Profile>(original_profile)))
    718     registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CREATED,
    719                       content::Source<Profile>(original_profile));
    720   if (registrar_.IsRegistered(this, chrome::NOTIFICATION_EXTENSIONS_READY,
    721                               content::Source<Profile>(original_profile)))
    722     registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
    723                       content::Source<Profile>(original_profile));
    724 }
    725 
    726 Profile* ExtensionProcessManager::GetProfile() const {
    727   return Profile::FromBrowserContext(site_instance_->GetBrowserContext());
    728 }
    729 
    730 void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host,
    731                                                      bool is_background) {
    732   DCHECK_EQ(site_instance_->GetBrowserContext(), host->profile());
    733   if (is_background) {
    734     background_hosts_.insert(host);
    735 
    736     if (BackgroundInfo::HasLazyBackgroundPage(host->extension())) {
    737       linked_ptr<PerfTimer> since_suspended(
    738           background_page_data_[host->extension()->id()].
    739               since_suspended.release());
    740       if (since_suspended.get()) {
    741         UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageIdleTime",
    742                                  since_suspended->Elapsed());
    743       }
    744     }
    745   }
    746 }
    747 
    748 void ExtensionProcessManager::CloseBackgroundHost(ExtensionHost* host) {
    749   CHECK(host->extension_host_type() ==
    750         extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE);
    751   delete host;
    752   // |host| should deregister itself from our structures.
    753   CHECK(background_hosts_.find(host) == background_hosts_.end());
    754 }
    755 
    756 void ExtensionProcessManager::CloseBackgroundHosts() {
    757   for (ExtensionHostSet::iterator iter = background_hosts_.begin();
    758        iter != background_hosts_.end(); ) {
    759     ExtensionHostSet::iterator current = iter++;
    760     delete *current;
    761   }
    762 }
    763 
    764 void ExtensionProcessManager::ClearBackgroundPageData(
    765     const std::string& extension_id) {
    766   background_page_data_.erase(extension_id);
    767 
    768   // Re-register all RenderViews for this extension. We do this to restore
    769   // the lazy_keepalive_count (if any) to properly reflect the number of open
    770   // views.
    771   for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin();
    772        it != all_extension_views_.end(); ++it) {
    773     if (GetExtensionID(it->first) == extension_id)
    774       IncrementLazyKeepaliveCountForView(it->first);
    775   }
    776 }
    777 
    778 bool ExtensionProcessManager::DeferLoadingBackgroundHosts() const {
    779   // The profile may not be valid yet if it is still being initialized.
    780   // In that case, defer loading, since it depends on an initialized profile.
    781   // http://crbug.com/222473
    782   if (!g_browser_process->profile_manager()->IsValidProfile(GetProfile()))
    783     return true;
    784 
    785 #if defined(OS_ANDROID)
    786   return false;
    787 #else
    788   return chrome::GetTotalBrowserCountForProfile(GetProfile()) == 0 &&
    789          CommandLine::ForCurrentProcess()->HasSwitch(switches::kShowAppList);
    790 #endif
    791 }
    792 
    793 //
    794 // IncognitoExtensionProcessManager
    795 //
    796 
    797 IncognitoExtensionProcessManager::IncognitoExtensionProcessManager(
    798     Profile* profile)
    799     : ExtensionProcessManager(profile),
    800       original_manager_(extensions::ExtensionSystem::Get(
    801           profile->GetOriginalProfile())->process_manager()) {
    802   DCHECK(profile->IsOffTheRecord());
    803 
    804   // The original profile will have its own ExtensionProcessManager to
    805   // load the background pages of the spanning extensions. This process
    806   // manager need only worry about the split mode extensions, which is handled
    807   // in the NOTIFICATION_BROWSER_WINDOW_READY notification handler.
    808   registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
    809                     content::Source<Profile>(profile->GetOriginalProfile()));
    810   registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_CREATED,
    811                     content::Source<Profile>(profile->GetOriginalProfile()));
    812 }
    813 
    814 IncognitoExtensionProcessManager::~IncognitoExtensionProcessManager() {
    815   // TODO(yoz): This cleanup code belongs in the MenuManager.
    816   // Remove "incognito" "split" mode context menu items.
    817   ExtensionService* service =
    818       extensions::ExtensionSystem::Get(GetProfile())->extension_service();
    819   if (service)
    820     service->menu_manager()->RemoveAllIncognitoContextItems();
    821 }
    822 
    823 ExtensionHost* IncognitoExtensionProcessManager::CreateViewHost(
    824     const Extension* extension,
    825     const GURL& url,
    826     Browser* browser,
    827     extensions::ViewType view_type) {
    828   if (extensions::IncognitoInfo::IsSplitMode(extension)) {
    829     if (IsIncognitoEnabled(extension)) {
    830       return ExtensionProcessManager::CreateViewHost(extension, url,
    831                                                      browser, view_type);
    832     } else {
    833       NOTREACHED() <<
    834           "We shouldn't be trying to create an incognito extension view unless "
    835           "it has been enabled for incognito.";
    836       return NULL;
    837     }
    838   } else {
    839     return original_manager_->CreateViewHost(extension, url,
    840                                              browser, view_type);
    841   }
    842 }
    843 
    844 void IncognitoExtensionProcessManager::CreateBackgroundHost(
    845     const Extension* extension, const GURL& url) {
    846   if (extensions::IncognitoInfo::IsSplitMode(extension)) {
    847     if (IsIncognitoEnabled(extension))
    848       ExtensionProcessManager::CreateBackgroundHost(extension, url);
    849   } else {
    850     // Do nothing. If an extension is spanning, then its original-profile
    851     // background page is shared with incognito, so we don't create another.
    852   }
    853 }
    854 
    855 SiteInstance* IncognitoExtensionProcessManager::GetSiteInstanceForURL(
    856     const GURL& url) {
    857   ExtensionService* service = GetProfile()->GetExtensionService();
    858   if (service) {
    859     const Extension* extension =
    860         service->extensions()->GetExtensionOrAppByURL(url);
    861     if (extension &&
    862         !extensions::IncognitoInfo::IsSplitMode(extension)) {
    863       return original_manager_->GetSiteInstanceForURL(url);
    864     }
    865   }
    866   return ExtensionProcessManager::GetSiteInstanceForURL(url);
    867 }
    868 
    869 bool IncognitoExtensionProcessManager::IsIncognitoEnabled(
    870     const Extension* extension) {
    871   // Keep in sync with duplicate in extension_info_map.cc.
    872   ExtensionService* service = GetProfile()->GetExtensionService();
    873   return service && service->IsIncognitoEnabled(extension->id());
    874 }
    875 
    876 void IncognitoExtensionProcessManager::Observe(
    877     int type,
    878     const content::NotificationSource& source,
    879     const content::NotificationDetails& details) {
    880   switch (type) {
    881     // Do not use ExtensionProcessManager's handler for
    882     // NOTIFICATION_BROWSER_WINDOW_READY.
    883     case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
    884       // We want to spawn our background hosts as soon as the user opens an
    885       // incognito window. Watch for new browsers and create the hosts if
    886       // it matches our profile.
    887       Browser* browser = content::Source<Browser>(source).ptr();
    888       if (browser->profile() == site_instance_->GetBrowserContext()) {
    889         // On Chrome OS, a login screen is implemented as a browser.
    890         // This browser has no extension service.  In this case,
    891         // service will be NULL.
    892         ExtensionService* service = GetProfile()->GetExtensionService();
    893         if (service && service->is_ready())
    894           CreateBackgroundHostsForProfileStartup();
    895       }
    896       break;
    897     }
    898     default:
    899       ExtensionProcessManager::Observe(type, source, details);
    900       break;
    901   }
    902 }
    903