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/files/file_util.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/path_service.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/process/kill.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "chrome/browser/plugins/plugin_prefs.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/test/base/in_process_browser_test.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "content/public/browser/browser_child_process_host_iterator.h"
24 #include "content/public/browser/browser_thread.h"
25 #include "content/public/browser/child_process_data.h"
26 #include "content/public/browser/plugin_service.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/common/content_constants.h"
29 #include "content/public/common/content_paths.h"
30 #include "content/public/common/process_type.h"
31 #include "content/public/common/webplugininfo.h"
32 #include "content/public/test/browser_test_utils.h"
33 #include "content/public/test/test_utils.h"
34 #include "net/base/filename_util.h"
37 #include "ui/aura/window.h"
38 #include "ui/aura/window_tree_host.h"
41 using content::BrowserThread
;
45 class CallbackBarrier
: public base::RefCountedThreadSafe
<CallbackBarrier
> {
47 explicit CallbackBarrier(const base::Closure
& target_callback
)
48 : target_callback_(target_callback
),
49 outstanding_callbacks_(0),
53 base::Callback
<void(bool)> CreateCallback() {
54 outstanding_callbacks_
++;
55 return base::Bind(&CallbackBarrier::MayRunTargetCallback
, this);
59 friend class base::RefCountedThreadSafe
<CallbackBarrier
>;
62 EXPECT_TRUE(target_callback_
.is_null());
65 void MayRunTargetCallback(bool did_enable
) {
66 EXPECT_GT(outstanding_callbacks_
, 0);
67 did_enable_
= did_enable_
&& did_enable
;
68 if (--outstanding_callbacks_
== 0) {
69 EXPECT_TRUE(did_enable_
);
70 target_callback_
.Run();
71 target_callback_
.Reset();
75 base::Closure target_callback_
;
76 int outstanding_callbacks_
;
82 class ChromePluginTest
: public InProcessBrowserTest
{
86 static GURL
GetURL(const char* filename
) {
88 PathService::Get(content::DIR_TEST_DATA
, &path
);
89 path
= path
.AppendASCII("plugin").AppendASCII(filename
);
90 CHECK(base::PathExists(path
));
91 return net::FilePathToFileURL(path
);
94 static void LoadAndWait(Browser
* window
, const GURL
& url
, bool pass
) {
95 content::WebContents
* web_contents
=
96 window
->tab_strip_model()->GetActiveWebContents();
97 base::string16
expected_title(
98 base::ASCIIToUTF16(pass
? "OK" : "plugin_not_found"));
99 content::TitleWatcher
title_watcher(web_contents
, expected_title
);
100 title_watcher
.AlsoWaitForTitle(base::ASCIIToUTF16("FAIL"));
101 title_watcher
.AlsoWaitForTitle(base::ASCIIToUTF16(
102 pass
? "plugin_not_found" : "OK"));
103 ui_test_utils::NavigateToURL(window
, url
);
104 ASSERT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
107 static void CrashFlash() {
108 scoped_refptr
<content::MessageLoopRunner
> runner
=
109 new content::MessageLoopRunner
;
110 BrowserThread::PostTask(
113 base::Bind(&CrashFlashInternal
, runner
->QuitClosure()));
117 static void GetFlashPath(std::vector
<base::FilePath
>* paths
) {
119 std::vector
<content::WebPluginInfo
> plugins
= GetPlugins();
120 for (std::vector
<content::WebPluginInfo
>::const_iterator it
=
121 plugins
.begin(); it
!= plugins
.end(); ++it
) {
122 if (it
->name
== base::ASCIIToUTF16(content::kFlashPluginName
))
123 paths
->push_back(it
->path
);
127 static std::vector
<content::WebPluginInfo
> GetPlugins() {
128 std::vector
<content::WebPluginInfo
> plugins
;
129 scoped_refptr
<content::MessageLoopRunner
> runner
=
130 new content::MessageLoopRunner
;
131 content::PluginService::GetInstance()->GetPlugins(
132 base::Bind(&GetPluginsInfoCallback
, &plugins
, runner
->QuitClosure()));
137 static void EnableFlash(bool enable
, Profile
* profile
) {
138 std::vector
<base::FilePath
> paths
;
139 GetFlashPath(&paths
);
140 ASSERT_FALSE(paths
.empty());
142 PluginPrefs
* plugin_prefs
= PluginPrefs::GetForProfile(profile
).get();
143 scoped_refptr
<content::MessageLoopRunner
> runner
=
144 new content::MessageLoopRunner
;
145 scoped_refptr
<CallbackBarrier
> callback_barrier(
146 new CallbackBarrier(runner
->QuitClosure()));
147 for (std::vector
<base::FilePath
>::iterator iter
= paths
.begin();
148 iter
!= paths
.end(); ++iter
) {
149 plugin_prefs
->EnablePlugin(enable
, *iter
,
150 callback_barrier
->CreateCallback());
155 static void EnsureFlashProcessCount(int expected
) {
157 scoped_refptr
<content::MessageLoopRunner
> runner
=
158 new content::MessageLoopRunner
;
159 BrowserThread::PostTask(
162 base::Bind(&CountPluginProcesses
, &actual
, runner
->QuitClosure()));
164 ASSERT_EQ(expected
, actual
);
168 static void CrashFlashInternal(const base::Closure
& quit_task
) {
170 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
171 if (iter
.GetData().process_type
!= content::PROCESS_TYPE_PLUGIN
&&
172 iter
.GetData().process_type
!= content::PROCESS_TYPE_PPAPI_PLUGIN
) {
175 base::KillProcess(iter
.GetData().handle
, 0, true);
178 ASSERT_TRUE(found
) << "Didn't find Flash process!";
179 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_task
);
182 static void GetPluginsInfoCallback(
183 std::vector
<content::WebPluginInfo
>* rv
,
184 const base::Closure
& quit_task
,
185 const std::vector
<content::WebPluginInfo
>& plugins
) {
190 static void CountPluginProcesses(int* count
, const base::Closure
& quit_task
) {
191 for (content::BrowserChildProcessHostIterator iter
; !iter
.Done(); ++iter
) {
192 if (iter
.GetData().process_type
== content::PROCESS_TYPE_PLUGIN
||
193 iter
.GetData().process_type
== content::PROCESS_TYPE_PPAPI_PLUGIN
) {
197 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
, quit_task
);
201 // Tests a bunch of basic scenarios with Flash.
202 // This test fails under ASan on Mac, see http://crbug.com/147004.
203 // It fails elsewhere, too. See http://crbug.com/152071.
204 IN_PROC_BROWSER_TEST_F(ChromePluginTest
, DISABLED_Flash
) {
205 // Official builds always have bundled Flash.
206 #if !defined(OFFICIAL_BUILD)
207 std::vector
<base::FilePath
> flash_paths
;
208 GetFlashPath(&flash_paths
);
209 if (flash_paths
.empty()) {
210 LOG(INFO
) << "Test not running because couldn't find Flash.";
215 GURL url
= GetURL("flash.html");
216 EnsureFlashProcessCount(0);
219 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
220 EnsureFlashProcessCount(1);
221 Profile
* profile
= browser()->profile();
223 ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateBrowser(profile
), url
, true));
224 // Try an incognito window.
225 ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateIncognitoBrowser(), url
, true));
226 EnsureFlashProcessCount(1);
228 // Now kill Flash process and verify it reloads.
230 EnsureFlashProcessCount(0);
232 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
233 EnsureFlashProcessCount(1);
235 // Now try disabling it.
236 EnableFlash(false, profile
);
239 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, false));
240 EnsureFlashProcessCount(0);
242 // Now enable it again.
243 EnableFlash(true, profile
);
244 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url
, true));
245 EnsureFlashProcessCount(1);
248 #if defined(OFFICIAL_BUILD)
249 // Verify that the official builds have the known set of plugins.
250 IN_PROC_BROWSER_TEST_F(ChromePluginTest
, InstalledPlugins
) {
251 const char* expected
[] = {
255 "Chrome Remote Desktop Viewer",
256 #if defined(OS_CHROMEOS)
257 "Google Talk Plugin",
258 "Google Talk Plugin Video Accelerator",
263 std::vector
<content::WebPluginInfo
> plugins
= GetPlugins();
264 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(expected
); ++i
) {
266 for (; j
< plugins
.size(); ++j
) {
267 if (plugins
[j
].name
== base::ASCIIToUTF16(expected
[i
]))
270 ASSERT_TRUE(j
!= plugins
.size()) << "Didn't find " << expected
[i
];