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.
8 #include "base/callback.h"
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/path_service.h"
13 #include "base/process/kill.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/plugins/plugin_prefs.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/browser_child_process_host_iterator.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/child_process_data.h"
23 #include "content/public/browser/plugin_service.h"
24 #include "content/public/common/content_constants.h"
25 #include "content/public/common/content_paths.h"
26 #include "content/public/common/process_type.h"
27 #include "content/public/common/webplugininfo.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/test_utils.h"
30 #include "net/base/net_util.h"
32 using content::BrowserThread
;
36 class CallbackBarrier
: public base::RefCountedThreadSafe
<CallbackBarrier
> {
38 explicit CallbackBarrier(const base::Closure
& target_callback
)
39 : target_callback_(target_callback
),
40 outstanding_callbacks_(0),
44 base::Callback
<void(bool)> CreateCallback() {
45 outstanding_callbacks_
++;
46 return base::Bind(&CallbackBarrier::MayRunTargetCallback
, this);
50 friend class base::RefCountedThreadSafe
<CallbackBarrier
>;
53 EXPECT_TRUE(target_callback_
.is_null());
56 void MayRunTargetCallback(bool did_enable
) {
57 EXPECT_GT(outstanding_callbacks_
, 0);
58 did_enable_
= did_enable_
&& did_enable
;
59 if (--outstanding_callbacks_
== 0) {
60 EXPECT_TRUE(did_enable_
);
61 target_callback_
.Run();
62 target_callback_
.Reset();
66 base::Closure target_callback_
;
67 int outstanding_callbacks_
;
73 class ChromePluginTest
: public InProcessBrowserTest
{
77 static GURL
GetURL(const char* filename
) {
79 PathService::Get(content::DIR_TEST_DATA
, &path
);
80 path
= path
.AppendASCII("plugin").AppendASCII(filename
);
81 CHECK(base::PathExists(path
));
82 return net::FilePathToFileURL(path
);
85 static void LoadAndWait(Browser
* window
, const GURL
& url
, bool pass
) {
86 content::WebContents
* web_contents
=
87 window
->tab_strip_model()->GetActiveWebContents();
88 base::string16
expected_title(
89 base::ASCIIToUTF16(pass
? "OK" : "plugin_not_found"));
90 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
91 title_watcher
.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
92 title_watcher
.AlsoWaitForTitle(base::ASCIIToUTF16(
93 pass
? "plugin_not_found" : "OK"));
94 ui_test_utils::NavigateToURL(window
, url
);
95 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
98 static void CrashFlash() {
99 scoped_refptr
<content::MessageLoopRunner
> runner
=
100 new content::MessageLoopRunner
;
101 BrowserThread::PostTask(
104 base::Bind(&CrashFlashInternal
, runner
->QuitClosure()));
108 static void GetFlashPath(std::vector
<base::FilePath
>* paths
) {
110 std::vector
<content::WebPluginInfo
> plugins
= GetPlugins();
111 for (std::vector
<content::WebPluginInfo
>::const_iterator it
=
112 plugins
.begin(); it
!= plugins
.end(); ++it
) {
113 if (it
->name
== base::ASCIIToUTF16(content::kFlashPluginName
))
114 paths
->push_back(it
->path
);
118 static std::vector
<content::WebPluginInfo
> GetPlugins() {
119 std::vector
<content::WebPluginInfo
> plugins
;
120 scoped_refptr
<content::MessageLoopRunner
> runner
=
121 new content::MessageLoopRunner
;
122 content::PluginService::GetInstance()->GetPlugins(
123 base::Bind(&GetPluginsInfoCallback
, &plugins
, runner
->QuitClosure()));
128 static void EnableFlash(bool enable
, Profile
* profile
) {
129 std::vector
<base::FilePath
> paths
;
130 GetFlashPath(&paths
);
131 ASSERT_FALSE(paths
.empty());
133 PluginPrefs
* plugin_prefs
= PluginPrefs::GetForProfile(profile
).get();
134 scoped_refptr
<content::MessageLoopRunner
> runner
=
135 new content::MessageLoopRunner
;
136 scoped_refptr
<CallbackBarrier
> callback_barrier(
137 new CallbackBarrier(runner
->QuitClosure()));
138 for (std::vector
<base::FilePath
>::iterator iter
= paths
.begin();
139 iter
!= paths
.end(); ++iter
) {
140 plugin_prefs
->EnablePlugin(enable
, *iter
,
141 callback_barrier
->CreateCallback());
146 static void EnsureFlashProcessCount(int expected
) {
148 scoped_refptr
<content::MessageLoopRunner
> runner
=
149 new content::MessageLoopRunner
;
150 BrowserThread::PostTask(
153 base::Bind(&CountPluginProcesses
, &actual
, runner
->QuitClosure()));
155 ASSERT_EQ(expected
, actual
);
159 static void CrashFlashInternal(const base::Closure
& quit_task
) {
161 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
162 if (iter
.GetData().process_type
!= content::PROCESS_TYPE_PLUGIN
&&
163 iter
.GetData().process_type
!= content::PROCESS_TYPE_PPAPI_PLUGIN
) {
166 base::KillProcess(iter
.GetData().handle
, 0, true);
169 ASSERT_TRUE(found
) << "Didn't find Flash process!";
170 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_task
);
173 static void GetPluginsInfoCallback(
174 std::vector
<content::WebPluginInfo
>* rv
,
175 const base::Closure
& quit_task
,
176 const std::vector
<content::WebPluginInfo
>& plugins
) {
181 static void CountPluginProcesses(int* count
, const base::Closure
& quit_task
) {
182 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
183 if (iter
.GetData().process_type
== content::PROCESS_TYPE_PLUGIN
||
184 iter
.GetData().process_type
== content::PROCESS_TYPE_PPAPI_PLUGIN
) {
188 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_task
);
192 // Tests a bunch of basic scenarios with Flash.
193 // This test fails under ASan on Mac, see http://crbug.com/147004.
194 // It fails elsewhere, too. See http://crbug.com/152071.
195 IN_PROC_BROWSER_TEST_F(ChromePluginTest
, DISABLED_Flash
) {
196 // Official builds always have bundled Flash.
197 #if !defined(OFFICIAL_BUILD)
198 std::vector
<base::FilePath
> flash_paths
;
199 GetFlashPath(&flash_paths
);
200 if (flash_paths
.empty()) {
201 LOG(INFO
) << "Test not running because couldn't find Flash.";
206 GURL url
= GetURL("flash.html");
207 EnsureFlashProcessCount(0);
210 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
211 EnsureFlashProcessCount(1);
212 Profile
* profile
= browser()->profile();
214 ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateBrowser(profile
), url
, true));
215 // Try an incognito window.
216 ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateIncognitoBrowser(), url
, true));
217 EnsureFlashProcessCount(1);
219 // Now kill Flash process and verify it reloads.
221 EnsureFlashProcessCount(0);
223 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
224 EnsureFlashProcessCount(1);
226 // Now try disabling it.
227 EnableFlash(false, profile
);
230 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, false));
231 EnsureFlashProcessCount(0);
233 // Now enable it again.
234 EnableFlash(true, profile
);
235 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
236 EnsureFlashProcessCount(1);
239 // Verify that the official builds have the known set of plugins.
240 IN_PROC_BROWSER_TEST_F(ChromePluginTest
, InstalledPlugins
) {
241 #if !defined(OFFICIAL_BUILD)
244 const char* expected
[] = {
248 "Chrome Remote Desktop Viewer",
249 #if defined(OS_CHROMEOS)
250 "Google Talk Plugin",
251 "Google Talk Plugin Video Accelerator",
256 std::vector
<content::WebPluginInfo
> plugins
= GetPlugins();
257 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(expected
); ++i
) {
259 for (; j
< plugins
.size(); ++j
) {
260 if (plugins
[j
].name
== base::ASCIIToUTF16(expected
[i
]))
263 ASSERT_TRUE(j
!= plugins
.size()) << "Didn't find " << expected
[i
];