Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / extensions / tab_helper.cc
blobfda6175796dd255c2253775a8135e00c18a55138
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.
5 #include "chrome/browser/extensions/tab_helper.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/extensions/activity_log/activity_log.h"
13 #include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
14 #include "chrome/browser/extensions/api/declarative_content/content_rules_registry.h"
15 #include "chrome/browser/extensions/api/webstore/webstore_api.h"
16 #include "chrome/browser/extensions/bookmark_app_helper.h"
17 #include "chrome/browser/extensions/error_console/error_console.h"
18 #include "chrome/browser/extensions/extension_action.h"
19 #include "chrome/browser/extensions/extension_action_manager.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_tab_util.h"
22 #include "chrome/browser/extensions/image_loader.h"
23 #include "chrome/browser/extensions/page_action_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/browser_commands.h"
32 #include "chrome/browser/ui/browser_dialogs.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/browser_window.h"
35 #include "chrome/browser/ui/host_desktop.h"
36 #include "chrome/browser/web_applications/web_app.h"
37 #include "chrome/common/chrome_switches.h"
38 #include "chrome/common/extensions/chrome_extension_messages.h"
39 #include "chrome/common/extensions/extension_constants.h"
40 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
41 #include "chrome/common/render_messages.h"
42 #include "chrome/common/url_constants.h"
43 #include "content/public/browser/invalidate_type.h"
44 #include "content/public/browser/navigation_controller.h"
45 #include "content/public/browser/navigation_details.h"
46 #include "content/public/browser/navigation_entry.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/notification_source.h"
49 #include "content/public/browser/notification_types.h"
50 #include "content/public/browser/render_process_host.h"
51 #include "content/public/browser/render_view_host.h"
52 #include "content/public/browser/render_widget_host_view.h"
53 #include "content/public/browser/web_contents.h"
54 #include "content/public/common/frame_navigate_params.h"
55 #include "extensions/browser/extension_error.h"
56 #include "extensions/browser/extension_registry.h"
57 #include "extensions/browser/extension_system.h"
58 #include "extensions/common/extension.h"
59 #include "extensions/common/extension_icon_set.h"
60 #include "extensions/common/extension_messages.h"
61 #include "extensions/common/extension_resource.h"
62 #include "extensions/common/extension_urls.h"
63 #include "extensions/common/feature_switch.h"
64 #include "extensions/common/manifest_handlers/icons_handler.h"
66 #if defined(OS_CHROMEOS)
67 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
68 #endif
70 #if defined(OS_WIN)
71 #include "chrome/browser/web_applications/web_app_win.h"
72 #endif
74 using content::NavigationController;
75 using content::NavigationEntry;
76 using content::RenderViewHost;
77 using content::WebContents;
79 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper);
81 namespace extensions {
83 TabHelper::ScriptExecutionObserver::ScriptExecutionObserver(
84 TabHelper* tab_helper)
85 : tab_helper_(tab_helper) {
86 tab_helper_->AddScriptExecutionObserver(this);
89 TabHelper::ScriptExecutionObserver::ScriptExecutionObserver()
90 : tab_helper_(NULL) {
93 TabHelper::ScriptExecutionObserver::~ScriptExecutionObserver() {
94 if (tab_helper_)
95 tab_helper_->RemoveScriptExecutionObserver(this);
98 TabHelper::TabHelper(content::WebContents* web_contents)
99 : content::WebContentsObserver(web_contents),
100 extension_app_(NULL),
101 extension_function_dispatcher_(
102 Profile::FromBrowserContext(web_contents->GetBrowserContext()), this),
103 pending_web_app_action_(NONE),
104 script_executor_(new ScriptExecutor(web_contents,
105 &script_execution_observers_)),
106 location_bar_controller_(new PageActionController(web_contents)),
107 image_loader_ptr_factory_(this),
108 webstore_inline_installer_factory_(new WebstoreInlineInstallerFactory()) {
109 // The ActiveTabPermissionManager requires a session ID; ensure this
110 // WebContents has one.
111 SessionTabHelper::CreateForWebContents(web_contents);
112 if (web_contents->GetRenderViewHost())
113 SetTabId(web_contents->GetRenderViewHost());
114 active_tab_permission_granter_.reset(new ActiveTabPermissionGranter(
115 web_contents,
116 SessionID::IdForTab(web_contents),
117 Profile::FromBrowserContext(web_contents->GetBrowserContext())));
119 // If more classes need to listen to global content script activity, then
120 // a separate routing class with an observer interface should be written.
121 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
123 #if defined(ENABLE_EXTENSIONS)
124 AddScriptExecutionObserver(ActivityLog::GetInstance(profile_));
125 #endif
127 registrar_.Add(this,
128 content::NOTIFICATION_LOAD_STOP,
129 content::Source<NavigationController>(
130 &web_contents->GetController()));
133 TabHelper::~TabHelper() {
134 #if defined(ENABLE_EXTENSIONS)
135 RemoveScriptExecutionObserver(ActivityLog::GetInstance(profile_));
136 #endif
139 void TabHelper::CreateApplicationShortcuts() {
140 DCHECK(CanCreateApplicationShortcuts());
141 NavigationEntry* entry =
142 web_contents()->GetController().GetLastCommittedEntry();
143 if (!entry)
144 return;
146 pending_web_app_action_ = CREATE_SHORTCUT;
148 // Start fetching web app info for CreateApplicationShortcut dialog and show
149 // the dialog when the data is available in OnDidGetApplicationInfo.
150 GetApplicationInfo(entry->GetPageID());
153 void TabHelper::CreateHostedAppFromWebContents() {
154 DCHECK(CanCreateBookmarkApp());
155 NavigationEntry* entry =
156 web_contents()->GetController().GetLastCommittedEntry();
157 if (!entry)
158 return;
160 pending_web_app_action_ = CREATE_HOSTED_APP;
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());
167 bool TabHelper::CanCreateApplicationShortcuts() const {
168 #if defined(OS_MACOSX)
169 return false;
170 #else
171 return web_app::IsValidUrl(web_contents()->GetURL()) &&
172 pending_web_app_action_ == NONE;
173 #endif
176 bool TabHelper::CanCreateBookmarkApp() const {
177 #if defined(OS_MACOSX)
178 return false;
179 #else
180 return IsValidBookmarkAppUrl(web_contents()->GetURL()) &&
181 pending_web_app_action_ == NONE;
182 #endif
185 void TabHelper::SetExtensionApp(const Extension* extension) {
186 DCHECK(!extension || AppLaunchInfo::GetFullLaunchURL(extension).is_valid());
187 if (extension_app_ == extension)
188 return;
190 extension_app_ = extension;
192 UpdateExtensionAppIcon(extension_app_);
194 content::NotificationService::current()->Notify(
195 chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
196 content::Source<TabHelper>(this),
197 content::NotificationService::NoDetails());
200 void TabHelper::SetExtensionAppById(const std::string& extension_app_id) {
201 const Extension* extension = GetExtension(extension_app_id);
202 if (extension)
203 SetExtensionApp(extension);
206 void TabHelper::SetExtensionAppIconById(const std::string& extension_app_id) {
207 const Extension* extension = GetExtension(extension_app_id);
208 if (extension)
209 UpdateExtensionAppIcon(extension);
212 SkBitmap* TabHelper::GetExtensionAppIcon() {
213 if (extension_app_icon_.empty())
214 return NULL;
216 return &extension_app_icon_;
219 void TabHelper::FinishCreateBookmarkApp(
220 const extensions::Extension* extension,
221 const WebApplicationInfo& web_app_info) {
222 pending_web_app_action_ = NONE;
224 // There was an error with downloading the icons or installing the app.
225 if (!extension)
226 return;
228 #if defined(OS_CHROMEOS)
229 ChromeLauncherController::instance()->PinAppWithID(extension->id());
230 #endif
232 // Android does not implement browser_finder.cc.
233 #if !defined(OS_ANDROID)
234 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
235 if (browser) {
236 browser->window()->ShowBookmarkAppBubble(web_app_info, extension->id());
238 #endif
241 void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) {
242 SetTabId(render_view_host);
245 void TabHelper::DidNavigateMainFrame(
246 const content::LoadCommittedDetails& details,
247 const content::FrameNavigateParams& params) {
248 #if defined(ENABLE_EXTENSIONS)
249 if (ExtensionSystem::Get(profile_)->extension_service() &&
250 RulesRegistryService::Get(profile_)) {
251 RulesRegistryService::Get(profile_)->content_rules_registry()->
252 DidNavigateMainFrame(web_contents(), details, params);
254 #endif // defined(ENABLE_EXTENSIONS)
256 content::BrowserContext* context = web_contents()->GetBrowserContext();
257 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
258 const ExtensionSet& enabled_extensions = registry->enabled_extensions();
260 if (CommandLine::ForCurrentProcess()->HasSwitch(
261 switches::kEnableStreamlinedHostedApps)) {
262 #if !defined(OS_ANDROID)
263 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
264 if (browser && browser->is_app()) {
265 SetExtensionApp(registry->GetExtensionById(
266 web_app::GetExtensionIdFromApplicationName(browser->app_name()),
267 ExtensionRegistry::EVERYTHING));
268 } else {
269 UpdateExtensionAppIcon(
270 enabled_extensions.GetExtensionOrAppByURL(params.url));
272 #endif
273 } else {
274 UpdateExtensionAppIcon(
275 enabled_extensions.GetExtensionOrAppByURL(params.url));
278 if (details.is_in_page)
279 return;
281 ExtensionActionManager* extension_action_manager =
282 ExtensionActionManager::Get(Profile::FromBrowserContext(context));
283 for (ExtensionSet::const_iterator it = enabled_extensions.begin();
284 it != enabled_extensions.end();
285 ++it) {
286 ExtensionAction* browser_action =
287 extension_action_manager->GetBrowserAction(*it->get());
288 if (browser_action) {
289 browser_action->ClearAllValuesForTab(SessionID::IdForTab(web_contents()));
290 content::NotificationService::current()->Notify(
291 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
292 content::Source<ExtensionAction>(browser_action),
293 content::NotificationService::NoDetails());
298 bool TabHelper::OnMessageReceived(const IPC::Message& message) {
299 bool handled = true;
300 IPC_BEGIN_MESSAGE_MAP(TabHelper, message)
301 IPC_MESSAGE_HANDLER(ChromeExtensionHostMsg_DidGetApplicationInfo,
302 OnDidGetApplicationInfo)
303 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall,
304 OnInlineWebstoreInstall)
305 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState,
306 OnGetAppInstallState);
307 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
308 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting,
309 OnContentScriptsExecuting)
310 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
311 OnWatchedPageChange)
312 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DetailedConsoleMessageAdded,
313 OnDetailedConsoleMessageAdded)
314 IPC_MESSAGE_UNHANDLED(handled = false)
315 IPC_END_MESSAGE_MAP()
316 return handled;
319 void TabHelper::DidCloneToNewWebContents(WebContents* old_web_contents,
320 WebContents* new_web_contents) {
321 // When the WebContents that this is attached to is cloned, give the new clone
322 // a TabHelper and copy state over.
323 CreateForWebContents(new_web_contents);
324 TabHelper* new_helper = FromWebContents(new_web_contents);
326 new_helper->SetExtensionApp(extension_app());
327 new_helper->extension_app_icon_ = extension_app_icon_;
330 void TabHelper::OnDidGetApplicationInfo(int32 page_id,
331 const WebApplicationInfo& info) {
332 // Android does not implement BrowserWindow.
333 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
334 web_app_info_ = info;
336 NavigationEntry* entry =
337 web_contents()->GetController().GetLastCommittedEntry();
338 if (!entry || (entry->GetPageID() != page_id))
339 return;
341 switch (pending_web_app_action_) {
342 case CREATE_SHORTCUT: {
343 chrome::ShowCreateWebAppShortcutsDialog(
344 web_contents()->GetTopLevelNativeWindow(),
345 web_contents());
346 break;
348 case CREATE_HOSTED_APP: {
349 if (web_app_info_.app_url.is_empty())
350 web_app_info_.app_url = web_contents()->GetURL();
352 if (web_app_info_.title.empty())
353 web_app_info_.title = web_contents()->GetTitle();
354 if (web_app_info_.title.empty())
355 web_app_info_.title = base::UTF8ToUTF16(web_app_info_.app_url.spec());
357 bookmark_app_helper_.reset(new BookmarkAppHelper(
358 profile_->GetExtensionService(), web_app_info_, web_contents()));
359 bookmark_app_helper_->Create(base::Bind(
360 &TabHelper::FinishCreateBookmarkApp, base::Unretained(this)));
361 break;
363 case UPDATE_SHORTCUT: {
364 web_app::UpdateShortcutForTabContents(web_contents());
365 break;
367 default:
368 NOTREACHED();
369 break;
372 // The hosted app action will be cleared once the installation completes or
373 // fails.
374 if (pending_web_app_action_ != CREATE_HOSTED_APP)
375 pending_web_app_action_ = NONE;
376 #endif
379 void TabHelper::OnInlineWebstoreInstall(int install_id,
380 int return_route_id,
381 const std::string& webstore_item_id,
382 const GURL& requestor_url,
383 int listeners_mask) {
384 #if defined(ENABLE_EXTENSIONS)
385 // Check that the listener is reasonable. We should never get anything other
386 // than an install stage listener, a download listener, or both.
387 if ((listeners_mask & ~(api::webstore::INSTALL_STAGE_LISTENER |
388 api::webstore::DOWNLOAD_PROGRESS_LISTENER)) != 0) {
389 NOTREACHED();
390 return;
392 // Inform the Webstore API that an inline install is happening, in case the
393 // page requested status updates.
394 Profile* profile =
395 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
396 WebstoreAPI::Get(profile)->OnInlineInstallStart(
397 return_route_id, this, webstore_item_id, listeners_mask);
398 #endif
400 WebstoreStandaloneInstaller::Callback callback =
401 base::Bind(&TabHelper::OnInlineInstallComplete, base::Unretained(this),
402 install_id, return_route_id);
403 scoped_refptr<WebstoreInlineInstaller> installer(
404 webstore_inline_installer_factory_->CreateInstaller(
405 web_contents(),
406 webstore_item_id,
407 requestor_url,
408 callback));
409 installer->BeginInstall();
412 void TabHelper::OnGetAppInstallState(const GURL& requestor_url,
413 int return_route_id,
414 int callback_id) {
415 ExtensionRegistry* registry =
416 ExtensionRegistry::Get(web_contents()->GetBrowserContext());
417 const ExtensionSet& extensions = registry->enabled_extensions();
418 const ExtensionSet& disabled_extensions = registry->disabled_extensions();
420 std::string state;
421 if (extensions.GetHostedAppByURL(requestor_url))
422 state = extension_misc::kAppStateInstalled;
423 else if (disabled_extensions.GetHostedAppByURL(requestor_url))
424 state = extension_misc::kAppStateDisabled;
425 else
426 state = extension_misc::kAppStateNotInstalled;
428 Send(new ExtensionMsg_GetAppInstallStateResponse(
429 return_route_id, state, callback_id));
432 void TabHelper::OnRequest(const ExtensionHostMsg_Request_Params& request) {
433 extension_function_dispatcher_.Dispatch(request,
434 web_contents()->GetRenderViewHost());
437 void TabHelper::OnContentScriptsExecuting(
438 const ScriptExecutionObserver::ExecutingScriptsMap& executing_scripts_map,
439 int32 on_page_id,
440 const GURL& on_url) {
441 FOR_EACH_OBSERVER(ScriptExecutionObserver, script_execution_observers_,
442 OnScriptsExecuted(web_contents(),
443 executing_scripts_map,
444 on_page_id,
445 on_url));
448 void TabHelper::OnWatchedPageChange(
449 const std::vector<std::string>& css_selectors) {
450 #if defined(ENABLE_EXTENSIONS)
451 if (ExtensionSystem::Get(profile_)->extension_service() &&
452 RulesRegistryService::Get(profile_)) {
453 RulesRegistryService::Get(profile_)->content_rules_registry()->Apply(
454 web_contents(), css_selectors);
456 #endif // defined(ENABLE_EXTENSIONS)
459 void TabHelper::OnDetailedConsoleMessageAdded(
460 const base::string16& message,
461 const base::string16& source,
462 const StackTrace& stack_trace,
463 int32 severity_level) {
464 if (IsSourceFromAnExtension(source)) {
465 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
466 ErrorConsole::Get(profile_)->ReportError(
467 scoped_ptr<ExtensionError>(new RuntimeError(
468 extension_app_ ? extension_app_->id() : std::string(),
469 profile_->IsOffTheRecord(),
470 source,
471 message,
472 stack_trace,
473 web_contents() ?
474 web_contents()->GetLastCommittedURL() : GURL::EmptyGURL(),
475 static_cast<logging::LogSeverity>(severity_level),
476 rvh->GetRoutingID(),
477 rvh->GetProcess()->GetID())));
481 const Extension* TabHelper::GetExtension(const std::string& extension_app_id) {
482 if (extension_app_id.empty())
483 return NULL;
485 Profile* profile =
486 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
487 ExtensionService* extension_service = profile->GetExtensionService();
488 if (!extension_service || !extension_service->is_ready())
489 return NULL;
491 const Extension* extension =
492 extension_service->GetExtensionById(extension_app_id, false);
493 return extension;
496 void TabHelper::UpdateExtensionAppIcon(const Extension* extension) {
497 extension_app_icon_.reset();
498 // Ensure previously enqueued callbacks are ignored.
499 image_loader_ptr_factory_.InvalidateWeakPtrs();
501 // Enqueue OnImageLoaded callback.
502 if (extension) {
503 Profile* profile =
504 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
505 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile);
506 loader->LoadImageAsync(
507 extension,
508 IconsInfo::GetIconResource(extension,
509 extension_misc::EXTENSION_ICON_SMALL,
510 ExtensionIconSet::MATCH_BIGGER),
511 gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
512 extension_misc::EXTENSION_ICON_SMALL),
513 base::Bind(&TabHelper::OnImageLoaded,
514 image_loader_ptr_factory_.GetWeakPtr()));
518 void TabHelper::SetAppIcon(const SkBitmap& app_icon) {
519 extension_app_icon_ = app_icon;
520 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
523 void TabHelper::SetWebstoreInlineInstallerFactoryForTests(
524 WebstoreInlineInstallerFactory* factory) {
525 webstore_inline_installer_factory_.reset(factory);
528 void TabHelper::OnImageLoaded(const gfx::Image& image) {
529 if (!image.IsEmpty()) {
530 extension_app_icon_ = *image.ToSkBitmap();
531 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
535 WindowController* TabHelper::GetExtensionWindowController() const {
536 return ExtensionTabUtil::GetWindowControllerOfTab(web_contents());
539 void TabHelper::OnInlineInstallComplete(int install_id,
540 int return_route_id,
541 bool success,
542 const std::string& error) {
543 Send(new ExtensionMsg_InlineWebstoreInstallResponse(
544 return_route_id, install_id, success, success ? std::string() : error));
547 WebContents* TabHelper::GetAssociatedWebContents() const {
548 return web_contents();
551 void TabHelper::GetApplicationInfo(int32 page_id) {
552 Send(new ChromeExtensionMsg_GetApplicationInfo(routing_id(), page_id));
555 void TabHelper::Observe(int type,
556 const content::NotificationSource& source,
557 const content::NotificationDetails& details) {
558 switch (type) {
559 case content::NOTIFICATION_LOAD_STOP: {
560 const NavigationController& controller =
561 *content::Source<NavigationController>(source).ptr();
562 DCHECK_EQ(controller.GetWebContents(), web_contents());
564 if (pending_web_app_action_ == UPDATE_SHORTCUT) {
565 // Schedule a shortcut update when web application info is available if
566 // last committed entry is not NULL. Last committed entry could be NULL
567 // when an interstitial page is injected (e.g. bad https certificate,
568 // malware site etc). When this happens, we abort the shortcut update.
569 NavigationEntry* entry = controller.GetLastCommittedEntry();
570 if (entry)
571 GetApplicationInfo(entry->GetPageID());
572 else
573 pending_web_app_action_ = NONE;
575 break;
580 void TabHelper::SetTabId(RenderViewHost* render_view_host) {
581 render_view_host->Send(
582 new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(),
583 SessionID::IdForTab(web_contents())));
586 } // namespace extensions