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_host.h"
      6 
      7 #include <list>
      8 
      9 #include "base/bind.h"
     10 #include "base/memory/singleton.h"
     11 #include "base/memory/weak_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/metrics/histogram.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "chrome/browser/browser_shutdown.h"
     17 #include "chrome/browser/chrome_notification_types.h"
     18 #include "chrome/browser/extensions/event_router.h"
     19 #include "chrome/browser/extensions/extension_process_manager.h"
     20 #include "chrome/browser/extensions/extension_service.h"
     21 #include "chrome/browser/extensions/extension_system.h"
     22 #include "chrome/browser/extensions/extension_tab_util.h"
     23 #include "chrome/browser/extensions/window_controller.h"
     24 #include "chrome/browser/file_select_helper.h"
     25 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
     26 #include "chrome/browser/profiles/profile.h"
     27 #include "chrome/browser/ui/app_modal_dialogs/javascript_dialog_manager.h"
     28 #include "chrome/browser/ui/browser.h"
     29 #include "chrome/browser/ui/browser_dialogs.h"
     30 #include "chrome/browser/ui/browser_finder.h"
     31 #include "chrome/browser/ui/browser_list.h"
     32 #include "chrome/browser/ui/browser_window.h"
     33 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
     34 #include "chrome/common/chrome_constants.h"
     35 #include "chrome/common/extensions/background_info.h"
     36 #include "chrome/common/extensions/extension.h"
     37 #include "chrome/common/extensions/extension_constants.h"
     38 #include "chrome/common/extensions/extension_messages.h"
     39 #include "chrome/common/extensions/feature_switch.h"
     40 #include "chrome/common/render_messages.h"
     41 #include "chrome/common/url_constants.h"
     42 #include "content/public/browser/content_browser_client.h"
     43 #include "content/public/browser/native_web_keyboard_event.h"
     44 #include "content/public/browser/notification_service.h"
     45 #include "content/public/browser/render_process_host.h"
     46 #include "content/public/browser/render_view_host.h"
     47 #include "content/public/browser/site_instance.h"
     48 #include "content/public/browser/web_contents.h"
     49 #include "content/public/browser/web_contents_view.h"
     50 #include "extensions/browser/view_type_utils.h"
     51 #include "grit/browser_resources.h"
     52 #include "grit/chromium_strings.h"
     53 #include "grit/generated_resources.h"
     54 #include "ui/base/keycodes/keyboard_codes.h"
     55 #include "ui/base/l10n/l10n_util.h"
     56 #include "ui/base/resource/resource_bundle.h"
     57 
     58 #if !defined(OS_ANDROID)
     59 #include "components/web_modal/web_contents_modal_dialog_manager.h"
     60 #endif
     61 
     62 using WebKit::WebDragOperation;
     63 using WebKit::WebDragOperationsMask;
     64 using content::NativeWebKeyboardEvent;
     65 using content::OpenURLParams;
     66 using content::RenderViewHost;
     67 using content::SiteInstance;
     68 using content::WebContents;
     69 
     70 namespace extensions {
     71 
     72 // Helper class that rate-limits the creation of renderer processes for
     73 // ExtensionHosts, to avoid blocking the UI.
     74 class ExtensionHost::ProcessCreationQueue {
     75  public:
     76   static ProcessCreationQueue* GetInstance() {
     77     return Singleton<ProcessCreationQueue>::get();
     78   }
     79 
     80   // Add a host to the queue for RenderView creation.
     81   void CreateSoon(ExtensionHost* host) {
     82     queue_.push_back(host);
     83     PostTask();
     84   }
     85 
     86   // Remove a host from the queue (in case it's being deleted).
     87   void Remove(ExtensionHost* host) {
     88     Queue::iterator it = std::find(queue_.begin(), queue_.end(), host);
     89     if (it != queue_.end())
     90       queue_.erase(it);
     91   }
     92 
     93  private:
     94   friend class Singleton<ProcessCreationQueue>;
     95   friend struct DefaultSingletonTraits<ProcessCreationQueue>;
     96   ProcessCreationQueue()
     97       : pending_create_(false),
     98         ptr_factory_(this) {}
     99 
    100   // Queue up a delayed task to process the next ExtensionHost in the queue.
    101   void PostTask() {
    102     if (!pending_create_) {
    103       base::MessageLoop::current()->PostTask(FROM_HERE,
    104           base::Bind(&ProcessCreationQueue::ProcessOneHost,
    105                      ptr_factory_.GetWeakPtr()));
    106       pending_create_ = true;
    107     }
    108   }
    109 
    110   // Create the RenderView for the next host in the queue.
    111   void ProcessOneHost() {
    112     pending_create_ = false;
    113     if (queue_.empty())
    114       return;  // can happen on shutdown
    115 
    116     queue_.front()->CreateRenderViewNow();
    117     queue_.pop_front();
    118 
    119     if (!queue_.empty())
    120       PostTask();
    121   }
    122 
    123   typedef std::list<ExtensionHost*> Queue;
    124   Queue queue_;
    125   bool pending_create_;
    126   base::WeakPtrFactory<ProcessCreationQueue> ptr_factory_;
    127 };
    128 
    129 ////////////////
    130 // ExtensionHost
    131 
    132 ExtensionHost::ExtensionHost(const Extension* extension,
    133                              SiteInstance* site_instance,
    134                              const GURL& url,
    135                              ViewType host_type)
    136     : extension_(extension),
    137       extension_id_(extension->id()),
    138       profile_(Profile::FromBrowserContext(
    139           site_instance->GetBrowserContext())),
    140       render_view_host_(NULL),
    141       did_stop_loading_(false),
    142       document_element_available_(false),
    143       initial_url_(url),
    144       extension_function_dispatcher_(profile_, this),
    145       extension_host_type_(host_type),
    146       associated_web_contents_(NULL) {
    147   host_contents_.reset(WebContents::Create(
    148       WebContents::CreateParams(profile_, site_instance))),
    149   content::WebContentsObserver::Observe(host_contents_.get());
    150   host_contents_->SetDelegate(this);
    151   SetViewType(host_contents_.get(), host_type);
    152 
    153   PrefsTabHelper::CreateForWebContents(host_contents());
    154 
    155   render_view_host_ = host_contents_->GetRenderViewHost();
    156 
    157   // Listen for when an extension is unloaded from the same profile, as it may
    158   // be the same extension that this points to.
    159   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
    160                  content::Source<Profile>(profile_));
    161 }
    162 
    163 ExtensionHost::~ExtensionHost() {
    164   if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE &&
    165       extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_)) {
    166     UMA_HISTOGRAM_LONG_TIMES("Extensions.EventPageActiveTime",
    167                              since_created_.Elapsed());
    168   }
    169   content::NotificationService::current()->Notify(
    170       chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
    171       content::Source<Profile>(profile_),
    172       content::Details<ExtensionHost>(this));
    173   ProcessCreationQueue::GetInstance()->Remove(this);
    174 }
    175 
    176 void ExtensionHost::CreateView(Browser* browser) {
    177 #if defined(TOOLKIT_VIEWS)
    178   view_.reset(new ExtensionViewViews(this, browser));
    179   // We own |view_|, so don't auto delete when it's removed from the view
    180   // hierarchy.
    181   view_->set_owned_by_client();
    182 #elif defined(OS_MACOSX)
    183   view_.reset(new ExtensionViewMac(this, browser));
    184   view_->Init();
    185 #elif defined(TOOLKIT_GTK)
    186   view_.reset(new ExtensionViewGtk(this, browser));
    187   view_->Init();
    188 #else
    189   // TODO(port)
    190   NOTREACHED();
    191 #endif
    192 }
    193 
    194 WebContents* ExtensionHost::GetAssociatedWebContents() const {
    195   return associated_web_contents_;
    196 }
    197 
    198 WebContents* ExtensionHost::GetVisibleWebContents() const {
    199   if (associated_web_contents_)
    200     return associated_web_contents_;
    201   if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) ||
    202       (extension_host_type_ == VIEW_TYPE_PANEL))
    203     return host_contents_.get();
    204   return NULL;
    205 }
    206 
    207 void ExtensionHost::SetAssociatedWebContents(
    208     content::WebContents* web_contents) {
    209   associated_web_contents_ = web_contents;
    210   if (web_contents) {
    211     registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    212                    content::Source<WebContents>(associated_web_contents_));
    213   }
    214 }
    215 
    216 content::RenderProcessHost* ExtensionHost::render_process_host() const {
    217   return render_view_host()->GetProcess();
    218 }
    219 
    220 RenderViewHost* ExtensionHost::render_view_host() const {
    221   // TODO(mpcomplete): This can be NULL. How do we handle that?
    222   return render_view_host_;
    223 }
    224 
    225 bool ExtensionHost::IsRenderViewLive() const {
    226   return render_view_host()->IsRenderViewLive();
    227 }
    228 
    229 void ExtensionHost::CreateRenderViewSoon() {
    230   if ((render_process_host() && render_process_host()->HasConnection())) {
    231     // If the process is already started, go ahead and initialize the RenderView
    232     // synchronously. The process creation is the real meaty part that we want
    233     // to defer.
    234     CreateRenderViewNow();
    235   } else {
    236     ProcessCreationQueue::GetInstance()->CreateSoon(this);
    237   }
    238 }
    239 
    240 void ExtensionHost::CreateRenderViewNow() {
    241   LoadInitialURL();
    242   if (is_background_page()) {
    243     DCHECK(IsRenderViewLive());
    244     ExtensionSystem::Get(profile_)->extension_service()->
    245         DidCreateRenderViewForBackgroundPage(this);
    246   }
    247 }
    248 
    249 WindowController* ExtensionHost::GetExtensionWindowController() const {
    250   return view() && view()->browser() ?
    251       view()->browser()->extension_window_controller() : NULL;
    252 }
    253 
    254 const GURL& ExtensionHost::GetURL() const {
    255   return host_contents()->GetURL();
    256 }
    257 
    258 void ExtensionHost::LoadInitialURL() {
    259   if (!is_background_page() &&
    260       !ExtensionSystem::Get(profile_)->extension_service()->
    261           IsBackgroundPageReady(extension_)) {
    262     // Make sure the background page loads before any others.
    263     registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
    264                    content::Source<Extension>(extension_));
    265     return;
    266   }
    267 
    268 #if !defined(OS_ANDROID)
    269   if ((extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) ||
    270       (extension_host_type_ == VIEW_TYPE_PANEL)) {
    271     web_modal::WebContentsModalDialogManager::CreateForWebContents(
    272         host_contents_.get());
    273     web_modal::WebContentsModalDialogManager::FromWebContents(
    274         host_contents_.get())->set_delegate(this);
    275   }
    276 #endif
    277 
    278   host_contents_->GetController().LoadURL(
    279       initial_url_, content::Referrer(), content::PAGE_TRANSITION_LINK,
    280       std::string());
    281 }
    282 
    283 void ExtensionHost::Close() {
    284   content::NotificationService::current()->Notify(
    285       chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
    286       content::Source<Profile>(profile_),
    287       content::Details<ExtensionHost>(this));
    288 }
    289 
    290 void ExtensionHost::Observe(int type,
    291                             const content::NotificationSource& source,
    292                             const content::NotificationDetails& details) {
    293   switch (type) {
    294     case chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY:
    295       DCHECK(ExtensionSystem::Get(profile_)->extension_service()->
    296           IsBackgroundPageReady(extension_));
    297       LoadInitialURL();
    298       break;
    299     case chrome::NOTIFICATION_EXTENSION_UNLOADED:
    300       // The extension object will be deleted after this notification has been
    301       // sent. NULL it out so that dirty pointer issues don't arise in cases
    302       // when multiple ExtensionHost objects pointing to the same Extension are
    303       // present.
    304       if (extension_ == content::Details<UnloadedExtensionInfo>(details)->
    305           extension) {
    306         extension_ = NULL;
    307       }
    308       break;
    309     case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
    310       if (content::Source<WebContents>(source).ptr() ==
    311           associated_web_contents_) {
    312         associated_web_contents_ = NULL;
    313       }
    314       break;
    315     default:
    316       NOTREACHED() << "Unexpected notification sent.";
    317       break;
    318   }
    319 }
    320 
    321 void ExtensionHost::ResizeDueToAutoResize(WebContents* source,
    322                                           const gfx::Size& new_size) {
    323   if (view())
    324     view()->ResizeDueToAutoResize(new_size);
    325 }
    326 
    327 void ExtensionHost::RenderProcessGone(base::TerminationStatus status) {
    328   // During browser shutdown, we may use sudden termination on an extension
    329   // process, so it is expected to lose our connection to the render view.
    330   // Do nothing.
    331   if (browser_shutdown::GetShutdownType() != browser_shutdown::NOT_VALID)
    332     return;
    333 
    334   // In certain cases, multiple ExtensionHost objects may have pointed to
    335   // the same Extension at some point (one with a background page and a
    336   // popup, for example). When the first ExtensionHost goes away, the extension
    337   // is unloaded, and any other host that pointed to that extension will have
    338   // its pointer to it NULLed out so that any attempt to unload a dirty pointer
    339   // will be averted.
    340   if (!extension_)
    341     return;
    342 
    343   // TODO(aa): This is suspicious. There can be multiple views in an extension,
    344   // and they aren't all going to use ExtensionHost. This should be in someplace
    345   // more central, like EPM maybe.
    346   content::NotificationService::current()->Notify(
    347       chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
    348       content::Source<Profile>(profile_),
    349       content::Details<ExtensionHost>(this));
    350 }
    351 
    352 void ExtensionHost::InsertInfobarCSS() {
    353   DCHECK(!is_background_page());
    354 
    355   static const base::StringPiece css(
    356       ResourceBundle::GetSharedInstance().GetRawDataResource(
    357       IDR_EXTENSIONS_INFOBAR_CSS));
    358 
    359   render_view_host()->InsertCSS(string16(), css.as_string());
    360 }
    361 
    362 void ExtensionHost::DidStopLoading(content::RenderViewHost* render_view_host) {
    363   bool notify = !did_stop_loading_;
    364   did_stop_loading_ = true;
    365   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP ||
    366       extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG ||
    367       extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR ||
    368       extension_host_type_ == VIEW_TYPE_PANEL) {
    369 #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX)
    370     if (view())
    371       view()->DidStopLoading();
    372 #endif
    373   }
    374   if (notify) {
    375     if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
    376       if (extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_)) {
    377         UMA_HISTOGRAM_TIMES("Extensions.EventPageLoadTime",
    378                             since_created_.Elapsed());
    379       } else {
    380         UMA_HISTOGRAM_TIMES("Extensions.BackgroundPageLoadTime",
    381                             since_created_.Elapsed());
    382       }
    383     } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG) {
    384       UMA_HISTOGRAM_TIMES("Extensions.DialogLoadTime",
    385                           since_created_.Elapsed());
    386     } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) {
    387       UMA_HISTOGRAM_TIMES("Extensions.PopupLoadTime",
    388                           since_created_.Elapsed());
    389     } else if (extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR) {
    390       UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime",
    391         since_created_.Elapsed());
    392     } else if (extension_host_type_ == VIEW_TYPE_PANEL) {
    393       UMA_HISTOGRAM_TIMES("Extensions.PanelLoadTime", since_created_.Elapsed());
    394     }
    395 
    396     // Send the notification last, because it might result in this being
    397     // deleted.
    398     content::NotificationService::current()->Notify(
    399         chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
    400         content::Source<Profile>(profile_),
    401         content::Details<ExtensionHost>(this));
    402   }
    403 }
    404 
    405 void ExtensionHost::DocumentAvailableInMainFrame() {
    406   // If the document has already been marked as available for this host, then
    407   // bail. No need for the redundant setup. http://crbug.com/31170
    408   if (document_element_available_)
    409     return;
    410 
    411   document_element_available_ = true;
    412   if (is_background_page()) {
    413     ExtensionSystem::Get(profile_)->extension_service()->
    414         SetBackgroundPageReady(extension_);
    415   } else {
    416     switch (extension_host_type_) {
    417       case VIEW_TYPE_EXTENSION_INFOBAR:
    418         InsertInfobarCSS();
    419         break;
    420       default:
    421         break;  // No style sheet for other types, at the moment.
    422     }
    423   }
    424 }
    425 
    426 void ExtensionHost::CloseContents(WebContents* contents) {
    427   // TODO(mpcomplete): is this check really necessary?
    428   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP ||
    429       extension_host_type_ == VIEW_TYPE_EXTENSION_DIALOG ||
    430       extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE ||
    431       extension_host_type_ == VIEW_TYPE_EXTENSION_INFOBAR ||
    432       extension_host_type_ == VIEW_TYPE_PANEL) {
    433     Close();
    434   }
    435 }
    436 
    437 void ExtensionHost::WillRunJavaScriptDialog() {
    438   ExtensionProcessManager* pm =
    439       ExtensionSystem::Get(profile_)->process_manager();
    440   if (pm)
    441     pm->IncrementLazyKeepaliveCount(extension());
    442 }
    443 
    444 void ExtensionHost::DidCloseJavaScriptDialog() {
    445   ExtensionProcessManager* pm =
    446       ExtensionSystem::Get(profile_)->process_manager();
    447   if (pm)
    448     pm->DecrementLazyKeepaliveCount(extension());
    449 }
    450 
    451 WebContents* ExtensionHost::OpenURLFromTab(WebContents* source,
    452                                            const OpenURLParams& params) {
    453   // Whitelist the dispositions we will allow to be opened.
    454   switch (params.disposition) {
    455     case SINGLETON_TAB:
    456     case NEW_FOREGROUND_TAB:
    457     case NEW_BACKGROUND_TAB:
    458     case NEW_POPUP:
    459     case NEW_WINDOW:
    460     case SAVE_TO_DISK:
    461     case OFF_THE_RECORD: {
    462       // Only allow these from hosts that are bound to a browser (e.g. popups).
    463       // Otherwise they are not driven by a user gesture.
    464       Browser* browser = view() ? view()->browser() : NULL;
    465       return browser ? browser->OpenURL(params) : NULL;
    466     }
    467     default:
    468       return NULL;
    469   }
    470 }
    471 
    472 bool ExtensionHost::PreHandleKeyboardEvent(WebContents* source,
    473                                            const NativeWebKeyboardEvent& event,
    474                                            bool* is_keyboard_shortcut) {
    475   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP &&
    476       event.type == NativeWebKeyboardEvent::RawKeyDown &&
    477       event.windowsKeyCode == ui::VKEY_ESCAPE) {
    478     DCHECK(is_keyboard_shortcut != NULL);
    479     *is_keyboard_shortcut = true;
    480     return false;
    481   }
    482 
    483   // Handle higher priority browser shortcuts such as Ctrl-w.
    484   Browser* browser = view() ? view()->browser() : NULL;
    485   if (browser)
    486     return browser->PreHandleKeyboardEvent(source, event, is_keyboard_shortcut);
    487 
    488   *is_keyboard_shortcut = false;
    489   return false;
    490 }
    491 
    492 void ExtensionHost::HandleKeyboardEvent(WebContents* source,
    493                                         const NativeWebKeyboardEvent& event) {
    494   if (extension_host_type_ == VIEW_TYPE_EXTENSION_POPUP) {
    495     if (event.type == NativeWebKeyboardEvent::RawKeyDown &&
    496         event.windowsKeyCode == ui::VKEY_ESCAPE) {
    497       Close();
    498       return;
    499     }
    500   }
    501   UnhandledKeyboardEvent(source, event);
    502 }
    503 
    504 bool ExtensionHost::OnMessageReceived(const IPC::Message& message) {
    505   bool handled = true;
    506   IPC_BEGIN_MESSAGE_MAP(ExtensionHost, message)
    507     IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
    508     IPC_MESSAGE_HANDLER(ExtensionHostMsg_EventAck, OnEventAck)
    509     IPC_MESSAGE_HANDLER(ExtensionHostMsg_IncrementLazyKeepaliveCount,
    510                         OnIncrementLazyKeepaliveCount)
    511     IPC_MESSAGE_HANDLER(ExtensionHostMsg_DecrementLazyKeepaliveCount,
    512                         OnDecrementLazyKeepaliveCount)
    513     IPC_MESSAGE_UNHANDLED(handled = false)
    514   IPC_END_MESSAGE_MAP()
    515   return handled;
    516 }
    517 
    518 void ExtensionHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
    519   extension_function_dispatcher_.Dispatch(params, render_view_host());
    520 }
    521 
    522 void ExtensionHost::OnEventAck() {
    523   EventRouter* router = ExtensionSystem::Get(profile_)->event_router();
    524   if (router)
    525     router->OnEventAck(profile_, extension_id());
    526 }
    527 
    528 void ExtensionHost::OnIncrementLazyKeepaliveCount() {
    529   ExtensionProcessManager* pm =
    530       ExtensionSystem::Get(profile_)->process_manager();
    531   if (pm)
    532     pm->IncrementLazyKeepaliveCount(extension());
    533 }
    534 
    535 void ExtensionHost::OnDecrementLazyKeepaliveCount() {
    536   ExtensionProcessManager* pm =
    537       ExtensionSystem::Get(profile_)->process_manager();
    538   if (pm)
    539     pm->DecrementLazyKeepaliveCount(extension());
    540 }
    541 
    542 void ExtensionHost::UnhandledKeyboardEvent(
    543     WebContents* source,
    544     const content::NativeWebKeyboardEvent& event) {
    545   Browser* browser = view() ? view()->browser() : NULL;
    546   if (browser) {
    547     // Handle lower priority browser shortcuts such as Ctrl-f.
    548     return browser->HandleKeyboardEvent(source, event);
    549   } else {
    550 #if defined(TOOLKIT_VIEWS)
    551     // In case there's no Browser (e.g. for dialogs), pass it to
    552     // ExtensionViewViews to handle acceleratos. The view's FocusManager does
    553     // not know anything about Browser accelerators, but might know others such
    554     // as Ash's.
    555     if (view())
    556       view()->HandleKeyboardEvent(event);
    557 #endif
    558   }
    559 }
    560 
    561 void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) {
    562   render_view_host_ = render_view_host;
    563 
    564   if (view())
    565     view()->RenderViewCreated();
    566 
    567   // If the host is bound to a window, then extract its id. Extensions hosted
    568   // in ExternalTabContainer objects may not have an associated window.
    569   WindowController* window = GetExtensionWindowController();
    570   if (window) {
    571     render_view_host->Send(new ExtensionMsg_UpdateBrowserWindowId(
    572         render_view_host->GetRoutingID(), window->GetWindowId()));
    573   }
    574 }
    575 
    576 void ExtensionHost::RenderViewDeleted(RenderViewHost* render_view_host) {
    577   // If our RenderViewHost is deleted, fall back to the host_contents' current
    578   // RVH. There is sometimes a small gap between the pending RVH being deleted
    579   // and RenderViewCreated being called, so we update it here.
    580   if (render_view_host == render_view_host_)
    581     render_view_host_ = host_contents_->GetRenderViewHost();
    582 }
    583 
    584 content::JavaScriptDialogManager* ExtensionHost::GetJavaScriptDialogManager() {
    585   if (!dialog_manager_) {
    586     dialog_manager_.reset(CreateJavaScriptDialogManagerInstance(this));
    587   }
    588   return dialog_manager_.get();
    589 }
    590 
    591 content::ColorChooser* ExtensionHost::OpenColorChooser(
    592     WebContents* web_contents, SkColor initial_color) {
    593   return chrome::ShowColorChooser(web_contents, initial_color);
    594 }
    595 
    596 void ExtensionHost::RunFileChooser(WebContents* tab,
    597                                    const content::FileChooserParams& params) {
    598   FileSelectHelper::RunFileChooser(tab, params);
    599 }
    600 
    601 void ExtensionHost::AddNewContents(WebContents* source,
    602                                    WebContents* new_contents,
    603                                    WindowOpenDisposition disposition,
    604                                    const gfx::Rect& initial_pos,
    605                                    bool user_gesture,
    606                                    bool* was_blocked) {
    607   // First, if the creating extension view was associated with a tab contents,
    608   // use that tab content's delegate. We must be careful here that the
    609   // associated tab contents has the same profile as the new tab contents. In
    610   // the case of extensions in 'spanning' incognito mode, they can mismatch.
    611   // We don't want to end up putting a normal tab into an incognito window, or
    612   // vice versa.
    613   // Note that we don't do this for popup windows, because we need to associate
    614   // those with their extension_app_id.
    615   if (disposition != NEW_POPUP) {
    616     WebContents* associated_contents = GetAssociatedWebContents();
    617     if (associated_contents &&
    618         associated_contents->GetBrowserContext() ==
    619             new_contents->GetBrowserContext()) {
    620       WebContentsDelegate* delegate = associated_contents->GetDelegate();
    621       if (delegate) {
    622         delegate->AddNewContents(
    623             associated_contents, new_contents, disposition, initial_pos,
    624             user_gesture, was_blocked);
    625         return;
    626       }
    627     }
    628   }
    629 
    630   ExtensionTabUtil::CreateTab(new_contents, extension_id_, disposition,
    631                               initial_pos, user_gesture);
    632 }
    633 
    634 void ExtensionHost::RenderViewReady() {
    635   content::NotificationService::current()->Notify(
    636       chrome::NOTIFICATION_EXTENSION_HOST_CREATED,
    637       content::Source<Profile>(profile_),
    638       content::Details<ExtensionHost>(this));
    639 }
    640 
    641 void ExtensionHost::RequestMediaAccessPermission(
    642     content::WebContents* web_contents,
    643     const content::MediaStreamRequest& request,
    644     const content::MediaResponseCallback& callback) {
    645   MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
    646       web_contents, request, callback, extension());
    647 }
    648 
    649 }  // namespace extensions
    650