Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / plugins / plugin_observer.cc
blob21b5df704f9273a957ba24b0da44724ca83994b6
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/plugins/plugin_observer.h"
7 #include "base/auto_reset.h"
8 #include "base/bind.h"
9 #include "base/debug/crash_logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/infobars/infobar_service.h"
15 #include "chrome/browser/lifetime/application_lifetime.h"
16 #include "chrome/browser/metrics/metrics_services_manager.h"
17 #include "chrome/browser/plugins/plugin_finder.h"
18 #include "chrome/browser/plugins/plugin_infobar_delegates.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
21 #include "chrome/common/render_messages.h"
22 #include "chrome/common/url_constants.h"
23 #include "chrome/grit/generated_resources.h"
24 #include "components/content_settings/content/common/content_settings_messages.h"
25 #include "components/content_settings/core/browser/host_content_settings_map.h"
26 #include "components/infobars/core/confirm_infobar_delegate.h"
27 #include "components/infobars/core/infobar.h"
28 #include "components/infobars/core/simple_alert_infobar_delegate.h"
29 #include "content/public/browser/plugin_service.h"
30 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/browser/web_contents_delegate.h"
34 #include "content/public/common/webplugininfo.h"
35 #include "grit/theme_resources.h"
36 #include "ui/base/l10n/l10n_util.h"
38 #if defined(ENABLE_PLUGIN_INSTALLATION)
39 #if defined(OS_WIN)
40 #include "base/win/metro.h"
41 #endif
42 #include "chrome/browser/plugins/plugin_installer.h"
43 #include "chrome/browser/plugins/plugin_installer_observer.h"
44 #include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
45 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
47 using content::OpenURLParams;
48 using content::PluginService;
49 using content::Referrer;
50 using content::WebContents;
52 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PluginObserver);
54 namespace {
56 #if defined(ENABLE_PLUGIN_INSTALLATION)
58 // ConfirmInstallDialogDelegate ------------------------------------------------
60 class ConfirmInstallDialogDelegate : public TabModalConfirmDialogDelegate,
61 public WeakPluginInstallerObserver {
62 public:
63 ConfirmInstallDialogDelegate(content::WebContents* web_contents,
64 PluginInstaller* installer,
65 scoped_ptr<PluginMetadata> plugin_metadata);
67 // TabModalConfirmDialogDelegate methods:
68 base::string16 GetTitle() override;
69 base::string16 GetDialogMessage() override;
70 base::string16 GetAcceptButtonTitle() override;
71 void OnAccepted() override;
72 void OnCanceled() override;
74 // WeakPluginInstallerObserver methods:
75 void DownloadStarted() override;
76 void OnlyWeakObserversLeft() override;
78 private:
79 content::WebContents* web_contents_;
80 scoped_ptr<PluginMetadata> plugin_metadata_;
83 ConfirmInstallDialogDelegate::ConfirmInstallDialogDelegate(
84 content::WebContents* web_contents,
85 PluginInstaller* installer,
86 scoped_ptr<PluginMetadata> plugin_metadata)
87 : TabModalConfirmDialogDelegate(web_contents),
88 WeakPluginInstallerObserver(installer),
89 web_contents_(web_contents),
90 plugin_metadata_(plugin_metadata.Pass()) {
93 base::string16 ConfirmInstallDialogDelegate::GetTitle() {
94 return l10n_util::GetStringFUTF16(
95 IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_TITLE, plugin_metadata_->name());
98 base::string16 ConfirmInstallDialogDelegate::GetDialogMessage() {
99 return l10n_util::GetStringFUTF16(IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_MSG,
100 plugin_metadata_->name());
103 base::string16 ConfirmInstallDialogDelegate::GetAcceptButtonTitle() {
104 return l10n_util::GetStringUTF16(
105 IDS_PLUGIN_CONFIRM_INSTALL_DIALOG_ACCEPT_BUTTON);
108 void ConfirmInstallDialogDelegate::OnAccepted() {
109 installer()->StartInstalling(plugin_metadata_->plugin_url(), web_contents_);
112 void ConfirmInstallDialogDelegate::OnCanceled() {
115 void ConfirmInstallDialogDelegate::DownloadStarted() {
116 Cancel();
119 void ConfirmInstallDialogDelegate::OnlyWeakObserversLeft() {
120 Cancel();
122 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
124 // ReloadPluginInfoBarDelegate -------------------------------------------------
126 class ReloadPluginInfoBarDelegate : public ConfirmInfoBarDelegate {
127 public:
128 static void Create(InfoBarService* infobar_service,
129 content::NavigationController* controller,
130 const base::string16& message);
132 private:
133 ReloadPluginInfoBarDelegate(content::NavigationController* controller,
134 const base::string16& message);
135 ~ReloadPluginInfoBarDelegate() override;
137 // ConfirmInfobarDelegate:
138 int GetIconId() const override;
139 base::string16 GetMessageText() const override;
140 int GetButtons() const override;
141 base::string16 GetButtonLabel(InfoBarButton button) const override;
142 bool Accept() override;
144 content::NavigationController* controller_;
145 base::string16 message_;
148 // static
149 void ReloadPluginInfoBarDelegate::Create(
150 InfoBarService* infobar_service,
151 content::NavigationController* controller,
152 const base::string16& message) {
153 infobar_service->AddInfoBar(
154 infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
155 new ReloadPluginInfoBarDelegate(controller, message))));
158 ReloadPluginInfoBarDelegate::ReloadPluginInfoBarDelegate(
159 content::NavigationController* controller,
160 const base::string16& message)
161 : controller_(controller),
162 message_(message) {}
164 ReloadPluginInfoBarDelegate::~ReloadPluginInfoBarDelegate(){ }
166 int ReloadPluginInfoBarDelegate::GetIconId() const {
167 return IDR_INFOBAR_PLUGIN_CRASHED;
170 base::string16 ReloadPluginInfoBarDelegate::GetMessageText() const {
171 return message_;
174 int ReloadPluginInfoBarDelegate::GetButtons() const {
175 return BUTTON_OK;
178 base::string16 ReloadPluginInfoBarDelegate::GetButtonLabel(
179 InfoBarButton button) const {
180 DCHECK_EQ(BUTTON_OK, button);
181 return l10n_util::GetStringUTF16(IDS_RELOAD_PAGE_WITH_PLUGIN);
184 bool ReloadPluginInfoBarDelegate::Accept() {
185 controller_->Reload(true);
186 return true;
189 } // namespace
191 // PluginObserver -------------------------------------------------------------
193 #if defined(ENABLE_PLUGIN_INSTALLATION)
194 class PluginObserver::PluginPlaceholderHost : public PluginInstallerObserver {
195 public:
196 PluginPlaceholderHost(PluginObserver* observer,
197 int routing_id,
198 base::string16 plugin_name,
199 PluginInstaller* installer)
200 : PluginInstallerObserver(installer),
201 observer_(observer),
202 routing_id_(routing_id) {
203 DCHECK(installer);
204 switch (installer->state()) {
205 case PluginInstaller::INSTALLER_STATE_IDLE: {
206 observer->Send(new ChromeViewMsg_FoundMissingPlugin(routing_id_,
207 plugin_name));
208 break;
210 case PluginInstaller::INSTALLER_STATE_DOWNLOADING: {
211 DownloadStarted();
212 break;
217 // PluginInstallerObserver methods:
218 void DownloadStarted() override {
219 observer_->Send(new ChromeViewMsg_StartedDownloadingPlugin(routing_id_));
222 void DownloadError(const std::string& msg) override {
223 observer_->Send(new ChromeViewMsg_ErrorDownloadingPlugin(routing_id_, msg));
226 void DownloadCancelled() override {
227 observer_->Send(new ChromeViewMsg_CancelledDownloadingPlugin(routing_id_));
230 void DownloadFinished() override {
231 observer_->Send(new ChromeViewMsg_FinishedDownloadingPlugin(routing_id_));
234 private:
235 // Weak pointer; owns us.
236 PluginObserver* observer_;
238 int routing_id_;
240 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
242 PluginObserver::PluginObserver(content::WebContents* web_contents)
243 : content::WebContentsObserver(web_contents),
244 weak_ptr_factory_(this) {
247 PluginObserver::~PluginObserver() {
248 #if defined(ENABLE_PLUGIN_INSTALLATION)
249 STLDeleteValues(&plugin_placeholders_);
250 #endif
253 void PluginObserver::RenderFrameCreated(
254 content::RenderFrameHost* render_frame_host) {
255 #if defined(OS_WIN)
256 // If the window belongs to the Ash desktop, before we navigate we need
257 // to tell the renderview that NPAPI plugins are not supported so it does
258 // not try to instantiate them. The final decision is actually done in
259 // the IO thread by PluginInfoMessageFilter of this proces,s but it's more
260 // complex to manage a map of Ash views in PluginInfoMessageFilter than
261 // just telling the renderer via IPC.
263 // TODO(shrikant): Implement solution which will help associate
264 // render_view_host/webcontents/view/window instance with host desktop.
265 // Refer to issue http://crbug.com/317940.
266 // When non-active tabs are restored they are not added in view/window parent
267 // hierarchy (chrome::CreateRestoredTab/CreateParams). Normally we traverse
268 // parent hierarchy to identify containing desktop (like in function
269 // chrome::GetHostDesktopTypeForNativeView).
270 // Possible issue with chrome::GetActiveDesktop, is that it's global
271 // state, which remembers last active desktop, which may break in scenarios
272 // where we have instances on both Ash and Native desktop.
274 // We will do both tests. Both have some factor of unreliability.
275 aura::Window* window = web_contents()->GetNativeView();
276 if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH ||
277 chrome::GetHostDesktopTypeForNativeView(window) ==
278 chrome::HOST_DESKTOP_TYPE_ASH) {
279 int routing_id = render_frame_host->GetRoutingID();
280 render_frame_host->Send(new ChromeViewMsg_NPAPINotSupported(routing_id));
282 #endif
285 void PluginObserver::PluginCrashed(const base::FilePath& plugin_path,
286 base::ProcessId plugin_pid) {
287 DCHECK(!plugin_path.value().empty());
289 base::string16 plugin_name =
290 PluginService::GetInstance()->GetPluginDisplayNameByPath(plugin_path);
291 base::string16 infobar_text;
292 #if defined(OS_WIN)
293 // Find out whether the plugin process is still alive.
294 // Note: Although the chances are slim, it is possible that after the plugin
295 // process died, |plugin_pid| has been reused by a new process. The
296 // consequence is that we will display |IDS_PLUGIN_DISCONNECTED_PROMPT| rather
297 // than |IDS_PLUGIN_CRASHED_PROMPT| to the user, which seems acceptable.
298 base::Process plugin_process =
299 base::Process::OpenWithAccess(plugin_pid,
300 PROCESS_QUERY_INFORMATION | SYNCHRONIZE);
301 bool is_running = false;
302 if (plugin_process.IsValid()) {
303 is_running =
304 base::GetTerminationStatus(plugin_process.Handle(), NULL) ==
305 base::TERMINATION_STATUS_STILL_RUNNING;
306 plugin_process.Close();
309 if (is_running) {
310 infobar_text = l10n_util::GetStringFUTF16(IDS_PLUGIN_DISCONNECTED_PROMPT,
311 plugin_name);
312 UMA_HISTOGRAM_COUNTS("Plugin.ShowDisconnectedInfobar", 1);
313 } else {
314 infobar_text = l10n_util::GetStringFUTF16(IDS_PLUGIN_CRASHED_PROMPT,
315 plugin_name);
316 UMA_HISTOGRAM_COUNTS("Plugin.ShowCrashedInfobar", 1);
318 #else
319 // Calling the POSIX version of base::GetTerminationStatus() may affect other
320 // code which is interested in the process termination status. (Please see the
321 // comment of the function.) Therefore, a better way is needed to distinguish
322 // disconnections from crashes.
323 infobar_text = l10n_util::GetStringFUTF16(IDS_PLUGIN_CRASHED_PROMPT,
324 plugin_name);
325 UMA_HISTOGRAM_COUNTS("Plugin.ShowCrashedInfobar", 1);
326 #endif
328 ReloadPluginInfoBarDelegate::Create(
329 InfoBarService::FromWebContents(web_contents()),
330 &web_contents()->GetController(),
331 infobar_text);
334 bool PluginObserver::OnMessageReceived(
335 const IPC::Message& message,
336 content::RenderFrameHost* render_frame_host) {
337 IPC_BEGIN_MESSAGE_MAP(PluginObserver, message)
338 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_BlockedOutdatedPlugin,
339 OnBlockedOutdatedPlugin)
340 #if defined(ENABLE_PLUGIN_INSTALLATION)
341 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RemovePluginPlaceholderHost,
342 OnRemovePluginPlaceholderHost)
343 #endif
344 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_OpenAboutPlugins,
345 OnOpenAboutPlugins)
346 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CouldNotLoadPlugin,
347 OnCouldNotLoadPlugin)
348 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_NPAPINotSupported,
349 OnNPAPINotSupported)
351 IPC_MESSAGE_UNHANDLED(return false)
352 IPC_END_MESSAGE_MAP()
354 return true;
357 void PluginObserver::OnBlockedOutdatedPlugin(int placeholder_id,
358 const std::string& identifier) {
359 #if defined(ENABLE_PLUGIN_INSTALLATION)
360 PluginFinder* finder = PluginFinder::GetInstance();
361 // Find plugin to update.
362 PluginInstaller* installer = NULL;
363 scoped_ptr<PluginMetadata> plugin;
364 if (finder->FindPluginWithIdentifier(identifier, &installer, &plugin)) {
365 plugin_placeholders_[placeholder_id] = new PluginPlaceholderHost(
366 this, placeholder_id, plugin->name(), installer);
367 OutdatedPluginInfoBarDelegate::Create(InfoBarService::FromWebContents(
368 web_contents()), installer, plugin.Pass());
369 } else {
370 NOTREACHED();
372 #else
373 // If we don't support third-party plugin installation, we shouldn't have
374 // outdated plugins.
375 NOTREACHED();
376 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
379 #if defined(ENABLE_PLUGIN_INSTALLATION)
380 void PluginObserver::OnRemovePluginPlaceholderHost(int placeholder_id) {
381 std::map<int, PluginPlaceholderHost*>::iterator it =
382 plugin_placeholders_.find(placeholder_id);
383 if (it == plugin_placeholders_.end()) {
384 NOTREACHED();
385 return;
387 delete it->second;
388 plugin_placeholders_.erase(it);
390 #endif // defined(ENABLE_PLUGIN_INSTALLATION)
392 void PluginObserver::OnOpenAboutPlugins() {
393 web_contents()->OpenURL(OpenURLParams(
394 GURL(chrome::kChromeUIPluginsURL),
395 content::Referrer::SanitizeForRequest(
396 GURL(chrome::kChromeUIPluginsURL),
397 content::Referrer(web_contents()->GetURL(),
398 blink::WebReferrerPolicyDefault)),
399 NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_AUTO_BOOKMARK, false));
402 void PluginObserver::OnCouldNotLoadPlugin(const base::FilePath& plugin_path) {
403 g_browser_process->GetMetricsServicesManager()->OnPluginLoadingError(
404 plugin_path);
405 base::string16 plugin_name =
406 PluginService::GetInstance()->GetPluginDisplayNameByPath(plugin_path);
407 SimpleAlertInfoBarDelegate::Create(
408 InfoBarService::FromWebContents(web_contents()),
409 IDR_INFOBAR_PLUGIN_CRASHED,
410 l10n_util::GetStringFUTF16(IDS_PLUGIN_INITIALIZATION_ERROR_PROMPT,
411 plugin_name),
412 true);
415 void PluginObserver::OnNPAPINotSupported(const std::string& identifier) {
416 #if defined(OS_WIN) && defined(ENABLE_PLUGIN_INSTALLATION)
417 #if !defined(USE_AURA)
418 DCHECK(base::win::IsMetroProcess());
419 #endif
421 scoped_ptr<PluginMetadata> plugin;
422 bool ret = PluginFinder::GetInstance()->FindPluginWithIdentifier(
423 identifier, NULL, &plugin);
424 DCHECK(ret);
426 PluginMetroModeInfoBarDelegate::Create(
427 InfoBarService::FromWebContents(web_contents()),
428 PluginMetroModeInfoBarDelegate::DESKTOP_MODE_REQUIRED, plugin->name());
429 #endif