tab_helper.cc revision f2477e01787aa58f445919b809d89e252beef54f
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/tab_helper.h"
6
7#include "base/logging.h"
8#include "base/strings/string_util.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/extensions/activity_log/activity_log.h"
11#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
12#include "chrome/browser/extensions/api/declarative_content/content_rules_registry.h"
13#include "chrome/browser/extensions/crx_installer.h"
14#include "chrome/browser/extensions/error_console/error_console.h"
15#include "chrome/browser/extensions/extension_action.h"
16#include "chrome/browser/extensions/extension_action_manager.h"
17#include "chrome/browser/extensions/extension_service.h"
18#include "chrome/browser/extensions/extension_system.h"
19#include "chrome/browser/extensions/extension_tab_util.h"
20#include "chrome/browser/extensions/image_loader.h"
21#include "chrome/browser/extensions/page_action_controller.h"
22#include "chrome/browser/extensions/script_badge_controller.h"
23#include "chrome/browser/extensions/script_bubble_controller.h"
24#include "chrome/browser/extensions/script_executor.h"
25#include "chrome/browser/extensions/webstore_inline_installer.h"
26#include "chrome/browser/extensions/webstore_inline_installer_factory.h"
27#include "chrome/browser/profiles/profile.h"
28#include "chrome/browser/sessions/session_id.h"
29#include "chrome/browser/sessions/session_tab_helper.h"
30#include "chrome/browser/shell_integration.h"
31#include "chrome/browser/ui/app_list/app_list_service.h"
32#include "chrome/browser/ui/app_list/app_list_util.h"
33#include "chrome/browser/ui/browser_commands.h"
34#include "chrome/browser/ui/browser_dialogs.h"
35#include "chrome/browser/ui/browser_finder.h"
36#include "chrome/browser/ui/host_desktop.h"
37#include "chrome/browser/ui/web_applications/web_app_ui.h"
38#include "chrome/browser/web_applications/web_app.h"
39#include "chrome/common/extensions/extension_constants.h"
40#include "chrome/common/extensions/extension_icon_set.h"
41#include "chrome/common/extensions/extension_messages.h"
42#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
43#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
44#include "chrome/common/render_messages.h"
45#include "chrome/common/url_constants.h"
46#include "content/public/browser/invalidate_type.h"
47#include "content/public/browser/navigation_controller.h"
48#include "content/public/browser/navigation_details.h"
49#include "content/public/browser/navigation_entry.h"
50#include "content/public/browser/notification_service.h"
51#include "content/public/browser/notification_source.h"
52#include "content/public/browser/notification_types.h"
53#include "content/public/browser/render_process_host.h"
54#include "content/public/browser/render_view_host.h"
55#include "content/public/browser/render_widget_host_view.h"
56#include "content/public/browser/web_contents.h"
57#include "content/public/browser/web_contents_view.h"
58#include "extensions/browser/extension_error.h"
59#include "extensions/common/extension.h"
60#include "extensions/common/extension_resource.h"
61#include "extensions/common/extension_urls.h"
62#include "extensions/common/feature_switch.h"
63#include "ui/gfx/image/image.h"
64
65using content::NavigationController;
66using content::NavigationEntry;
67using content::RenderViewHost;
68using content::WebContents;
69
70DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper);
71
72namespace extensions {
73
74TabHelper::ScriptExecutionObserver::ScriptExecutionObserver(
75    TabHelper* tab_helper)
76    : tab_helper_(tab_helper) {
77  tab_helper_->AddScriptExecutionObserver(this);
78}
79
80TabHelper::ScriptExecutionObserver::ScriptExecutionObserver()
81    : tab_helper_(NULL) {
82}
83
84TabHelper::ScriptExecutionObserver::~ScriptExecutionObserver() {
85  if (tab_helper_)
86    tab_helper_->RemoveScriptExecutionObserver(this);
87}
88
89TabHelper::TabHelper(content::WebContents* web_contents)
90    : content::WebContentsObserver(web_contents),
91      extension_app_(NULL),
92      extension_function_dispatcher_(
93          Profile::FromBrowserContext(web_contents->GetBrowserContext()), this),
94      pending_web_app_action_(NONE),
95      script_executor_(new ScriptExecutor(web_contents,
96                                          &script_execution_observers_)),
97      image_loader_ptr_factory_(this),
98      webstore_inline_installer_factory_(new WebstoreInlineInstallerFactory()) {
99  // The ActiveTabPermissionManager requires a session ID; ensure this
100  // WebContents has one.
101  SessionTabHelper::CreateForWebContents(web_contents);
102  if (web_contents->GetRenderViewHost())
103    SetTabId(web_contents->GetRenderViewHost());
104  active_tab_permission_granter_.reset(new ActiveTabPermissionGranter(
105      web_contents,
106      SessionID::IdForTab(web_contents),
107      Profile::FromBrowserContext(web_contents->GetBrowserContext())));
108  if (FeatureSwitch::script_badges()->IsEnabled()) {
109    location_bar_controller_.reset(
110        new ScriptBadgeController(web_contents, this));
111  } else {
112    location_bar_controller_.reset(
113        new PageActionController(web_contents));
114  }
115
116  if (FeatureSwitch::script_bubble()->IsEnabled()) {
117    script_bubble_controller_.reset(
118        new ScriptBubbleController(web_contents, this));
119  }
120
121  // If more classes need to listen to global content script activity, then
122  // a separate routing class with an observer interface should be written.
123  profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
124
125#if defined(ENABLE_EXTENSIONS)
126  AddScriptExecutionObserver(ActivityLog::GetInstance(profile_));
127#endif
128
129  registrar_.Add(this,
130                 content::NOTIFICATION_LOAD_STOP,
131                 content::Source<NavigationController>(
132                     &web_contents->GetController()));
133
134  registrar_.Add(this,
135                 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
136                 content::Source<CrxInstaller>(NULL));
137
138  registrar_.Add(this,
139                 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
140                 content::NotificationService::AllSources());
141
142  registrar_.Add(this,
143                 chrome::NOTIFICATION_EXTENSION_UNLOADED,
144                 content::NotificationService::AllSources());
145}
146
147TabHelper::~TabHelper() {
148#if defined(ENABLE_EXTENSIONS)
149  RemoveScriptExecutionObserver(ActivityLog::GetInstance(profile_));
150#endif
151}
152
153void TabHelper::CreateApplicationShortcuts() {
154  DCHECK(CanCreateApplicationShortcuts());
155  NavigationEntry* entry =
156      web_contents()->GetController().GetLastCommittedEntry();
157  if (!entry)
158    return;
159
160  pending_web_app_action_ = CREATE_SHORTCUT;
161
162  // Start fetching web app info for CreateApplicationShortcut dialog and show
163  // the dialog when the data is available in OnDidGetApplicationInfo.
164  GetApplicationInfo(entry->GetPageID());
165}
166
167void TabHelper::CreateHostedAppFromWebContents() {
168  DCHECK(CanCreateApplicationShortcuts());
169  NavigationEntry* entry =
170      web_contents()->GetController().GetLastCommittedEntry();
171  if (!entry)
172    return;
173
174  pending_web_app_action_ = CREATE_HOSTED_APP;
175
176  // Start fetching web app info for CreateApplicationShortcut dialog and show
177  // the dialog when the data is available in OnDidGetApplicationInfo.
178  GetApplicationInfo(entry->GetPageID());
179}
180
181bool TabHelper::CanCreateApplicationShortcuts() const {
182#if defined(OS_MACOSX)
183  return false;
184#else
185  return web_app::IsValidUrl(web_contents()->GetURL()) &&
186      pending_web_app_action_ == NONE;
187#endif
188}
189
190void TabHelper::SetExtensionApp(const Extension* extension) {
191  DCHECK(!extension || AppLaunchInfo::GetFullLaunchURL(extension).is_valid());
192  extension_app_ = extension;
193
194  UpdateExtensionAppIcon(extension_app_);
195
196  content::NotificationService::current()->Notify(
197      chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
198      content::Source<TabHelper>(this),
199      content::NotificationService::NoDetails());
200}
201
202void TabHelper::SetExtensionAppById(const std::string& extension_app_id) {
203  const Extension* extension = GetExtension(extension_app_id);
204  if (extension)
205    SetExtensionApp(extension);
206}
207
208void TabHelper::SetExtensionAppIconById(const std::string& extension_app_id) {
209  const Extension* extension = GetExtension(extension_app_id);
210  if (extension)
211    UpdateExtensionAppIcon(extension);
212}
213
214SkBitmap* TabHelper::GetExtensionAppIcon() {
215  if (extension_app_icon_.empty())
216    return NULL;
217
218  return &extension_app_icon_;
219}
220
221void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) {
222  SetTabId(render_view_host);
223}
224
225void TabHelper::DidNavigateMainFrame(
226    const content::LoadCommittedDetails& details,
227    const content::FrameNavigateParams& params) {
228#if defined(ENABLE_EXTENSIONS)
229  if (ExtensionSystem::Get(profile_)->extension_service() &&
230      RulesRegistryService::Get(profile_)) {
231    RulesRegistryService::Get(profile_)->content_rules_registry()->
232        DidNavigateMainFrame(web_contents(), details, params);
233  }
234#endif  // defined(ENABLE_EXTENSIONS)
235
236  if (details.is_in_page)
237    return;
238
239  Profile* profile =
240      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
241  ExtensionService* service = profile->GetExtensionService();
242  if (!service)
243    return;
244
245  ExtensionActionManager* extension_action_manager =
246      ExtensionActionManager::Get(profile);
247  for (ExtensionSet::const_iterator it = service->extensions()->begin();
248       it != service->extensions()->end(); ++it) {
249    ExtensionAction* browser_action =
250        extension_action_manager->GetBrowserAction(*it->get());
251    if (browser_action) {
252      browser_action->ClearAllValuesForTab(SessionID::IdForTab(web_contents()));
253      content::NotificationService::current()->Notify(
254          chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
255          content::Source<ExtensionAction>(browser_action),
256          content::NotificationService::NoDetails());
257    }
258  }
259}
260
261bool TabHelper::OnMessageReceived(const IPC::Message& message) {
262  bool handled = true;
263  IPC_BEGIN_MESSAGE_MAP(TabHelper, message)
264    IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidGetApplicationInfo,
265                        OnDidGetApplicationInfo)
266    IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall,
267                        OnInlineWebstoreInstall)
268    IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState,
269                        OnGetAppInstallState);
270    IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
271    IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting,
272                        OnContentScriptsExecuting)
273    IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
274                        OnWatchedPageChange)
275    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DetailedConsoleMessageAdded,
276                        OnDetailedConsoleMessageAdded)
277    IPC_MESSAGE_UNHANDLED(handled = false)
278  IPC_END_MESSAGE_MAP()
279  return handled;
280}
281
282void TabHelper::DidCloneToNewWebContents(WebContents* old_web_contents,
283                                         WebContents* new_web_contents) {
284  // When the WebContents that this is attached to is cloned, give the new clone
285  // a TabHelper and copy state over.
286  CreateForWebContents(new_web_contents);
287  TabHelper* new_helper = FromWebContents(new_web_contents);
288
289  new_helper->SetExtensionApp(extension_app());
290  new_helper->extension_app_icon_ = extension_app_icon_;
291}
292
293void TabHelper::OnDidGetApplicationInfo(int32 page_id,
294                                        const WebApplicationInfo& info) {
295  // Android does not implement BrowserWindow.
296#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
297  web_app_info_ = info;
298
299  NavigationEntry* entry =
300      web_contents()->GetController().GetLastCommittedEntry();
301  if (!entry || (entry->GetPageID() != page_id))
302    return;
303
304  switch (pending_web_app_action_) {
305    case CREATE_SHORTCUT: {
306      chrome::ShowCreateWebAppShortcutsDialog(
307          web_contents()->GetView()->GetTopLevelNativeWindow(),
308          web_contents());
309      break;
310    }
311    case CREATE_HOSTED_APP: {
312      CreateHostedApp(info);
313      break;
314    }
315    case UPDATE_SHORTCUT: {
316      web_app::UpdateShortcutForTabContents(web_contents());
317      break;
318    }
319    default:
320      NOTREACHED();
321      break;
322  }
323
324  // The hosted app action will be cleared once the installation completes or
325  // fails.
326  if (pending_web_app_action_ != CREATE_HOSTED_APP)
327    pending_web_app_action_ = NONE;
328#endif
329}
330
331void TabHelper::CreateHostedApp(const WebApplicationInfo& info) {
332  ShellIntegration::ShortcutInfo shortcut_info;
333  web_app::GetShortcutInfoForTab(web_contents(), &shortcut_info);
334  WebApplicationInfo web_app_info;
335
336  web_app_info.is_bookmark_app = true;
337  web_app_info.app_url = shortcut_info.url;
338  web_app_info.title = shortcut_info.title;
339  web_app_info.urls.push_back(web_app_info.app_url);
340
341  // TODO(calamity): this should attempt to download the best icon that it can
342  // from |info.icons| rather than just using the favicon as it scales up badly.
343  // Fix this once |info.icons| gets populated commonly.
344
345  // Get the smallest icon in the icon family (should have only 1).
346  const gfx::Image* icon = shortcut_info.favicon.GetBest(0, 0);
347  SkBitmap bitmap = icon ? icon->AsBitmap() : SkBitmap();
348
349  if (!icon->IsEmpty()) {
350    WebApplicationInfo::IconInfo icon_info;
351    icon_info.data = bitmap;
352    icon_info.width = icon_info.data.width();
353    icon_info.height = icon_info.data.height();
354    web_app_info.icons.push_back(icon_info);
355  }
356
357  ExtensionService* service = profile_->GetExtensionService();
358  scoped_refptr<extensions::CrxInstaller> installer(
359      extensions::CrxInstaller::CreateSilent(service));
360  installer->set_error_on_unsupported_requirements(true);
361  installer->InstallWebApp(web_app_info);
362}
363
364void TabHelper::OnInlineWebstoreInstall(
365    int install_id,
366    int return_route_id,
367    const std::string& webstore_item_id,
368    const GURL& requestor_url) {
369  WebstoreStandaloneInstaller::Callback callback =
370      base::Bind(&TabHelper::OnInlineInstallComplete, base::Unretained(this),
371                 install_id, return_route_id);
372  scoped_refptr<WebstoreInlineInstaller> installer(
373      webstore_inline_installer_factory_->CreateInstaller(
374          web_contents(),
375          webstore_item_id,
376          requestor_url,
377          callback));
378  installer->BeginInstall();
379}
380
381void TabHelper::OnGetAppInstallState(const GURL& requestor_url,
382                                     int return_route_id,
383                                     int callback_id) {
384  Profile* profile =
385      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
386  ExtensionService* extension_service = profile->GetExtensionService();
387  const ExtensionSet* extensions = extension_service->extensions();
388  const ExtensionSet* disabled = extension_service->disabled_extensions();
389
390  std::string state;
391  if (extensions->GetHostedAppByURL(requestor_url))
392    state = extension_misc::kAppStateInstalled;
393  else if (disabled->GetHostedAppByURL(requestor_url))
394    state = extension_misc::kAppStateDisabled;
395  else
396    state = extension_misc::kAppStateNotInstalled;
397
398  Send(new ExtensionMsg_GetAppInstallStateResponse(
399      return_route_id, state, callback_id));
400}
401
402void TabHelper::OnRequest(const ExtensionHostMsg_Request_Params& request) {
403  extension_function_dispatcher_.Dispatch(request,
404                                          web_contents()->GetRenderViewHost());
405}
406
407void TabHelper::OnContentScriptsExecuting(
408    const ScriptExecutionObserver::ExecutingScriptsMap& executing_scripts_map,
409    int32 on_page_id,
410    const GURL& on_url) {
411  FOR_EACH_OBSERVER(ScriptExecutionObserver, script_execution_observers_,
412                    OnScriptsExecuted(web_contents(),
413                                      executing_scripts_map,
414                                      on_page_id,
415                                      on_url));
416}
417
418void TabHelper::OnWatchedPageChange(
419    const std::vector<std::string>& css_selectors) {
420#if defined(ENABLE_EXTENSIONS)
421  if (ExtensionSystem::Get(profile_)->extension_service() &&
422      RulesRegistryService::Get(profile_)) {
423    RulesRegistryService::Get(profile_)->content_rules_registry()->Apply(
424        web_contents(), css_selectors);
425  }
426#endif  // defined(ENABLE_EXTENSIONS)
427}
428
429void TabHelper::OnDetailedConsoleMessageAdded(
430    const base::string16& message,
431    const base::string16& source,
432    const StackTrace& stack_trace,
433    int32 severity_level) {
434  if (IsSourceFromAnExtension(source)) {
435    content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
436    ErrorConsole::Get(profile_)->ReportError(
437        scoped_ptr<ExtensionError>(new RuntimeError(
438            extension_app_ ? extension_app_->id() : std::string(),
439            profile_->IsOffTheRecord(),
440            source,
441            message,
442            stack_trace,
443            web_contents() ?
444                web_contents()->GetLastCommittedURL() : GURL::EmptyGURL(),
445            static_cast<logging::LogSeverity>(severity_level),
446            rvh->GetRoutingID(),
447            rvh->GetProcess()->GetID())));
448  }
449}
450
451const Extension* TabHelper::GetExtension(const std::string& extension_app_id) {
452  if (extension_app_id.empty())
453    return NULL;
454
455  Profile* profile =
456      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
457  ExtensionService* extension_service = profile->GetExtensionService();
458  if (!extension_service || !extension_service->is_ready())
459    return NULL;
460
461  const Extension* extension =
462      extension_service->GetExtensionById(extension_app_id, false);
463  return extension;
464}
465
466void TabHelper::UpdateExtensionAppIcon(const Extension* extension) {
467  extension_app_icon_.reset();
468  // Ensure previously enqueued callbacks are ignored.
469  image_loader_ptr_factory_.InvalidateWeakPtrs();
470
471  // Enqueue OnImageLoaded callback.
472  if (extension) {
473    Profile* profile =
474        Profile::FromBrowserContext(web_contents()->GetBrowserContext());
475    extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile);
476    loader->LoadImageAsync(
477        extension,
478        IconsInfo::GetIconResource(extension,
479                                   extension_misc::EXTENSION_ICON_SMALLISH,
480                                   ExtensionIconSet::MATCH_EXACTLY),
481        gfx::Size(extension_misc::EXTENSION_ICON_SMALLISH,
482                  extension_misc::EXTENSION_ICON_SMALLISH),
483        base::Bind(&TabHelper::OnImageLoaded,
484                   image_loader_ptr_factory_.GetWeakPtr()));
485  }
486}
487
488void TabHelper::SetAppIcon(const SkBitmap& app_icon) {
489  extension_app_icon_ = app_icon;
490  web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
491}
492
493void TabHelper::SetWebstoreInlineInstallerFactoryForTests(
494    WebstoreInlineInstallerFactory* factory) {
495  webstore_inline_installer_factory_.reset(factory);
496}
497
498void TabHelper::OnImageLoaded(const gfx::Image& image) {
499  if (!image.IsEmpty()) {
500    extension_app_icon_ = *image.ToSkBitmap();
501    web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
502  }
503}
504
505WindowController* TabHelper::GetExtensionWindowController() const  {
506  return ExtensionTabUtil::GetWindowControllerOfTab(web_contents());
507}
508
509void TabHelper::OnInlineInstallComplete(int install_id,
510                                        int return_route_id,
511                                        bool success,
512                                        const std::string& error) {
513  Send(new ExtensionMsg_InlineWebstoreInstallResponse(
514      return_route_id, install_id, success, success ? std::string() : error));
515}
516
517WebContents* TabHelper::GetAssociatedWebContents() const {
518  return web_contents();
519}
520
521void TabHelper::GetApplicationInfo(int32 page_id) {
522  Send(new ExtensionMsg_GetApplicationInfo(routing_id(), page_id));
523}
524
525void TabHelper::Observe(int type,
526                        const content::NotificationSource& source,
527                        const content::NotificationDetails& details) {
528  switch (type) {
529    case content::NOTIFICATION_LOAD_STOP: {
530      const NavigationController& controller =
531          *content::Source<NavigationController>(source).ptr();
532      DCHECK_EQ(controller.GetWebContents(), web_contents());
533
534      if (pending_web_app_action_ == UPDATE_SHORTCUT) {
535        // Schedule a shortcut update when web application info is available if
536        // last committed entry is not NULL. Last committed entry could be NULL
537        // when an interstitial page is injected (e.g. bad https certificate,
538        // malware site etc). When this happens, we abort the shortcut update.
539        NavigationEntry* entry = controller.GetLastCommittedEntry();
540        if (entry)
541          GetApplicationInfo(entry->GetPageID());
542        else
543          pending_web_app_action_ = NONE;
544      }
545      break;
546    }
547    case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
548      if (pending_web_app_action_ != CREATE_HOSTED_APP)
549        return;
550
551      pending_web_app_action_ = NONE;
552
553      const Extension* extension =
554          content::Details<const Extension>(details).ptr();
555      if (!extension || !extension->from_bookmark())
556        return;
557
558      // If enabled, launch the app launcher and highlight the new app.
559      // Otherwise, open the chrome://apps page in a new foreground tab.
560      if (IsAppLauncherEnabled()) {
561        AppListService::Get(chrome::GetHostDesktopTypeForNativeView(
562            web_contents()->GetView()->GetNativeView()))->
563            ShowForProfile(profile_);
564
565        content::NotificationService::current()->Notify(
566            chrome::NOTIFICATION_APP_INSTALLED_TO_APPLIST,
567            content::Source<Profile>(profile_),
568            content::Details<const std::string>(&extension->id()));
569        return;
570      }
571
572      // Android does not implement browser_finder.cc.
573#if !defined(OS_ANDROID)
574      Browser* browser =
575          chrome::FindBrowserWithWebContents(web_contents());
576      if (browser) {
577        browser->OpenURL(
578            content::OpenURLParams(GURL(chrome::kChromeUIAppsURL),
579                                   content::Referrer(),
580                                   NEW_FOREGROUND_TAB,
581                                   content::PAGE_TRANSITION_LINK,
582                                   false));
583      }
584#endif
585    }
586    case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: {
587      if (pending_web_app_action_ == CREATE_HOSTED_APP)
588        pending_web_app_action_ = NONE;
589      break;
590    }
591    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
592      if (script_bubble_controller_) {
593        script_bubble_controller_->OnExtensionUnloaded(
594            content::Details<extensions::UnloadedExtensionInfo>(
595                details)->extension->id());
596        break;
597      }
598    }
599  }
600}
601
602void TabHelper::SetTabId(RenderViewHost* render_view_host) {
603  render_view_host->Send(
604      new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(),
605                                SessionID::IdForTab(web_contents())));
606}
607
608}  // namespace extensions
609