Home | History | Annotate | Download | only in browser
      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/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"
     31 
     32 using content::BrowserThread;
     33 
     34 namespace {
     35 
     36 class CallbackBarrier : public base::RefCountedThreadSafe<CallbackBarrier> {
     37  public:
     38   explicit CallbackBarrier(const base::Closure& target_callback)
     39       : target_callback_(target_callback),
     40         outstanding_callbacks_(0),
     41         did_enable_(true) {
     42   }
     43 
     44   base::Callback<void(bool)> CreateCallback() {
     45     outstanding_callbacks_++;
     46     return base::Bind(&CallbackBarrier::MayRunTargetCallback, this);
     47   }
     48 
     49  private:
     50   friend class base::RefCountedThreadSafe<CallbackBarrier>;
     51 
     52   ~CallbackBarrier() {
     53     EXPECT_TRUE(target_callback_.is_null());
     54   }
     55 
     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();
     63     }
     64   }
     65 
     66   base::Closure target_callback_;
     67   int outstanding_callbacks_;
     68   bool did_enable_;
     69 };
     70 
     71 }  // namespace
     72 
     73 class ChromePluginTest : public InProcessBrowserTest {
     74  protected:
     75   ChromePluginTest() {}
     76 
     77   static GURL GetURL(const char* filename) {
     78     base::FilePath path;
     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);
     83   }
     84 
     85   static void LoadAndWait(Browser* window, const GURL& url, bool pass) {
     86     content::WebContents* web_contents =
     87         window->tab_strip_model()->GetActiveWebContents();
     88     string16 expected_title(ASCIIToUTF16(pass ? "OK" : "plugin_not_found"));
     89     content::TitleWatcher title_watcher(web_contents, expected_title);
     90     title_watcher.AlsoWaitForTitle(ASCIIToUTF16("FAIL"));
     91     title_watcher.AlsoWaitForTitle(ASCIIToUTF16(
     92         pass ? "plugin_not_found" : "OK"));
     93     ui_test_utils::NavigateToURL(window, url);
     94     ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
     95   }
     96 
     97   static void CrashFlash() {
     98     scoped_refptr<content::MessageLoopRunner> runner =
     99         new content::MessageLoopRunner;
    100     BrowserThread::PostTask(
    101         BrowserThread::IO,
    102         FROM_HERE,
    103         base::Bind(&CrashFlashInternal, runner->QuitClosure()));
    104     runner->Run();
    105   }
    106 
    107   static void GetFlashPath(std::vector<base::FilePath>* paths) {
    108     paths->clear();
    109     std::vector<content::WebPluginInfo> plugins = GetPlugins();
    110     for (std::vector<content::WebPluginInfo>::const_iterator it =
    111              plugins.begin(); it != plugins.end(); ++it) {
    112       if (it->name == ASCIIToUTF16(content::kFlashPluginName))
    113         paths->push_back(it->path);
    114     }
    115   }
    116 
    117   static std::vector<content::WebPluginInfo> GetPlugins() {
    118     std::vector<content::WebPluginInfo> plugins;
    119     scoped_refptr<content::MessageLoopRunner> runner =
    120         new content::MessageLoopRunner;
    121     content::PluginService::GetInstance()->GetPlugins(
    122         base::Bind(&GetPluginsInfoCallback, &plugins, runner->QuitClosure()));
    123     runner->Run();
    124     return plugins;
    125   }
    126 
    127   static void EnableFlash(bool enable, Profile* profile) {
    128     std::vector<base::FilePath> paths;
    129     GetFlashPath(&paths);
    130     ASSERT_FALSE(paths.empty());
    131 
    132     PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile).get();
    133     scoped_refptr<content::MessageLoopRunner> runner =
    134         new content::MessageLoopRunner;
    135     scoped_refptr<CallbackBarrier> callback_barrier(
    136         new CallbackBarrier(runner->QuitClosure()));
    137     for (std::vector<base::FilePath>::iterator iter = paths.begin();
    138          iter != paths.end(); ++iter) {
    139       plugin_prefs->EnablePlugin(enable, *iter,
    140                                  callback_barrier->CreateCallback());
    141     }
    142     runner->Run();
    143   }
    144 
    145   static void EnsureFlashProcessCount(int expected) {
    146     int actual = 0;
    147     scoped_refptr<content::MessageLoopRunner> runner =
    148         new content::MessageLoopRunner;
    149     BrowserThread::PostTask(
    150         BrowserThread::IO,
    151         FROM_HERE,
    152         base::Bind(&CountPluginProcesses, &actual, runner->QuitClosure()));
    153     runner->Run();
    154     ASSERT_EQ(expected, actual);
    155   }
    156 
    157  private:
    158   static void CrashFlashInternal(const base::Closure& quit_task) {
    159     bool found = false;
    160     for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
    161       if (iter.GetData().process_type != content::PROCESS_TYPE_PLUGIN &&
    162           iter.GetData().process_type != content::PROCESS_TYPE_PPAPI_PLUGIN) {
    163         continue;
    164       }
    165       base::KillProcess(iter.GetData().handle, 0, true);
    166       found = true;
    167     }
    168     ASSERT_TRUE(found) << "Didn't find Flash process!";
    169     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task);
    170   }
    171 
    172   static void GetPluginsInfoCallback(
    173       std::vector<content::WebPluginInfo>* rv,
    174       const base::Closure& quit_task,
    175       const std::vector<content::WebPluginInfo>& plugins) {
    176     *rv = plugins;
    177     quit_task.Run();
    178   }
    179 
    180   static void CountPluginProcesses(int* count, const base::Closure& quit_task) {
    181     for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
    182       if (iter.GetData().process_type == content::PROCESS_TYPE_PLUGIN ||
    183           iter.GetData().process_type == content::PROCESS_TYPE_PPAPI_PLUGIN) {
    184         (*count)++;
    185       }
    186     }
    187     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task);
    188   }
    189 };
    190 
    191 // Tests a bunch of basic scenarios with Flash.
    192 // This test fails under ASan on Mac, see http://crbug.com/147004.
    193 // It fails elsewhere, too.  See http://crbug.com/152071.
    194 IN_PROC_BROWSER_TEST_F(ChromePluginTest, DISABLED_Flash) {
    195   // Official builds always have bundled Flash.
    196 #if !defined(OFFICIAL_BUILD)
    197   std::vector<base::FilePath> flash_paths;
    198   GetFlashPath(&flash_paths);
    199   if (flash_paths.empty()) {
    200     LOG(INFO) << "Test not running because couldn't find Flash.";
    201     return;
    202   }
    203 #endif
    204 
    205   GURL url = GetURL("flash.html");
    206   EnsureFlashProcessCount(0);
    207 
    208   // Try a single tab.
    209   ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
    210   EnsureFlashProcessCount(1);
    211   Profile* profile = browser()->profile();
    212   // Try another tab.
    213   ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateBrowser(profile), url, true));
    214   // Try an incognito window.
    215   ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateIncognitoBrowser(), url, true));
    216   EnsureFlashProcessCount(1);
    217 
    218   // Now kill Flash process and verify it reloads.
    219   CrashFlash();
    220   EnsureFlashProcessCount(0);
    221 
    222   ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
    223   EnsureFlashProcessCount(1);
    224 
    225   // Now try disabling it.
    226   EnableFlash(false, profile);
    227   CrashFlash();
    228 
    229   ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, false));
    230   EnsureFlashProcessCount(0);
    231 
    232   // Now enable it again.
    233   EnableFlash(true, profile);
    234   ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
    235   EnsureFlashProcessCount(1);
    236 }
    237 
    238 // Verify that the official builds have the known set of plugins.
    239 IN_PROC_BROWSER_TEST_F(ChromePluginTest, InstalledPlugins) {
    240 #if !defined(OFFICIAL_BUILD)
    241   return;
    242 #endif
    243   const char* expected[] = {
    244     "Chrome PDF Viewer",
    245     "Shockwave Flash",
    246     "Native Client",
    247     "Chrome Remote Desktop Viewer",
    248 #if defined(OS_CHROMEOS)
    249     "Google Talk Plugin",
    250     "Google Talk Plugin Video Accelerator",
    251     "Netflix",
    252 #endif
    253   };
    254 
    255   std::vector<content::WebPluginInfo> plugins = GetPlugins();
    256   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) {
    257     size_t j = 0;
    258     for (; j < plugins.size(); ++j) {
    259       if (plugins[j].name == ASCIIToUTF16(expected[i]))
    260         break;
    261     }
    262     ASSERT_TRUE(j != plugins.size()) << "Didn't find " << expected[i];
    263   }
    264 }
    265