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 <vector> 6 7 #include "base/bind.h" 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" 35 36 #if defined(OS_WIN) 37 #include "ui/aura/window.h" 38 #include "ui/aura/window_tree_host.h" 39 #endif 40 41 using content::BrowserThread; 42 43 namespace { 44 45 class CallbackBarrier : public base::RefCountedThreadSafe<CallbackBarrier> { 46 public: 47 explicit CallbackBarrier(const base::Closure& target_callback) 48 : target_callback_(target_callback), 49 outstanding_callbacks_(0), 50 did_enable_(true) { 51 } 52 53 base::Callback<void(bool)> CreateCallback() { 54 outstanding_callbacks_++; 55 return base::Bind(&CallbackBarrier::MayRunTargetCallback, this); 56 } 57 58 private: 59 friend class base::RefCountedThreadSafe<CallbackBarrier>; 60 61 ~CallbackBarrier() { 62 EXPECT_TRUE(target_callback_.is_null()); 63 } 64 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(); 72 } 73 } 74 75 base::Closure target_callback_; 76 int outstanding_callbacks_; 77 bool did_enable_; 78 }; 79 80 } // namespace 81 82 class ChromePluginTest : public InProcessBrowserTest { 83 protected: 84 ChromePluginTest() {} 85 86 static GURL GetURL(const char* filename) { 87 base::FilePath path; 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); 92 } 93 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()); 105 } 106 107 static void CrashFlash() { 108 scoped_refptr<content::MessageLoopRunner> runner = 109 new content::MessageLoopRunner; 110 BrowserThread::PostTask( 111 BrowserThread::IO, 112 FROM_HERE, 113 base::Bind(&CrashFlashInternal, runner->QuitClosure())); 114 runner->Run(); 115 } 116 117 static void GetFlashPath(std::vector<base::FilePath>* paths) { 118 paths->clear(); 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); 124 } 125 } 126 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())); 133 runner->Run(); 134 return plugins; 135 } 136 137 static void EnableFlash(bool enable, Profile* profile) { 138 std::vector<base::FilePath> paths; 139 GetFlashPath(&paths); 140 ASSERT_FALSE(paths.empty()); 141 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()); 151 } 152 runner->Run(); 153 } 154 155 static void EnsureFlashProcessCount(int expected) { 156 int actual = 0; 157 scoped_refptr<content::MessageLoopRunner> runner = 158 new content::MessageLoopRunner; 159 BrowserThread::PostTask( 160 BrowserThread::IO, 161 FROM_HERE, 162 base::Bind(&CountPluginProcesses, &actual, runner->QuitClosure())); 163 runner->Run(); 164 ASSERT_EQ(expected, actual); 165 } 166 167 private: 168 static void CrashFlashInternal(const base::Closure& quit_task) { 169 bool found = false; 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) { 173 continue; 174 } 175 base::KillProcess(iter.GetData().handle, 0, true); 176 found = true; 177 } 178 ASSERT_TRUE(found) << "Didn't find Flash process!"; 179 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task); 180 } 181 182 static void GetPluginsInfoCallback( 183 std::vector<content::WebPluginInfo>* rv, 184 const base::Closure& quit_task, 185 const std::vector<content::WebPluginInfo>& plugins) { 186 *rv = plugins; 187 quit_task.Run(); 188 } 189 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) { 194 (*count)++; 195 } 196 } 197 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task); 198 } 199 }; 200 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."; 211 return; 212 } 213 #endif 214 215 GURL url = GetURL("flash.html"); 216 EnsureFlashProcessCount(0); 217 218 // Try a single tab. 219 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true)); 220 EnsureFlashProcessCount(1); 221 Profile* profile = browser()->profile(); 222 // Try another tab. 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); 227 228 // Now kill Flash process and verify it reloads. 229 CrashFlash(); 230 EnsureFlashProcessCount(0); 231 232 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true)); 233 EnsureFlashProcessCount(1); 234 235 // Now try disabling it. 236 EnableFlash(false, profile); 237 CrashFlash(); 238 239 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, false)); 240 EnsureFlashProcessCount(0); 241 242 // Now enable it again. 243 EnableFlash(true, profile); 244 ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true)); 245 EnsureFlashProcessCount(1); 246 } 247 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[] = { 252 "Chrome PDF Viewer", 253 "Shockwave Flash", 254 "Native Client", 255 "Chrome Remote Desktop Viewer", 256 #if defined(OS_CHROMEOS) 257 "Google Talk Plugin", 258 "Google Talk Plugin Video Accelerator", 259 "Netflix", 260 #endif 261 }; 262 263 std::vector<content::WebPluginInfo> plugins = GetPlugins(); 264 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) { 265 size_t j = 0; 266 for (; j < plugins.size(); ++j) { 267 if (plugins[j].name == base::ASCIIToUTF16(expected[i])) 268 break; 269 } 270 ASSERT_TRUE(j != plugins.size()) << "Didn't find " << expected[i]; 271 } 272 } 273 #endif 274