fixup! Change content::PluginList to only run on the UI thread.

This commit is contained in:
deepak1556 2022-10-20 02:09:45 +09:00
Родитель 2ff24a33d0
Коммит 7b5ec87d4f
8 изменённых файлов: 82 добавлений и 761 удалений

Просмотреть файл

@ -613,6 +613,8 @@ source_set("electron_lib") {
if (enable_plugins) {
deps += [ "chromium_src:plugins" ]
sources += [
"shell/common/plugin_info.cc",
"shell/common/plugin_info.h",
"shell/renderer/pepper_helper.cc",
"shell/renderer/pepper_helper.h",
]

Просмотреть файл

@ -119,4 +119,3 @@ feat_ensure_mas_builds_of_the_same_application_can_use_safestorage.patch
fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch
preconnect_manager.patch
fix_remove_caption-removing_style_call.patch
revert_change_content_pluginlist_to_only_run_on_the_ui_thread.patch

Просмотреть файл

@ -1,736 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Kleinschmidt <jkleinsc@electronjs.org>
Date: Tue, 18 Oct 2022 19:07:14 -0400
Subject: Revert "Change content::PluginList to only run on the UI thread."
https://chromium-review.googlesource.com/c/chromium/src/+/3866812 broke our PDF viewer.
We probably should figure out a better way to deal with this, but for now this will
unblock the roll.
diff --git a/content/browser/plugin_list.cc b/content/browser/plugin_list.cc
index f6a5b2c2a19fe7094d62d02763276af70950a621..483163f94335fc65d7c46230f7b3839c7ab95f33 100644
--- a/content/browser/plugin_list.cc
+++ b/content/browser/plugin_list.cc
@@ -16,7 +16,6 @@
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "net/base/mime_util.h"
#include "url/gurl.h"
@@ -68,18 +67,17 @@ bool SupportsExtension(const WebPluginInfo& plugin,
// static
PluginList* PluginList::Singleton() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
return g_singleton.Pointer();
}
void PluginList::RefreshPlugins() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::AutoLock lock(lock_);
loading_state_ = LOADING_STATE_NEEDS_REFRESH;
}
void PluginList::RegisterInternalPlugin(const WebPluginInfo& info,
bool add_at_beginning) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::AutoLock lock(lock_);
internal_plugins_.push_back(info);
if (add_at_beginning) {
@@ -92,8 +90,7 @@ void PluginList::RegisterInternalPlugin(const WebPluginInfo& info,
}
void PluginList::UnregisterInternalPlugin(const base::FilePath& path) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
+ base::AutoLock lock(lock_);
bool found = false;
for (size_t i = 0; i < internal_plugins_.size(); i++) {
if (internal_plugins_[i].path == path) {
@@ -103,12 +100,12 @@ void PluginList::UnregisterInternalPlugin(const base::FilePath& path) {
}
}
DCHECK(found);
- RemoveExtraPluginPath(path);
+ RemoveExtraPluginPathLocked(path);
}
void PluginList::GetInternalPlugins(
std::vector<WebPluginInfo>* internal_plugins) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::AutoLock lock(lock_);
for (const auto& plugin : internal_plugins_)
internal_plugins->push_back(plugin);
@@ -116,8 +113,7 @@ void PluginList::GetInternalPlugins(
bool PluginList::ReadPluginInfo(const base::FilePath& filename,
WebPluginInfo* info) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
+ base::AutoLock lock(lock_);
for (const auto& plugin : internal_plugins_) {
if (filename == plugin.path) {
*info = plugin;
@@ -127,13 +123,10 @@ bool PluginList::ReadPluginInfo(const base::FilePath& filename,
return false;
}
-PluginList::PluginList() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
+PluginList::PluginList() = default;
bool PluginList::PrepareForPluginLoading() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
+ base::AutoLock lock(lock_);
if (loading_state_ == LOADING_STATE_UP_TO_DATE)
return false;
@@ -142,12 +135,18 @@ bool PluginList::PrepareForPluginLoading() {
}
void PluginList::LoadPlugins() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
if (!PrepareForPluginLoading())
return;
std::vector<WebPluginInfo> new_plugins;
+ base::OnceClosure will_load_callback;
+ {
+ base::AutoLock lock(lock_);
+ will_load_callback = will_load_plugins_callback_;
+ }
+ if (will_load_callback)
+ std::move(will_load_callback).Run();
+
std::vector<base::FilePath> plugin_paths;
GetPluginPathsToLoad(&plugin_paths);
@@ -162,8 +161,6 @@ void PluginList::LoadPlugins() {
bool PluginList::LoadPluginIntoPluginList(const base::FilePath& path,
std::vector<WebPluginInfo>* plugins,
WebPluginInfo* plugin_info) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
if (!ReadPluginInfo(path, plugin_info))
return false;
@@ -181,9 +178,15 @@ bool PluginList::LoadPluginIntoPluginList(const base::FilePath& path,
void PluginList::GetPluginPathsToLoad(
std::vector<base::FilePath>* plugin_paths) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ // Don't want to hold the lock while loading new plugins, so we don't block
+ // other methods if they're called on other threads.
+ std::vector<base::FilePath> extra_plugin_paths;
+ {
+ base::AutoLock lock(lock_);
+ extra_plugin_paths = extra_plugin_paths_;
+ }
- for (const base::FilePath& path : extra_plugin_paths_) {
+ for (const base::FilePath& path : extra_plugin_paths) {
if (base::Contains(*plugin_paths, path))
continue;
plugin_paths->push_back(path);
@@ -191,7 +194,7 @@ void PluginList::GetPluginPathsToLoad(
}
void PluginList::SetPlugins(const std::vector<WebPluginInfo>& plugins) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::AutoLock lock(lock_);
// If we haven't been invalidated in the mean time, mark the plugin list as
// up to date.
@@ -201,14 +204,20 @@ void PluginList::SetPlugins(const std::vector<WebPluginInfo>& plugins) {
plugins_list_ = plugins;
}
+void PluginList::set_will_load_plugins_callback(
+ const base::RepeatingClosure& callback) {
+ base::AutoLock lock(lock_);
+ will_load_plugins_callback_ = callback;
+}
+
void PluginList::GetPlugins(std::vector<WebPluginInfo>* plugins) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
LoadPlugins();
+ base::AutoLock lock(lock_);
plugins->insert(plugins->end(), plugins_list_.begin(), plugins_list_.end());
}
bool PluginList::GetPluginsNoRefresh(std::vector<WebPluginInfo>* plugins) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ base::AutoLock lock(lock_);
plugins->insert(plugins->end(), plugins_list_.begin(), plugins_list_.end());
return loading_state_ == LOADING_STATE_UP_TO_DATE;
@@ -220,10 +229,10 @@ bool PluginList::GetPluginInfoArray(
bool allow_wildcard,
std::vector<WebPluginInfo>* info,
std::vector<std::string>* actual_mime_types) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(mime_type == base::ToLowerASCII(mime_type));
DCHECK(info);
+ base::AutoLock lock(lock_);
bool is_stale = loading_state_ != LOADING_STATE_UP_TO_DATE;
info->clear();
if (actual_mime_types)
@@ -270,8 +279,9 @@ bool PluginList::GetPluginInfoArray(
return is_stale;
}
-void PluginList::RemoveExtraPluginPath(const base::FilePath& plugin_path) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+void PluginList::RemoveExtraPluginPathLocked(
+ const base::FilePath& plugin_path) {
+ lock_.AssertAcquired();
std::vector<base::FilePath>::iterator it =
base::ranges::find(extra_plugin_paths_, plugin_path);
if (it != extra_plugin_paths_.end())
diff --git a/content/browser/plugin_list.h b/content/browser/plugin_list.h
index 0b0a8600acfa1884f499cd2de5c0c149c68fefb9..0949b863b7e35511a9ef679d18ed410c4222434d 100644
--- a/content/browser/plugin_list.h
+++ b/content/browser/plugin_list.h
@@ -10,8 +10,11 @@
#include <utility>
#include <vector>
+#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
#include "content/public/common/webplugininfo.h"
@@ -25,8 +28,14 @@ class GURL;
namespace content {
-// Manages the list of plugins. At this point, there are no external plugins.
-// This object lives on the UI thread.
+// The PluginList is responsible for loading our NPAPI based plugins. It does
+// so in whatever manner is appropriate for the platform. On Windows, it loads
+// plugins from a known directory by looking for DLLs which start with "NP",
+// and checking to see if they are valid NPAPI libraries. On the Mac, it walks
+// the machine-wide and user plugin directories and loads anything that has
+// the correct types. On Linux, it walks the plugin directories as well
+// (e.g. /usr/lib/browser-plugins/).
+// This object is thread safe.
class CONTENT_EXPORT PluginList {
public:
// Gets the one instance of the PluginList.
@@ -77,6 +86,8 @@ class CONTENT_EXPORT PluginList {
std::vector<WebPluginInfo>* info,
std::vector<std::string>* actual_mime_types);
+ void set_will_load_plugins_callback(const base::RepeatingClosure& callback);
+
private:
enum LoadingState {
LOADING_STATE_NEEDS_REFRESH,
@@ -109,8 +120,10 @@ class CONTENT_EXPORT PluginList {
// Load all plugins from the default plugins directory.
void LoadPlugins();
- // Removes |plugin_path| from the list of extra plugin paths.
- void RemoveExtraPluginPath(const base::FilePath& plugin_path);
+ // Removes |plugin_path| from the list of extra plugin paths. Should only be
+ // called while holding |lock_|.
+ void RemoveExtraPluginPathLocked(const base::FilePath& plugin_path)
+ EXCLUSIVE_LOCKS_REQUIRED(lock_);
// Creates a WebPluginInfo structure given a plugin's path. On success
// returns true, with the information being put into "info".
@@ -130,16 +143,23 @@ class CONTENT_EXPORT PluginList {
// States whether we will load the plugin list the next time we try to access
// it, whether we are currently in the process of loading it, or whether we
// consider it up to date.
- LoadingState loading_state_ = LOADING_STATE_NEEDS_REFRESH;
+ LoadingState loading_state_ GUARDED_BY(lock_) = LOADING_STATE_NEEDS_REFRESH;
// Extra plugin paths that we want to search when loading.
- std::vector<base::FilePath> extra_plugin_paths_;
+ std::vector<base::FilePath> extra_plugin_paths_ GUARDED_BY(lock_);
// Holds information about internal plugins.
- std::vector<WebPluginInfo> internal_plugins_;
+ std::vector<WebPluginInfo> internal_plugins_ GUARDED_BY(lock_);
// A list holding all plugins.
- std::vector<WebPluginInfo> plugins_list_;
+ std::vector<WebPluginInfo> plugins_list_ GUARDED_BY(lock_);
+
+ // Callback that is invoked whenever the PluginList will reload the plugins.
+ base::RepeatingClosure will_load_plugins_callback_ GUARDED_BY(lock_);
+
+ // Need synchronization for the above members since this object can be
+ // accessed on multiple threads.
+ base::Lock lock_;
};
} // namespace content
diff --git a/content/browser/plugin_list_unittest.cc b/content/browser/plugin_list_unittest.cc
index 7cda980e4272dec80b0db5571f7fefb0ea3355ea..7f319488496786d605c6fda210492f587f7e6e14 100644
--- a/content/browser/plugin_list_unittest.cc
+++ b/content/browser/plugin_list_unittest.cc
@@ -6,8 +6,7 @@
#include <string>
-#include "base/files/file_path.h"
-#include "content/public/test/browser_task_environment.h"
+#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -17,8 +16,9 @@ namespace {
base::FilePath::CharType kFooPath[] = FILE_PATH_LITERAL("/plugins/foo.plugin");
base::FilePath::CharType kBarPath[] = FILE_PATH_LITERAL("/plugins/bar.plugin");
-const char kFooMimeType[] = "application/x-foo-mime-type";
-const char kFooFileType[] = "foo";
+const char* kFooName = "Foo Plugin";
+const char* kFooMimeType = "application/x-foo-mime-type";
+const char* kFooFileType = "foo";
bool Equals(const WebPluginInfo& a, const WebPluginInfo& b) {
return (a.name == b.name && a.path == b.path && a.version == b.version &&
@@ -40,7 +40,7 @@ bool Contains(const std::vector<WebPluginInfo>& list,
class PluginListTest : public testing::Test {
public:
PluginListTest()
- : foo_plugin_(u"Foo PluginListTest",
+ : foo_plugin_(base::ASCIIToUTF16(kFooName),
base::FilePath(kFooPath),
u"1.2.3",
u"foo"),
@@ -48,33 +48,21 @@ class PluginListTest : public testing::Test {
}
void SetUp() override {
- // Cannot use std::unique_ptr due to private ctor.
- plugin_list_ = new PluginList();
- plugin_list_->RegisterInternalPlugin(bar_plugin_, false);
+ plugin_list_.RegisterInternalPlugin(bar_plugin_, false);
foo_plugin_.mime_types.emplace_back(kFooMimeType, kFooFileType,
std::string());
- plugin_list_->RegisterInternalPlugin(foo_plugin_, false);
- }
-
- void TearDown() override {
- // Cannot use std::unique_ptr due to private dtor.
- delete plugin_list_;
+ plugin_list_.RegisterInternalPlugin(foo_plugin_, false);
}
protected:
- // Must be first.
- BrowserTaskEnvironment task_environment_;
-
- // Owns the PluginList but cannot be a std::unique_ptr due to private
- // ctor/dtor.
- PluginList* plugin_list_;
+ PluginList plugin_list_;
WebPluginInfo foo_plugin_;
WebPluginInfo bar_plugin_;
};
TEST_F(PluginListTest, GetPlugins) {
std::vector<WebPluginInfo> plugins;
- plugin_list_->GetPlugins(&plugins);
+ plugin_list_.GetPlugins(&plugins);
EXPECT_EQ(2u, plugins.size());
EXPECT_TRUE(Contains(plugins, foo_plugin_));
EXPECT_TRUE(Contains(plugins, bar_plugin_));
@@ -85,11 +73,11 @@ TEST_F(PluginListTest, BadPluginDescription) {
std::u16string(), base::FilePath(FILE_PATH_LITERAL("/myplugin.3.0.43")),
std::u16string(), std::u16string());
// Simulate loading of the plugins.
- plugin_list_->RegisterInternalPlugin(plugin_3043, false);
+ plugin_list_.RegisterInternalPlugin(plugin_3043, false);
// Now we should have them in the state we specified above.
- plugin_list_->RefreshPlugins();
+ plugin_list_.RefreshPlugins();
std::vector<WebPluginInfo> plugins;
- plugin_list_->GetPlugins(&plugins);
+ plugin_list_.GetPlugins(&plugins);
ASSERT_TRUE(Contains(plugins, plugin_3043));
}
@@ -101,7 +89,7 @@ TEST_F(PluginListTest, GetPluginInfoArray) {
bool is_stale;
// The PluginList starts out in a stale state.
- is_stale = plugin_list_->GetPluginInfoArray(
+ is_stale = plugin_list_.GetPluginInfoArray(
target_url, "application/octet-stream",
/*allow_wildcard=*/false, &plugins, &actual_mime_types);
EXPECT_TRUE(is_stale);
@@ -109,13 +97,13 @@ TEST_F(PluginListTest, GetPluginInfoArray) {
EXPECT_EQ(0u, actual_mime_types.size());
// Refresh it.
- plugin_list_->GetPlugins(&plugins);
+ plugin_list_.GetPlugins(&plugins);
plugins.clear();
// The file type of the URL is supported by |foo_plugin_|. However,
// GetPluginInfoArray should not match |foo_plugin_| because the MIME type is
// application/octet-stream.
- is_stale = plugin_list_->GetPluginInfoArray(
+ is_stale = plugin_list_.GetPluginInfoArray(
target_url, "application/octet-stream",
/*allow_wildcard=*/false, &plugins, &actual_mime_types);
EXPECT_FALSE(is_stale);
@@ -125,9 +113,9 @@ TEST_F(PluginListTest, GetPluginInfoArray) {
// |foo_plugin_| matches due to the MIME type.
plugins.clear();
actual_mime_types.clear();
- is_stale = plugin_list_->GetPluginInfoArray(target_url, kFooMimeType,
- /*allow_wildcard=*/false,
- &plugins, &actual_mime_types);
+ is_stale = plugin_list_.GetPluginInfoArray(target_url, kFooMimeType,
+ /*allow_wildcard=*/false, &plugins,
+ &actual_mime_types);
EXPECT_FALSE(is_stale);
EXPECT_EQ(1u, plugins.size());
EXPECT_TRUE(Contains(plugins, foo_plugin_));
@@ -137,9 +125,9 @@ TEST_F(PluginListTest, GetPluginInfoArray) {
// |foo_plugin_| matches due to the file type and empty MIME type.
plugins.clear();
actual_mime_types.clear();
- is_stale = plugin_list_->GetPluginInfoArray(target_url, "",
- /*allow_wildcard=*/false,
- &plugins, &actual_mime_types);
+ is_stale = plugin_list_.GetPluginInfoArray(target_url, "",
+ /*allow_wildcard=*/false, &plugins,
+ &actual_mime_types);
EXPECT_FALSE(is_stale);
EXPECT_EQ(1u, plugins.size());
EXPECT_TRUE(Contains(plugins, foo_plugin_));
diff --git a/content/browser/plugin_service_impl.cc b/content/browser/plugin_service_impl.cc
index ab3e8c87dc84bcf1284d65b61a4a2f0338c24903..59e73c99c499d312dd6d31ad2f067f364a7909cd 100644
--- a/content/browser/plugin_service_impl.cc
+++ b/content/browser/plugin_service_impl.cc
@@ -19,7 +19,6 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
-#include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner_util.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread.h"
@@ -55,6 +54,18 @@ namespace content {
namespace {
+std::vector<WebPluginInfo> GetPluginsHelper() {
+ std::vector<WebPluginInfo> plugins;
+ PluginList::Singleton()->GetPlugins(&plugins);
+ return plugins;
+}
+
+// Callback set on the PluginList to assert that plugin loading happens on the
+// correct thread.
+void WillLoadPluginsCallback(base::SequenceChecker* sequence_checker) {
+ DCHECK(sequence_checker->CalledOnValidSequence());
+}
+
#if BUILDFLAG(ENABLE_PPAPI)
int CountPpapiPluginProcessesForProfile(
const base::FilePath& plugin_path,
@@ -79,8 +90,6 @@ PluginService* PluginService::GetInstance() {
void PluginService::PurgePluginListCache(BrowserContext* browser_context,
bool reload_pages) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
!it.IsAtEnd(); it.Advance()) {
RenderProcessHost* host = it.GetCurrentValue();
@@ -99,7 +108,14 @@ PluginServiceImpl::PluginServiceImpl() = default;
PluginServiceImpl::~PluginServiceImpl() = default;
void PluginServiceImpl::Init() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ plugin_list_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+
+ // Setup the sequence checker right after setting up the task runner.
+ plugin_list_sequence_checker_.DetachFromSequence();
+ PluginList::Singleton()->set_will_load_plugins_callback(base::BindRepeating(
+ &WillLoadPluginsCallback, &plugin_list_sequence_checker_));
RegisterPlugins();
}
@@ -109,8 +125,6 @@ PpapiPluginProcessHost* PluginServiceImpl::FindPpapiPluginProcess(
const base::FilePath& plugin_path,
const base::FilePath& profile_data_directory,
const absl::optional<url::Origin>& origin_lock) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
if (iter->plugin_path() == plugin_path &&
iter->profile_data_directory() == profile_data_directory &&
@@ -170,8 +184,6 @@ void PluginServiceImpl::OpenChannelToPpapiPlugin(
const base::FilePath& profile_data_directory,
const absl::optional<url::Origin>& origin_lock,
PpapiPluginProcessHost::PluginClient* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
PpapiPluginProcessHost* plugin_host = FindOrStartPpapiPluginProcess(
render_process_id, plugin_path, profile_data_directory, origin_lock);
if (plugin_host) {
@@ -189,8 +201,6 @@ bool PluginServiceImpl::GetPluginInfoArray(
bool allow_wildcard,
std::vector<WebPluginInfo>* plugins,
std::vector<std::string>* actual_mime_types) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
return PluginList::Singleton()->GetPluginInfoArray(
url, mime_type, allow_wildcard, plugins, actual_mime_types);
}
@@ -224,8 +234,6 @@ bool PluginServiceImpl::GetPluginInfo(content::BrowserContext* browser_context,
bool PluginServiceImpl::GetPluginInfoByPath(const base::FilePath& plugin_path,
WebPluginInfo* info) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
std::vector<WebPluginInfo> plugins;
PluginList::Singleton()->GetPluginsNoRefresh(&plugins);
@@ -241,8 +249,6 @@ bool PluginServiceImpl::GetPluginInfoByPath(const base::FilePath& plugin_path,
std::u16string PluginServiceImpl::GetPluginDisplayNameByPath(
const base::FilePath& path) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
std::u16string plugin_name = path.LossyDisplayName();
WebPluginInfo info;
if (PluginService::GetInstance()->GetPluginInfoByPath(path, &info) &&
@@ -260,23 +266,16 @@ std::u16string PluginServiceImpl::GetPluginDisplayNameByPath(
}
void PluginServiceImpl::GetPlugins(GetPluginsCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- // Run `callback` later, to stay compatible with prior behavior.
- base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), GetPluginsSynchronous()));
+ base::PostTaskAndReplyWithResult(plugin_list_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&GetPluginsHelper),
+ std::move(callback));
}
std::vector<WebPluginInfo> PluginServiceImpl::GetPluginsSynchronous() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- std::vector<WebPluginInfo> plugins;
- PluginList::Singleton()->GetPlugins(&plugins);
- return plugins;
+ return GetPluginsHelper();
}
void PluginServiceImpl::RegisterPlugins() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
#if BUILDFLAG(ENABLE_PPAPI)
ComputePepperPluginList(&plugins_);
#else
@@ -289,8 +288,6 @@ void PluginServiceImpl::RegisterPlugins() {
// There should generally be very few plugins so a brute-force search is fine.
const ContentPluginInfo* PluginServiceImpl::GetRegisteredPluginInfo(
const base::FilePath& plugin_path) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
for (auto& plugin : plugins_) {
if (plugin.path == plugin_path)
return &plugin;
@@ -316,12 +313,10 @@ const ContentPluginInfo* PluginServiceImpl::GetRegisteredPluginInfo(
}
void PluginServiceImpl::SetFilter(PluginServiceFilter* filter) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
filter_ = filter;
}
PluginServiceFilter* PluginServiceImpl::GetFilter() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
return filter_;
}
@@ -357,32 +352,27 @@ bool PluginServiceImpl::IsPluginUnstable(const base::FilePath& path) {
}
void PluginServiceImpl::RefreshPlugins() {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
PluginList::Singleton()->RefreshPlugins();
}
void PluginServiceImpl::RegisterInternalPlugin(
const WebPluginInfo& info,
bool add_at_beginning) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
PluginList::Singleton()->RegisterInternalPlugin(info, add_at_beginning);
}
void PluginServiceImpl::UnregisterInternalPlugin(const base::FilePath& path) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
PluginList::Singleton()->UnregisterInternalPlugin(path);
}
void PluginServiceImpl::GetInternalPlugins(
std::vector<WebPluginInfo>* plugins) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
PluginList::Singleton()->GetInternalPlugins(plugins);
}
bool PluginServiceImpl::PpapiDevChannelSupported(
BrowserContext* browser_context,
const GURL& document_url) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
return GetContentClient()->browser()->IsPluginAllowedToUseDevChannelAPIs(
browser_context, document_url);
}
diff --git a/content/browser/plugin_service_impl.h b/content/browser/plugin_service_impl.h
index e179b53facd24e6eef7b273bf52d8d80bdc41398..cf98068c47fb772d1f7fe1e8be67d42bac8bde54 100644
--- a/content/browser/plugin_service_impl.h
+++ b/content/browser/plugin_service_impl.h
@@ -10,6 +10,8 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/singleton.h"
+#include "base/sequence_checker.h"
+#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/common/content_export.h"
@@ -32,7 +34,7 @@ class PluginServiceFilter;
struct ContentPluginInfo;
// This class responds to requests from renderers for the list of plugins, and
-// also a proxy object for plugin instances. It lives on the UI thread.
+// also a proxy object for plugin instances.
class CONTENT_EXPORT PluginServiceImpl : public PluginService {
public:
// Returns the PluginServiceImpl singleton.
@@ -78,7 +80,7 @@ class CONTENT_EXPORT PluginServiceImpl : public PluginService {
// Returns the plugin process host corresponding to the plugin process that
// has been started by this service. This will start a process to host the
// 'plugin_path' if needed. If the process fails to start, the return value
- // is NULL.
+ // is NULL. Must be called on the IO thread.
PpapiPluginProcessHost* FindOrStartPpapiPluginProcess(
int render_process_id,
const base::FilePath& plugin_path,
@@ -86,7 +88,8 @@ class CONTENT_EXPORT PluginServiceImpl : public PluginService {
const absl::optional<url::Origin>& origin_lock);
// Opens a channel to a plugin process for the given mime type, starting
- // a new plugin process if necessary.
+ // a new plugin process if necessary. This must be called on the IO thread
+ // or else a deadlock can occur.
void OpenChannelToPpapiPlugin(int render_process_id,
const base::FilePath& plugin_path,
const base::FilePath& profile_data_directory,
@@ -129,9 +132,15 @@ class CONTENT_EXPORT PluginServiceImpl : public PluginService {
int max_ppapi_processes_per_profile_ = kDefaultMaxPpapiProcessesPerProfile;
- // Weak pointer; set during the startup and must outlive us.
+ // Weak pointer; set during the startup on UI thread and must outlive us.
raw_ptr<PluginServiceFilter> filter_ = nullptr;
+ // Used to load plugins from disk.
+ scoped_refptr<base::SequencedTaskRunner> plugin_list_task_runner_;
+
+ // Used to verify that loading plugins from disk is done sequentially.
+ base::SequenceChecker plugin_list_sequence_checker_;
+
// Used to detect if a given plugin is crashing over and over.
std::map<base::FilePath, std::vector<base::Time>> crash_times_;
};
diff --git a/content/public/browser/plugin_service.h b/content/public/browser/plugin_service.h
index 0cd7b92aa5850c9dc139e0689e3394fb8ecb42c5..9c3d960a9c6a1ad16487599a0e75875ee1676aaf 100644
--- a/content/public/browser/plugin_service.h
+++ b/content/public/browser/plugin_service.h
@@ -30,7 +30,12 @@ class PluginServiceFilter;
struct ContentPluginInfo;
struct WebPluginInfo;
-// This class lives on the UI thread.
+// This must be created on the main thread but it's only called on the IO/file
+// thread unless otherwise noted. This is an asynchronous wrapper around the
+// PluginList interface for querying plugin information. This must be used
+// instead of that to avoid doing expensive disk operations on the IO/UI
+// threads.
+// TODO(http://crbug.com/990013): Only use this on the UI thread.
class CONTENT_EXPORT PluginService {
public:
using GetPluginsCallback =
@@ -43,6 +48,7 @@ class CONTENT_EXPORT PluginService {
// to throw away their cache of the plugin list, and optionally also reload
// all the pages with plugins. If |browser_context| is nullptr, purges the
// cache in all renderers.
+ // NOTE: can only be called on the UI thread.
static void PurgePluginListCache(BrowserContext* browser_context,
bool reload_pages);
@@ -52,8 +58,8 @@ class CONTENT_EXPORT PluginService {
virtual void Init() = 0;
// Gets the plugin in the list of plugins that matches the given url and mime
- // type. Returns true if the data is from a stale plugin list, false if it is
- // up to date.
+ // type. Returns true if the data is frome a stale plugin list, false if it
+ // is up to date. This can be called from any thread.
virtual bool GetPluginInfoArray(
const GURL& url,
const std::string& mime_type,
@@ -63,7 +69,8 @@ class CONTENT_EXPORT PluginService {
// Gets plugin info for an individual plugin and filters the plugins using
// the |browser_context|. This will report whether the data is stale via
- // |is_stale| and returns whether or not the plugin can be found.
+ // |is_stale| and returns whether or not the plugin can be found. This must be
+ // called from the UI thread.
virtual bool GetPluginInfo(content::BrowserContext* browser_context,
const GURL& url,
const std::string& mime_type,
@@ -75,21 +82,25 @@ class CONTENT_EXPORT PluginService {
// Get plugin info by plugin path (including disabled plugins). Returns true
// if the plugin is found and WebPluginInfo has been filled in |info|. This
// will use cached data in the plugin list.
+ // This can be called from any thread.
virtual bool GetPluginInfoByPath(const base::FilePath& plugin_path,
WebPluginInfo* info) = 0;
// Returns the display name for the plugin identified by the given path. If
// the path doesn't identify a plugin, or the plugin has no display name,
// this will attempt to generate a display name from the path.
+ // This can be called from any thread.
virtual std::u16string GetPluginDisplayNameByPath(
const base::FilePath& plugin_path) = 0;
// Asynchronously loads plugins if necessary and then calls back to the
// provided function on the calling sequence on completion.
+ // This can be called from any thread.
virtual void GetPlugins(GetPluginsCallback callback) = 0;
// Synchronously loads plugins if necessary and returns the list of plugin
- // infos.
+ // infos. This can be called from any thread. This method is expected to
+ // not perform any disk IO.
virtual std::vector<WebPluginInfo> GetPluginsSynchronous() = 0;
// Returns information about a plugin if it exists, otherwise `nullptr`. The

Просмотреть файл

@ -43,7 +43,6 @@
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
#if BUILDFLAG(ENABLE_PLUGINS)
#include "content/public/browser/plugin_service.h"
#include "content/public/common/content_plugin_info.h"
#include "ppapi/shared_impl/ppapi_permissions.h"
#include "ppapi/shared_impl/ppapi_switches.h" // nogncheck crbug.com/1125897
@ -121,20 +120,6 @@ void ComputeBuiltInPlugins(std::vector<content::ContentPluginInfo>* plugins) {
"Portable Document Format");
pdf_info.mime_types.push_back(pdf_mime_type);
plugins->push_back(pdf_info);
// NB. in Chrome, this plugin isn't registered until the PDF extension is
// loaded. However, in Electron, we load the PDF extension unconditionally
// when it is enabled in the build, so we're OK to load the plugin eagerly
// here.
content::WebPluginInfo info;
info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
info.name = base::ASCIIToUTF16(kPDFExtensionPluginName);
// This isn't a real file path; it's just used as a unique identifier.
info.path = base::FilePath::FromUTF8Unsafe(extension_misc::kPdfExtensionId);
info.background_color = content::WebPluginInfo::kDefaultBackgroundColor;
info.mime_types.emplace_back(kPDFMimeType, "pdf", "Portable Document Format");
content::PluginService::GetInstance()->RefreshPlugins();
content::PluginService::GetInstance()->RegisterInternalPlugin(info, true);
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
}
#endif // BUILDFLAG(ENABLE_PLUGINS)

Просмотреть файл

@ -112,6 +112,11 @@
#include "chrome/browser/spellchecker/spellcheck_factory.h" // nogncheck
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
#include "content/public/browser/plugin_service.h"
#include "shell/common/plugin_info.h"
#endif // BUILDFLAG(ENABLE_PLUGINS)
namespace electron {
namespace {
@ -382,6 +387,18 @@ void ElectronBrowserMainParts::PostCreateThreads() {
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&tracing::TracingSamplerProfiler::CreateOnChildThread));
#if BUILDFLAG(ENABLE_PLUGINS)
// PluginService can only be used on the UI thread
// and ContentClient::AddPlugins gets called for both browser and render
// process where the latter will not have UI thread which leads to DCHECK.
// Separate the WebPluginInfo registration for these processes.
std::vector<content::WebPluginInfo> plugins;
auto* plugin_service = content::PluginService::GetInstance();
plugin_service->RefreshPlugins();
GetInternalPlugins(&plugins);
for (const auto& plugin : plugins)
plugin_service->RegisterInternalPlugin(plugin, true);
#endif
}
void ElectronBrowserMainParts::PostDestroyThreads() {

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) 2022 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/common/plugin_info.h"
#if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/pdf_util.h"
#include "extensions/common/constants.h"
#include "shell/common/electron_constants.h"
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
namespace electron {
void GetInternalPlugins(std::vector<content::WebPluginInfo>* plugins) {
#if BUILDFLAG(ENABLE_PDF_VIEWER)
// NB. in Chrome, this plugin isn't registered until the PDF extension is
// loaded. However, in Electron, we load the PDF extension unconditionally
// when it is enabled in the build, so we're OK to load the plugin eagerly
// here.
plugins->push_back(GetPDFPluginInfo());
#endif
}
#if BUILDFLAG(ENABLE_PDF_VIEWER)
content::WebPluginInfo GetPDFPluginInfo() {
content::WebPluginInfo info;
info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
info.name = base::ASCIIToUTF16(kPDFExtensionPluginName);
// This isn't a real file path; it's just used as a unique identifier.
info.path = base::FilePath::FromUTF8Unsafe(extension_misc::kPdfExtensionId);
info.background_color = content::WebPluginInfo::kDefaultBackgroundColor;
info.mime_types.emplace_back(kPDFMimeType, "pdf", "Portable Document Format");
return info;
}
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
} // namespace electron

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) 2022 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ELECTRON_SHELL_COMMON_PLUGIN_INFO_H_
#define ELECTRON_SHELL_COMMON_PLUGIN_INFO_H_
#include "content/public/common/content_plugin_info.h"
#include "electron/buildflags/buildflags.h"
namespace electron {
void GetInternalPlugins(std::vector<content::WebPluginInfo>* plugins);
#if BUILDFLAG(ENABLE_PDF_VIEWER)
content::WebPluginInfo GetPDFPluginInfo();
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
} // namespace electron
#endif // ELECTRON_SHELL_COMMON_PLUGIN_INFO_H_

Просмотреть файл

@ -73,6 +73,7 @@
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
#if BUILDFLAG(ENABLE_PLUGINS)
#include "shell/common/plugin_info.h"
#include "shell/renderer/pepper_helper.h"
#endif // BUILDFLAG(ENABLE_PLUGINS)
@ -420,19 +421,12 @@ bool RendererClientBase::IsPluginHandledExternally(
->CreateFrameContainer(plugin_element, original_url, mime_type, info);
}
// TODO(nornagon): this info should be shared with the data in
// electron_content_client.cc / ComputeBuiltInPlugins.
content::WebPluginInfo info;
info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
info.name = base::ASCIIToUTF16(kPDFExtensionPluginName);
info.path = base::FilePath::FromUTF8Unsafe(extension_misc::kPdfExtensionId);
info.background_color = content::WebPluginInfo::kDefaultBackgroundColor;
info.mime_types.emplace_back(kPDFMimeType, "pdf", "Portable Document Format");
return extensions::MimeHandlerViewContainerManager::Get(
content::RenderFrame::FromWebFrame(
plugin_element.GetDocument().GetFrame()),
true /* create_if_does_not_exist */)
->CreateFrameContainer(plugin_element, original_url, mime_type, info);
->CreateFrameContainer(plugin_element, original_url, mime_type,
GetPDFPluginInfo());
#else
return false;
#endif