Move ChromeRequirementsChecker to //extensions as a PreloadCheck
Remove the "Chrome" from ChromeRequirementsChecker. Make it implement
PreloadCheck and simplify its async logic a bit. Transform
RequirementsCheckerBrowserTest to a unit test.
This lets AppShell and other modules use RequirementsChecker. (This
wasn't possible until GPUFeatureChecker was moved to //content in
http://crrev.com/2666243002.)
BUG=679971
[email protected]
[email protected]
Review-Url: https://codereview.chromium.org/2783813002
Cr-Commit-Position: refs/heads/master@{#462607}
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ade7ac6..65abf852 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4041,17 +4041,6 @@
<message name="IDS_APP_CANT_DOWNGRADE_VERSION" desc="Error message when a user tries to install an app with a lower version than a version that it already installed.">
Attempted to downgrade app.
</message>
- <message name="IDS_EXTENSION_WEBGL_NOT_SUPPORTED" desc="Error message when an extension has a requirement for WebGL that the system does not support.">
- WebGL is not supported.
- </message>
- <message name="IDS_EXTENSION_NPAPI_NOT_SUPPORTED" desc="Error message when an extension has a requirement for plugins that the system does not support.">
- NPAPI plugins are not supported.
- </message>
- <if expr="not use_aura">
- <message name="IDS_EXTENSION_WINDOW_SHAPE_NOT_SUPPORTED" desc="Error message when an extension has a requirement for shaped windows that the system does not support.">
- Shaped windows are not supported.
- </message>
- </if>
<if expr="chromeos">
<message name="IDS_EXTENSION_CANT_INSTALL_IN_DEVICE_LOCAL_ACCOUNT" desc="Error message when a user tries to install or the administrator tries to force-install through policy an extension that is not allowed in a device-local account.">
<ph name="EXTENSION_NAME">$1<ex>Google Talk</ex></ph> (extension ID "<ph name="EXTENSION_ID">$2<ex>nckgahadagoaajjgafhacjanaoiihapd</ex></ph>") is not allowed in this type of session.
@@ -4108,9 +4097,6 @@
<message name="IDS_EXTENSION_BAD_FILE_ENCODING" desc="">
Could not load file '<ph name="RELATIVE_PATH">$1<ex>file.js</ex></ph>' for content script. It isn't UTF-8 encoded.
</message>
- <message name="IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED" desc="">
- Could not load '<ph name="PLUGIN_PATH">$1<ex>/path/to/file</ex></ph>' for plugin.
- </message>
<message name="IDS_EXTENSION_LOAD_ICON_FOR_PAGE_ACTION_FAILED" desc="">
Could not load icon '<ph name="ICON">$1<ex>icon.png</ex></ph>' for page action.
</message>
diff --git a/chrome/browser/content_settings/content_settings_internal_extension_provider.cc b/chrome/browser/content_settings/content_settings_internal_extension_provider.cc
index d153e10..bd58d07 100644
--- a/chrome/browser/content_settings/content_settings_internal_extension_provider.cc
+++ b/chrome/browser/content_settings/content_settings_internal_extension_provider.cc
@@ -10,7 +10,6 @@
#include "chrome/browser/pdf/pdf_extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_content_client.h"
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "components/content_settings/core/browser/content_settings_rule.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
@@ -23,6 +22,7 @@
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#include "extensions/common/features/simple_feature.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
using extensions::UnloadedExtensionInfo;
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 6ef51a2..cc6a1797 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -487,8 +487,6 @@
"chrome_mojo_service_registration.h",
"chrome_process_manager_delegate.cc",
"chrome_process_manager_delegate.h",
- "chrome_requirements_checker.cc",
- "chrome_requirements_checker.h",
"chrome_url_request_util.cc",
"chrome_url_request_util.h",
"clipboard_extension_helper_chromeos.cc",
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
index 9d52108..8fd3eff 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -10,7 +10,6 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/bookmark_app_helper.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
-#include "chrome/browser/extensions/chrome_requirements_checker.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/launch_util.h"
@@ -225,11 +224,6 @@
web_contents, browser_context, extension, callback));
}
-std::unique_ptr<extensions::RequirementsChecker>
-ChromeManagementAPIDelegate::CreateRequirementsChecker() const {
- return base::MakeUnique<extensions::ChromeRequirementsChecker>();
-}
-
std::unique_ptr<extensions::UninstallDialogDelegate>
ChromeManagementAPIDelegate::UninstallFunctionDelegate(
extensions::ManagementUninstallFunctionBase* function,
diff --git a/chrome/browser/extensions/api/management/chrome_management_api_delegate.h b/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
index 6c12736..dec9423 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
@@ -31,8 +31,6 @@
content::BrowserContext* browser_context,
const extensions::Extension* extension,
const base::Callback<void(bool)>& callback) const override;
- std::unique_ptr<extensions::RequirementsChecker> CreateRequirementsChecker()
- const override;
std::unique_ptr<extensions::UninstallDialogDelegate>
UninstallFunctionDelegate(
extensions::ManagementUninstallFunctionBase* function,
diff --git a/chrome/browser/extensions/chrome_requirements_checker.cc b/chrome/browser/extensions/chrome_requirements_checker.cc
deleted file mode 100644
index 3aeacef..0000000
--- a/chrome/browser/extensions/chrome_requirements_checker.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/chrome_requirements_checker.h"
-
-#include "base/bind.h"
-#include "build/build_config.h"
-#include "chrome/grit/generated_resources.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/gpu_feature_checker.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/manifest.h"
-#include "extensions/common/manifest_handlers/requirements_info.h"
-#include "gpu/config/gpu_feature_type.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace extensions {
-
-ChromeRequirementsChecker::ChromeRequirementsChecker()
- : pending_requirement_checks_(0), weak_ptr_factory_(this) {
-}
-
-ChromeRequirementsChecker::~ChromeRequirementsChecker() {
-}
-
-void ChromeRequirementsChecker::Check(
- const scoped_refptr<const Extension>& extension,
- const RequirementsCheckedCallback& callback) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
- callback_ = callback;
- const RequirementsInfo& requirements =
- RequirementsInfo::GetRequirements(extension.get());
-
- if (requirements.npapi) {
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- errors_.push_back(
- l10n_util::GetStringUTF8(IDS_EXTENSION_NPAPI_NOT_SUPPORTED));
-#endif
- }
-
- if (requirements.window_shape) {
-#if !defined(USE_AURA)
- errors_.push_back(
- l10n_util::GetStringUTF8(IDS_EXTENSION_WINDOW_SHAPE_NOT_SUPPORTED));
-#endif
- }
-
- if (requirements.webgl) {
- ++pending_requirement_checks_;
- webgl_checker_ = content::GpuFeatureChecker::Create(
- gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL,
- base::Bind(&ChromeRequirementsChecker::SetWebGLAvailability,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- if (pending_requirement_checks_ == 0) {
- content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
- base::Bind(callback_, errors_));
- // Reset the callback so any ref-counted bound parameters will get released.
- callback_.Reset();
- return;
- }
- // Running the GPU checkers down here removes any race condition that arises
- // from the use of pending_requirement_checks_.
- if (webgl_checker_.get())
- webgl_checker_->CheckGpuFeatureAvailability();
-}
-
-void ChromeRequirementsChecker::SetWebGLAvailability(bool available) {
- if (!available) {
- errors_.push_back(
- l10n_util::GetStringUTF8(IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
- }
- MaybeRunCallback();
-}
-
-void ChromeRequirementsChecker::MaybeRunCallback() {
- if (--pending_requirement_checks_ == 0) {
- content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
- base::Bind(callback_, errors_));
- // Reset the callback so any ref-counted bound parameters will get released.
- callback_.Reset();
- errors_.clear();
- }
-}
-
-} // namespace extensions
diff --git a/chrome/browser/extensions/chrome_requirements_checker.h b/chrome/browser/extensions/chrome_requirements_checker.h
deleted file mode 100644
index 07304e9..0000000
--- a/chrome/browser/extensions/chrome_requirements_checker.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_CHROME_REQUIREMENTS_CHECKER_H_
-#define CHROME_BROWSER_EXTENSIONS_CHROME_REQUIREMENTS_CHECKER_H_
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "extensions/browser/requirements_checker.h"
-
-namespace content {
-class GpuFeatureChecker;
-}
-
-namespace extensions {
-class Extension;
-
-// Validates the 'requirements' extension manifest field. This is an
-// asynchronous process that involves several threads, but the public interface
-// of this class (including constructor and destructor) must only be used on
-// the UI thread.
-class ChromeRequirementsChecker : public RequirementsChecker {
- public:
- ChromeRequirementsChecker();
- ~ChromeRequirementsChecker() override;
-
- private:
- // RequirementsChecker:
- void Check(const scoped_refptr<const Extension>& extension,
- const RequirementsCheckedCallback& callback) override;
-
- // Callbacks for the GpuFeatureChecker.
- void SetWebGLAvailability(bool available);
-
- void MaybeRunCallback();
-
- std::vector<std::string> errors_;
-
- // Every requirement that needs to be resolved asynchronously will add to
- // this counter. When the counter is depleted, the callback will be run.
- int pending_requirement_checks_;
-
- scoped_refptr<content::GpuFeatureChecker> webgl_checker_;
-
- RequirementsCheckedCallback callback_;
-
- base::WeakPtrFactory<ChromeRequirementsChecker> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ChromeRequirementsChecker);
-};
-
-} // namespace extensions
-
-#endif // CHROME_BROWSER_EXTENSIONS_CHROME_REQUIREMENTS_CHECKER_H_
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index beb79a7..05462ce 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -526,12 +526,11 @@
return;
// Check for requirement errors.
- if (!install_checker_->requirement_errors().empty()) {
+ if (!install_checker_->requirements_error_message().empty()) {
if (error_on_unsupported_requirements_) {
ReportFailureFromUIThread(
CrxInstallError(CrxInstallError::ERROR_DECLINED,
- base::UTF8ToUTF16(base::JoinString(
- install_checker_->requirement_errors(), " "))));
+ install_checker_->requirements_error_message()));
return;
}
install_flags_ |= kInstallFlagHasRequirementErrors;
@@ -569,9 +568,8 @@
// Note: |client_| can be NULL in unit_tests!
if (extension()->from_webstore() && client_)
client_->install_ui()->SetSkipPostInstallUI(true);
- ReportFailureFromUIThread(
- CrxInstallError(CrxInstallError::ERROR_DECLINED,
- base::UTF8ToUTF16(install_checker_->policy_error())));
+ ReportFailureFromUIThread(CrxInstallError(
+ CrxInstallError::ERROR_DECLINED, install_checker_->policy_error()));
return;
}
diff --git a/chrome/browser/extensions/extension_install_checker.cc b/chrome/browser/extensions/extension_install_checker.cc
index 8117973..d529647e 100644
--- a/chrome/browser/extensions/extension_install_checker.cc
+++ b/chrome/browser/extensions/extension_install_checker.cc
@@ -10,11 +10,11 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/blacklist.h"
#include "chrome/browser/extensions/blacklist_check.h"
-#include "chrome/browser/extensions/chrome_requirements_checker.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/policy_check.h"
+#include "extensions/browser/requirements_checker.h"
namespace extensions {
@@ -72,7 +72,7 @@
void ExtensionInstallChecker::CheckManagementPolicy() {
// In tests, this check may already be stubbed.
if (!policy_check_)
- policy_check_ = base::MakeUnique<PolicyCheck>(profile_, extension_.get());
+ policy_check_ = base::MakeUnique<PolicyCheck>(profile_, extension_);
policy_check_->Start(
base::BindOnce(&ExtensionInstallChecker::OnManagementPolicyCheckDone,
weak_ptr_factory_.GetWeakPtr()));
@@ -82,7 +82,7 @@
PreloadCheck::Errors errors) {
if (!errors.empty()) {
DCHECK_EQ(1u, errors.count(PreloadCheck::DISALLOWED_BY_POLICY));
- policy_error_ = base::UTF16ToUTF8(policy_check_->GetErrorMessage());
+ policy_error_ = policy_check_->GetErrorMessage();
}
running_checks_ &= ~CHECK_MANAGEMENT_POLICY;
@@ -90,17 +90,19 @@
}
void ExtensionInstallChecker::CheckRequirements() {
- requirements_checker_ = base::MakeUnique<ChromeRequirementsChecker>();
- requirements_checker_->Check(
- extension_, base::Bind(&ExtensionInstallChecker::OnRequirementsCheckDone,
- weak_ptr_factory_.GetWeakPtr()));
+ // In tests, this check may already be stubbed.
+ if (!requirements_check_)
+ requirements_check_ = base::MakeUnique<RequirementsChecker>(extension_);
+ requirements_check_->Start(
+ base::BindOnce(&ExtensionInstallChecker::OnRequirementsCheckDone,
+ weak_ptr_factory_.GetWeakPtr()));
}
void ExtensionInstallChecker::OnRequirementsCheckDone(
- const std::vector<std::string>& errors) {
+ PreloadCheck::Errors errors) {
DCHECK(is_running());
- requirement_errors_ = errors;
+ requirements_error_message_ = requirements_check_->GetErrorMessage();
running_checks_ &= ~CHECK_REQUIREMENTS;
MaybeInvokeCallback();
@@ -109,8 +111,8 @@
void ExtensionInstallChecker::CheckBlacklistState() {
// In tests, this check may already be stubbed.
if (!blacklist_check_) {
- blacklist_check_ = base::MakeUnique<BlacklistCheck>(
- Blacklist::Get(profile_), extension_.get());
+ blacklist_check_ =
+ base::MakeUnique<BlacklistCheck>(Blacklist::Get(profile_), extension_);
}
blacklist_check_->Start(
base::BindOnce(&ExtensionInstallChecker::OnBlacklistStateCheckDone,
@@ -140,7 +142,7 @@
int failed_mask = 0;
if (blacklist_error_ == PreloadCheck::BLACKLISTED_ID)
failed_mask |= CHECK_BLACKLIST;
- if (!requirement_errors_.empty())
+ if (!requirements_error_message_.empty())
failed_mask |= CHECK_REQUIREMENTS;
if (!policy_error_.empty())
failed_mask |= CHECK_MANAGEMENT_POLICY;
@@ -153,7 +155,7 @@
// If we are failing fast, discard any pending results.
blacklist_check_.reset();
policy_check_.reset();
- requirements_checker_.reset();
+ requirements_check_.reset();
weak_ptr_factory_.InvalidateWeakPtrs();
base::ResetAndReturn(&callback_).Run(failed_mask);
}
diff --git a/chrome/browser/extensions/extension_install_checker.h b/chrome/browser/extensions/extension_install_checker.h
index 17da2427..767c466 100644
--- a/chrome/browser/extensions/extension_install_checker.h
+++ b/chrome/browser/extensions/extension_install_checker.h
@@ -20,8 +20,6 @@
namespace extensions {
-class RequirementsChecker;
-
// Performs common checks for validating whether an extension may be installed.
// This class should be Start()-ed at most once.
class ExtensionInstallChecker {
@@ -60,10 +58,9 @@
// Returns true if any checks are currently running.
bool is_running() const { return running_checks_ != 0; }
- // Returns the requirement violations. A non-empty list is considered to be
- // a check failure.
- const std::vector<std::string>& requirement_errors() const {
- return requirement_errors_;
+ // Returns the error message for requirement violations, if any were found.
+ const base::string16& requirements_error_message() const {
+ return requirements_error_message_;
}
// Returns the blacklist error of the extension. Note that there is only an
@@ -71,7 +68,7 @@
PreloadCheck::Error blacklist_error() const { return blacklist_error_; }
// Returns whether management policy permits installation of the extension.
- const std::string& policy_error() const { return policy_error_; }
+ const base::string16& policy_error() const { return policy_error_; }
void SetBlacklistCheckForTesting(std::unique_ptr<PreloadCheck> policy_check) {
blacklist_check_ = std::move(policy_check);
@@ -79,13 +76,17 @@
void SetPolicyCheckForTesting(std::unique_ptr<PreloadCheck> policy_check) {
policy_check_ = std::move(policy_check);
}
+ void SetRequirementsCheckForTesting(
+ std::unique_ptr<PreloadCheck> requirements_check) {
+ requirements_check_ = std::move(requirements_check);
+ }
protected:
virtual void CheckManagementPolicy();
void OnManagementPolicyCheckDone(PreloadCheck::Errors errors);
virtual void CheckRequirements();
- void OnRequirementsCheckDone(const std::vector<std::string>& errors);
+ void OnRequirementsCheckDone(PreloadCheck::Errors errors);
virtual void CheckBlacklistState();
void OnBlacklistStateCheckDone(PreloadCheck::Errors errors);
@@ -100,8 +101,8 @@
scoped_refptr<const Extension> extension_;
// Checks requirements specified in the manifest.
- std::unique_ptr<RequirementsChecker> requirements_checker_;
- std::vector<std::string> requirement_errors_;
+ std::unique_ptr<PreloadCheck> requirements_check_;
+ base::string16 requirements_error_message_;
// Checks if the extension is blacklisted.
std::unique_ptr<PreloadCheck> blacklist_check_;
@@ -109,7 +110,7 @@
// Checks whether management policies allow the extension to be installed.
std::unique_ptr<PreloadCheck> policy_check_;
- std::string policy_error_;
+ base::string16 policy_error_;
// Bitmask of enabled checks.
int enabled_checks_;
diff --git a/chrome/browser/extensions/extension_install_checker_unittest.cc b/chrome/browser/extensions/extension_install_checker_unittest.cc
index 36307ff..5c4238a4 100644
--- a/chrome/browser/extensions/extension_install_checker_unittest.cc
+++ b/chrome/browser/extensions/extension_install_checker_unittest.cc
@@ -34,41 +34,13 @@
~ExtensionInstallCheckerForTest() override {}
- void set_requirements_error(const std::string& error) {
- requirements_error_ = error;
- }
-
bool is_async() const { return is_async_; }
void set_is_async(bool is_async) { is_async_ = is_async; }
- protected:
- void MockCheckRequirements() {
- if (!is_running())
- return;
- std::vector<std::string> errors;
- if (!requirements_error_.empty())
- errors.push_back(requirements_error_);
- OnRequirementsCheckDone(errors);
- }
-
- void CheckRequirements() override {
- if (is_async_) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&ExtensionInstallCheckerForTest::MockCheckRequirements,
- base::Unretained(this)));
- } else {
- MockCheckRequirements();
- }
- }
-
private:
// Whether to run the requirements and blacklist checks asynchronously, as
// they often do in ExtensionInstallChecker.
bool is_async_ = false;
-
- // Dummy error for testing.
- std::string requirements_error_;
};
class CheckObserver {
@@ -121,29 +93,41 @@
checker->SetPolicyCheckForTesting(std::move(policy_check));
}
+ void SetRequirementsError(ExtensionInstallCheckerForTest* checker,
+ PreloadCheck::Error error,
+ const std::string& message) {
+ auto requirements_check = base::MakeUnique<PreloadCheckStub>();
+ requirements_check->set_is_async(checker->is_async());
+ if (error != PreloadCheck::NONE) {
+ requirements_check->AddError(error);
+ requirements_check->set_error_message(base::UTF8ToUTF16(message));
+ }
+ checker->SetRequirementsCheckForTesting(std::move(requirements_check));
+ }
+
protected:
void SetAllPass(ExtensionInstallCheckerForTest* checker) {
SetBlacklistError(checker, PreloadCheck::NONE);
SetPolicyError(checker, PreloadCheck::NONE, "");
- checker->set_requirements_error("");
+ SetRequirementsError(checker, PreloadCheck::NONE, "");
}
void SetAllErrors(ExtensionInstallCheckerForTest* checker) {
SetBlacklistError(checker, kBlacklistError);
SetPolicyError(checker, PreloadCheck::DISALLOWED_BY_POLICY,
kDummyPolicyError);
- checker->set_requirements_error(kDummyRequirementsError);
+ SetRequirementsError(checker, PreloadCheck::NPAPI_NOT_SUPPORTED,
+ kDummyRequirementsError);
}
void ExpectRequirementsPass(const ExtensionInstallCheckerForTest& checker) {
- EXPECT_TRUE(checker.requirement_errors().empty());
+ EXPECT_EQ(base::string16(), checker.requirements_error_message());
}
void ExpectRequirementsError(const char* expected_error,
const ExtensionInstallCheckerForTest& checker) {
- EXPECT_FALSE(checker.requirement_errors().empty());
- EXPECT_EQ(std::string(expected_error),
- checker.requirement_errors().front());
+ EXPECT_EQ(base::UTF8ToUTF16(expected_error),
+ checker.requirements_error_message());
}
void ExpectRequirementsError(const ExtensionInstallCheckerForTest& checker) {
@@ -165,7 +149,7 @@
void ExpectPolicyError(const char* expected_error,
const ExtensionInstallCheckerForTest& checker) {
EXPECT_FALSE(checker.policy_error().empty());
- EXPECT_EQ(std::string(expected_error), checker.policy_error());
+ EXPECT_EQ(base::UTF8ToUTF16(expected_error), checker.policy_error());
}
void ExpectPolicyError(const ExtensionInstallCheckerForTest& checker) {
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 06617e6d..9338f19 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -654,7 +654,9 @@
extensions::UnpackedInstaller::Create(this)->LoadFromCommandLine(
base::FilePath(t.token()), &extension_id, false /*only-allow-apps*/);
// Extension id is added to whitelist after its extension is loaded
- // because code is executed asynchronously.
+ // because code is executed asynchronously. TODO(michaelpg): Remove this
+ // assumption so loading extensions does not have to be asynchronous:
+ // crbug.com/708354.
if (switch_name == switches::kDisableExtensionsExcept)
disable_flag_exempted_extensions_.insert(extension_id);
}
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index ee94ed9..d1e8c5e4 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -78,7 +78,6 @@
#include "chrome/browser/ui/global_error/global_error_service_factory.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
#include "chrome/common/pref_names.h"
@@ -123,6 +122,7 @@
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/background_info.h"
#include "extensions/common/manifest_handlers/permissions_parser.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
#include "extensions/common/manifest_url_handlers.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
diff --git a/chrome/browser/extensions/plugin_manager.cc b/chrome/browser/extensions/plugin_manager.cc
index 0b9d50e..688f79f 100644
--- a/chrome/browser/extensions/plugin_manager.cc
+++ b/chrome/browser/extensions/plugin_manager.cc
@@ -2,21 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/browser/extensions/plugin_manager.h"
+
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/plugin_manager.h"
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/pepper_plugin_info.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handlers/mime_types_handler.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
#include "url/gurl.h"
#if !defined(DISABLE_NACL)
diff --git a/chrome/browser/extensions/requirements_checker_browsertest.cc b/chrome/browser/extensions/requirements_checker_browsertest.cc
deleted file mode 100644
index d8d40e4a..0000000
--- a/chrome/browser/extensions/requirements_checker_browsertest.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
-#include "base/strings/string_util.h"
-#include "build/build_config.h"
-#include "chrome/browser/extensions/chrome_requirements_checker.h"
-#include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/grit/generated_resources.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/gpu_data_manager.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/file_util.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace extensions {
-
-class RequirementsCheckerBrowserTest : public ExtensionBrowserTest {
- public:
- RequirementsCheckerBrowserTest()
- : checker_(new ChromeRequirementsChecker()) {}
-
- scoped_refptr<const Extension> LoadExtensionFromDirName(
- const std::string& extension_dir_name) {
- base::FilePath extension_path;
- std::string load_error;
- PathService::Get(chrome::DIR_TEST_DATA, &extension_path);
- extension_path = extension_path.AppendASCII("requirements_checker")
- .AppendASCII(extension_dir_name);
- scoped_refptr<const Extension> extension = file_util::LoadExtension(
- extension_path, Manifest::UNPACKED, 0, &load_error);
- CHECK_EQ(0U, load_error.length());
- return extension;
- }
-
- void ValidateRequirementErrors(
- const std::vector<std::string>& expected_errors,
- const std::vector<std::string>& actual_errors) {
- ASSERT_EQ(expected_errors, actual_errors);
- }
-
- protected:
- std::unique_ptr<RequirementsChecker> checker_;
-};
-
-IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, CheckEmptyExtension) {
- scoped_refptr<const Extension> extension(
- LoadExtensionFromDirName("no_requirements"));
- ASSERT_TRUE(extension.get());
- checker_->Check(extension, base::Bind(
- &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
- base::Unretained(this), std::vector<std::string>()));
- content::RunAllBlockingPoolTasksUntilIdle();
-}
-
-IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, CheckNpapiExtension) {
- scoped_refptr<const Extension> extension(
- LoadExtensionFromDirName("require_npapi"));
- ASSERT_TRUE(extension.get());
-
- std::vector<std::string> expected_errors;
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
- expected_errors.push_back(l10n_util::GetStringUTF8(
- IDS_EXTENSION_NPAPI_NOT_SUPPORTED));
-#endif
-
- checker_->Check(extension, base::Bind(
- &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
- base::Unretained(this), expected_errors));
- content::RunAllBlockingPoolTasksUntilIdle();
-}
-
-IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest,
- CheckWindowShapeExtension) {
- scoped_refptr<const Extension> extension(
- LoadExtensionFromDirName("require_window_shape"));
- ASSERT_TRUE(extension.get());
-
- std::vector<std::string> expected_errors;
-#if !defined(USE_AURA)
- expected_errors.push_back(l10n_util::GetStringUTF8(
- IDS_EXTENSION_WINDOW_SHAPE_NOT_SUPPORTED));
-#endif // !defined(USE_AURA)
-
- checker_->Check(extension, base::Bind(
- &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
- base::Unretained(this), expected_errors));
- content::RunAllBlockingPoolTasksUntilIdle();
-}
-
-IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, DisallowWebGL) {
- scoped_refptr<const Extension> extension(
- LoadExtensionFromDirName("require_3d"));
- ASSERT_TRUE(extension.get());
-
- content::GpuDataManager::GetInstance()->BlacklistWebGLForTesting();
- content::RunAllBlockingPoolTasksUntilIdle();
-
- std::vector<std::string> expected_errors;
- expected_errors.push_back(l10n_util::GetStringUTF8(
- IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
-
- checker_->Check(extension, base::Bind(
- &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
- base::Unretained(this), expected_errors));
- content::RunAllBlockingPoolTasksUntilIdle();
-}
-
-IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, Check3DExtension) {
- scoped_refptr<const Extension> extension(
- LoadExtensionFromDirName("require_3d"));
- ASSERT_TRUE(extension.get());
-
- std::vector<std::string> expected_errors;
-
- if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) {
- expected_errors.push_back(l10n_util::GetStringUTF8(
- IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
- }
-
- checker_->Check(extension, base::Bind(
- &RequirementsCheckerBrowserTest::ValidateRequirementErrors,
- base::Unretained(this), expected_errors));
- content::RunAllBlockingPoolTasksUntilIdle();
-}
-
-} // namespace extensions
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
index 148113f3..0d93fcc 100644
--- a/chrome/browser/extensions/unpacked_installer.cc
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -8,7 +8,9 @@
#include "base/callback.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/string16.h"
#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_install_checker.h"
@@ -18,7 +20,6 @@
#include "chrome/browser/extensions/permissions_updater.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/extensions/extension_install_ui_factory.h"
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "components/crx_file/id_util.h"
#include "components/sync/model/string_ordinal.h"
#include "content/public/browser/browser_thread.h"
@@ -30,6 +31,7 @@
#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/file_util.h"
#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
#include "extensions/common/manifest_handlers/shared_module_info.h"
#include "extensions/common/permissions/permissions_data.h"
@@ -253,14 +255,12 @@
void UnpackedInstaller::OnInstallChecksComplete(int failed_checks) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- if (!install_checker_->policy_error().empty()) {
- ReportExtensionLoadError(install_checker_->policy_error());
- return;
- }
+ base::string16 error_message = install_checker_->policy_error();
+ if (error_message.empty())
+ error_message = install_checker_->requirements_error_message();
- if (!install_checker_->requirement_errors().empty()) {
- ReportExtensionLoadError(
- base::JoinString(install_checker_->requirement_errors(), " "));
+ if (!error_message.empty()) {
+ ReportExtensionLoadError(base::UTF16ToUTF8(error_message));
return;
}
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index b9be3b0..79e8128d 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -252,8 +252,6 @@
"extensions/api/notifications/notification_style.h",
"extensions/api/omnibox/omnibox_handler.cc",
"extensions/api/omnibox/omnibox_handler.h",
- "extensions/api/plugins/plugins_handler.cc",
- "extensions/api/plugins/plugins_handler.h",
"extensions/api/speech/tts_engine_manifest_handler.cc",
"extensions/api/speech/tts_engine_manifest_handler.h",
"extensions/api/spellcheck/spellcheck_handler.cc",
diff --git a/chrome/common/extensions/chrome_manifest_handlers.cc b/chrome/common/extensions/chrome_manifest_handlers.cc
index ca7ecf5..a047f72 100644
--- a/chrome/common/extensions/chrome_manifest_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -7,7 +7,6 @@
#include "build/build_config.h"
#include "chrome/common/extensions/api/commands/commands_handler.h"
#include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
#include "chrome/common/extensions/api/spellcheck/spellcheck_handler.h"
#include "chrome/common/extensions/api/storage/storage_schema_manifest_handler.h"
@@ -26,7 +25,6 @@
#include "chrome/common/extensions/manifest_handlers/ui_overrides_handler.h"
#include "extensions/common/manifest_handlers/app_isolation_info.h"
#include "extensions/common/manifest_handlers/options_page_info.h"
-#include "extensions/common/manifest_handlers/requirements_info.h"
#include "extensions/common/manifest_url_handlers.h"
#if defined(OS_CHROMEOS)
@@ -53,8 +51,6 @@
(new MinimumChromeVersionChecker)->Register();
(new OmniboxHandler)->Register();
(new OptionsPageManifestHandler)->Register();
- (new PluginsHandler)->Register();
- (new RequirementsHandler)->Register(); // Depends on plugins.
(new SettingsOverridesHandler)->Register();
(new SpellcheckHandler)->Register();
(new StorageSchemaManifestHandler)->Register();
diff --git a/chrome/common/extensions/sync_helper.cc b/chrome/common/extensions/sync_helper.cc
index 5e216f91..9152450f 100644
--- a/chrome/common/extensions/sync_helper.cc
+++ b/chrome/common/extensions/sync_helper.cc
@@ -5,7 +5,6 @@
#include "chrome/common/extensions/sync_helper.h"
#include "base/logging.h"
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "chrome/common/extensions/extension_constants.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension.h"
@@ -13,6 +12,7 @@
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_provider.h"
#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
#include "extensions/common/manifest_url_handlers.h"
#include "extensions/common/permissions/permissions_data.h"
diff --git a/chrome/common/extensions/sync_type_unittest.cc b/chrome/common/extensions/sync_type_unittest.cc
index 2ac283b4..512ad30 100644
--- a/chrome/common/extensions/sync_type_unittest.cc
+++ b/chrome/common/extensions/sync_type_unittest.cc
@@ -4,13 +4,13 @@
#include "base/files/file_path.h"
#include "build/build_config.h"
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
#include "chrome/common/extensions/sync_helper.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/features/simple_feature.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index ac39ffe9..778daa9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1545,7 +1545,6 @@
"../browser/extensions/process_management_browsertest.cc",
"../browser/extensions/process_manager_browsertest.cc",
"../browser/extensions/renderer_initialization_browsertest.cc",
- "../browser/extensions/requirements_checker_browsertest.cc",
"../browser/extensions/sandboxed_pages_apitest.cc",
"../browser/extensions/service_worker_apitest.cc",
"../browser/extensions/shared_module_apitest.cc",
diff --git a/chrome/test/data/requirements_checker/no_requirements/manifest.json b/chrome/test/data/requirements_checker/no_requirements/manifest.json
deleted file mode 100644
index a464131..0000000
--- a/chrome/test/data/requirements_checker/no_requirements/manifest.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "name": "RequirementsChecker Browser Test",
- "version": "1.0",
- "manifest_version": 2
-}
diff --git a/chrome/test/data/requirements_checker/require_3d/manifest.json b/chrome/test/data/requirements_checker/require_3d/manifest.json
deleted file mode 100644
index c5cbf5d..0000000
--- a/chrome/test/data/requirements_checker/require_3d/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "RequirementsChecker Browser Test",
- "version": "1.0",
- "manifest_version": 2,
- "requirements": {
- "3D": {
- "features": ["webgl", "css3d"]
- }
- }
-}
diff --git a/chrome/test/data/requirements_checker/require_npapi/manifest.json b/chrome/test/data/requirements_checker/require_npapi/manifest.json
deleted file mode 100644
index 90835ac2b..0000000
--- a/chrome/test/data/requirements_checker/require_npapi/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "RequirementsChecker Browser Test",
- "version": "1.0",
- "manifest_version": 2,
- "requirements": {
- "plugins": {
- "npapi": true
- }
- }
-}
diff --git a/chrome/test/data/requirements_checker/require_window_shape/manifest.json b/chrome/test/data/requirements_checker/require_window_shape/manifest.json
deleted file mode 100644
index 0e145dc..0000000
--- a/chrome/test/data/requirements_checker/require_window_shape/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "RequirementsChecker Browser Test",
- "version": "1.0",
- "manifest_version": 2,
- "requirements": {
- "window": {
- "shape": true
- }
- }
-}
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 02a49b2..aee589d 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -244,6 +244,7 @@
"quota_service.h",
"renderer_startup_helper.cc",
"renderer_startup_helper.h",
+ "requirements_checker.cc",
"requirements_checker.h",
"runtime_data.cc",
"runtime_data.h",
@@ -452,6 +453,7 @@
"process_map_unittest.cc",
"quota_service_unittest.cc",
"renderer_startup_helper_unittest.cc",
+ "requirements_checker_unittest.cc",
"runtime_data_unittest.cc",
"sandboxed_unpacker_unittest.cc",
"updater/update_service_unittest.cc",
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index 99095ce4..bc6d14a 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -19,6 +19,7 @@
"+device/serial",
"+device/usb",
"+google_apis/gaia",
+ "+gpu/config",
"+grit/extensions_strings.h",
"+net",
# This directory contains build flags and does not pull all of PPAPI in.
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc
index c723341f..8f4df2a34 100644
--- a/extensions/browser/api/management/management_api.cc
+++ b/extensions/browser/api/management/management_api.cc
@@ -447,9 +447,8 @@
if (prefs->GetDisableReasons(extension_id_) &
Extension::DISABLE_UNSUPPORTED_REQUIREMENT) {
// Recheck the requirements.
- requirements_checker_ = delegate->CreateRequirementsChecker();
- requirements_checker_->Check(
- extension,
+ requirements_checker_ = base::MakeUnique<RequirementsChecker>(extension);
+ requirements_checker_->Start(
base::Bind(&ManagementSetEnabledFunction::OnRequirementsChecked,
this)); // This bind creates a reference.
return RespondLater();
@@ -478,15 +477,15 @@
}
void ManagementSetEnabledFunction::OnRequirementsChecked(
- const std::vector<std::string>& requirements_errors) {
- if (requirements_errors.empty()) {
+ PreloadCheck::Errors errors) {
+ if (errors.empty()) {
ManagementAPI::GetFactoryInstance()->Get(browser_context())->GetDelegate()->
EnableExtension(browser_context(), extension_id_);
Respond(NoArguments());
} else {
// TODO(devlin): Should we really be noisy here all the time?
Respond(Error(keys::kMissingRequirementsError,
- base::JoinString(requirements_errors, " ")));
+ base::UTF16ToUTF8(requirements_checker_->GetErrorMessage())));
}
}
diff --git a/extensions/browser/api/management/management_api.h b/extensions/browser/api/management/management_api.h
index 785af73..e699ece8 100644
--- a/extensions/browser/api/management/management_api.h
+++ b/extensions/browser/api/management/management_api.h
@@ -16,6 +16,7 @@
#include "extensions/browser/extension_event_histogram_value.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_registry_observer.h"
+#include "extensions/browser/preload_check.h"
struct WebApplicationInfo;
@@ -112,7 +113,7 @@
private:
void OnInstallPromptDone(bool did_accept);
- void OnRequirementsChecked(const std::vector<std::string>& requirements);
+ void OnRequirementsChecked(PreloadCheck::Errors errors);
std::string extension_id_;
diff --git a/extensions/browser/api/management/management_api_delegate.h b/extensions/browser/api/management/management_api_delegate.h
index b221907..7a0e461c 100644
--- a/extensions/browser/api/management/management_api_delegate.h
+++ b/extensions/browser/api/management/management_api_delegate.h
@@ -25,7 +25,6 @@
class ManagementGenerateAppForLinkFunction;
class ManagementGetPermissionWarningsByManifestFunction;
class ManagementUninstallFunctionBase;
-class RequirementsChecker;
// Manages the lifetime of the install prompt.
class InstallPromptDelegate {
@@ -83,10 +82,6 @@
const Extension* extension,
const base::Callback<void(bool)>& callback) const = 0;
- // Returns a new RequirementsChecker.
- virtual std::unique_ptr<RequirementsChecker> CreateRequirementsChecker()
- const = 0;
-
// Enables the extension identified by |extension_id|.
virtual void EnableExtension(content::BrowserContext* context,
const std::string& extension_id) const = 0;
diff --git a/extensions/browser/preload_check.h b/extensions/browser/preload_check.h
index 5050d54..d3445ff 100644
--- a/extensions/browser/preload_check.h
+++ b/extensions/browser/preload_check.h
@@ -27,6 +27,9 @@
BLACKLISTED_ID,
BLACKLISTED_UNKNOWN,
DISALLOWED_BY_POLICY,
+ NPAPI_NOT_SUPPORTED,
+ WEBGL_NOT_SUPPORTED,
+ WINDOW_SHAPE_NOT_SUPPORTED,
};
using Errors = std::set<Error>;
diff --git a/extensions/browser/requirements_checker.cc b/extensions/browser/requirements_checker.cc
new file mode 100644
index 0000000..a70b043
--- /dev/null
+++ b/extensions/browser/requirements_checker.cc
@@ -0,0 +1,99 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/requirements_checker.h"
+
+#include "base/bind.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/gpu_feature_checker.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handlers/requirements_info.h"
+#include "extensions/strings/grit/extensions_strings.h"
+#include "gpu/config/gpu_feature_type.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+RequirementsChecker::RequirementsChecker(
+ scoped_refptr<const Extension> extension)
+ : PreloadCheck(extension), weak_ptr_factory_(this) {}
+
+RequirementsChecker::~RequirementsChecker() {}
+
+void RequirementsChecker::Start(ResultCallback callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ const RequirementsInfo& requirements =
+ RequirementsInfo::GetRequirements(extension());
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ if (requirements.npapi)
+ errors_.insert(NPAPI_NOT_SUPPORTED);
+#endif
+
+#if !defined(USE_AURA)
+ if (requirements.window_shape)
+ errors_.insert(WINDOW_SHAPE_NOT_SUPPORTED);
+#endif
+
+ callback_ = std::move(callback);
+ if (requirements.webgl) {
+ webgl_checker_ = content::GpuFeatureChecker::Create(
+ gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL,
+ base::Bind(&RequirementsChecker::VerifyWebGLAvailability,
+ weak_ptr_factory_.GetWeakPtr()));
+ webgl_checker_->CheckGpuFeatureAvailability();
+ } else {
+ PostRunCallback();
+ }
+}
+
+base::string16 RequirementsChecker::GetErrorMessage() const {
+ // Join the error messages into one string.
+ std::vector<std::string> messages;
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ if (errors_.count(NPAPI_NOT_SUPPORTED)) {
+ messages.push_back(
+ l10n_util::GetStringUTF8(IDS_EXTENSION_NPAPI_NOT_SUPPORTED));
+ }
+#endif
+ if (errors_.count(WEBGL_NOT_SUPPORTED)) {
+ messages.push_back(
+ l10n_util::GetStringUTF8(IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
+ }
+#if !defined(USE_AURA)
+ if (errors_.count(WINDOW_SHAPE_NOT_SUPPORTED)) {
+ messages.push_back(
+ l10n_util::GetStringUTF8(IDS_EXTENSION_WINDOW_SHAPE_NOT_SUPPORTED));
+ }
+#endif
+
+ return base::UTF8ToUTF16(base::JoinString(messages, " "));
+}
+
+void RequirementsChecker::VerifyWebGLAvailability(bool available) {
+ if (!available)
+ errors_.insert(WEBGL_NOT_SUPPORTED);
+ PostRunCallback();
+}
+
+void RequirementsChecker::PostRunCallback() {
+ // TODO(michaelpg): This always forces the callback to run asynchronously
+ // to maintain the assumption in
+ // ExtensionService::LoadExtensionsFromCommandLineFlag(). Remove these helper
+ // functions after crbug.com/708354 is addressed.
+ content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&RequirementsChecker::RunCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void RequirementsChecker::RunCallback() {
+ DCHECK(callback_);
+ std::move(callback_).Run(errors_);
+}
+
+} // namespace extensions
diff --git a/extensions/browser/requirements_checker.h b/extensions/browser/requirements_checker.h
index 8844157e..3118325 100644
--- a/extensions/browser/requirements_checker.h
+++ b/extensions/browser/requirements_checker.h
@@ -5,10 +5,14 @@
#ifndef EXTENSIONS_BROWSER_REQUIREMENTS_CHECKER_H_
#define EXTENSIONS_BROWSER_REQUIREMENTS_CHECKER_H_
-#include <vector>
-
-#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "extensions/browser/preload_check.h"
+
+namespace content {
+class GpuFeatureChecker;
+}
namespace extensions {
class Extension;
@@ -17,20 +21,34 @@
// asynchronous process that involves several threads, but the public interface
// of this class (including constructor and destructor) must only be used on
// the UI thread.
-class RequirementsChecker {
+class RequirementsChecker : public PreloadCheck {
public:
- virtual ~RequirementsChecker() {}
+ explicit RequirementsChecker(scoped_refptr<const Extension> extension);
+ ~RequirementsChecker() override;
- using RequirementsCheckedCallback =
- base::Callback<void(const std::vector<std::string>& /* requirements */)>;
+ // PreloadCheck:
+ void Start(ResultCallback callback) override;
+ // Joins multiple errors into a space-separated string.
+ base::string16 GetErrorMessage() const override;
- // The vector passed to the callback are any localized errors describing
- // requirement violations. If this vector is non-empty, requirements checking
- // failed. This should only be called once. |callback| will always be invoked
- // asynchronously on the UI thread. |callback| will only be called once, and
- // will be reset after called.
- virtual void Check(const scoped_refptr<const Extension>& extension,
- const RequirementsCheckedCallback& callback) = 0;
+ private:
+ // Callback for the GpuFeatureChecker.
+ void VerifyWebGLAvailability(bool available);
+
+ // Helper function to post a task on the UI thread to call RunCallback().
+ void PostRunCallback();
+
+ // Helper function to run the callback.
+ void RunCallback();
+
+ scoped_refptr<content::GpuFeatureChecker> webgl_checker_;
+
+ ResultCallback callback_;
+ Errors errors_;
+
+ base::WeakPtrFactory<RequirementsChecker> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequirementsChecker);
};
} // namespace extensions
diff --git a/extensions/browser/requirements_checker_unittest.cc b/extensions/browser/requirements_checker_unittest.cc
new file mode 100644
index 0000000..c4532f74
--- /dev/null
+++ b/extensions/browser/requirements_checker_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/requirements_checker.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "content/public/browser/gpu_data_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/preload_check.h"
+#include "extensions/browser/preload_check_test_util.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+namespace {
+
+// Whether this build supports the window.shape requirement.
+const bool kSupportsWindowShape =
+#if defined(USE_AURA)
+ true;
+#else
+ false;
+#endif
+
+// Whether this build supports the plugins.npapi requirement.
+const bool kSupportsNPAPI =
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ false;
+#else
+ true;
+#endif
+
+// Returns true if a WebGL check might not fail immediately.
+bool MightSupportWebGL() {
+ return content::GpuDataManager::GetInstance()->GpuAccessAllowed(nullptr);
+}
+
+const char kFeaturesKey[] = "requirements.3D.features";
+const char kFeatureWebGL[] = "webgl";
+const char kFeatureCSS3d[] = "css3d";
+
+} // namespace
+
+class RequirementsCheckerTest : public ExtensionsTest {
+ public:
+ RequirementsCheckerTest() {
+ manifest_dict_ = base::MakeUnique<base::DictionaryValue>();
+ }
+
+ ~RequirementsCheckerTest() override {}
+
+ void CreateExtension() {
+ manifest_dict_->SetString("name", "dummy name");
+ manifest_dict_->SetString("version", "1");
+
+ std::string error;
+ extension_ =
+ Extension::Create(base::FilePath(), Manifest::UNPACKED, *manifest_dict_,
+ Extension::NO_FLAGS, &error);
+ ASSERT_TRUE(extension_.get()) << error;
+ }
+
+ protected:
+ void StartChecker() {
+ checker_ = base::MakeUnique<RequirementsChecker>(extension_);
+ // TODO(michaelpg): This should normally not have to be async. Use Run()
+ // instead of RunUntilComplete() after crbug.com/708354 is addressed.
+ runner_.RunUntilComplete(checker_.get());
+ }
+
+ void RequireWindowShape() {
+ manifest_dict_->SetBoolean("requirements.window.shape", true);
+ }
+
+ void RequireNPAPI() {
+ manifest_dict_->SetBoolean("requirements.plugins.npapi", true);
+ }
+
+ void RequireFeature(const char feature[]) {
+ if (!manifest_dict_->HasKey(kFeaturesKey))
+ manifest_dict_->Set(kFeaturesKey, base::MakeUnique<base::ListValue>());
+ base::ListValue* features_list = nullptr;
+ ASSERT_TRUE(manifest_dict_->GetList(kFeaturesKey, &features_list));
+ features_list->AppendString(feature);
+ }
+
+ std::unique_ptr<RequirementsChecker> checker_;
+ PreloadCheckRunner runner_;
+
+ private:
+ content::TestBrowserThreadBundle bundle_;
+ scoped_refptr<Extension> extension_;
+ std::unique_ptr<base::DictionaryValue> manifest_dict_;
+};
+
+// Tests no requirements.
+TEST_F(RequirementsCheckerTest, RequirementsEmpty) {
+ CreateExtension();
+ StartChecker();
+ EXPECT_TRUE(runner_.called());
+ EXPECT_EQ(0u, runner_.errors().size());
+ EXPECT_TRUE(checker_->GetErrorMessage().empty());
+}
+
+// Tests fulfilled requirements.
+TEST_F(RequirementsCheckerTest, RequirementsSuccess) {
+ if (kSupportsWindowShape)
+ RequireWindowShape();
+ if (kSupportsNPAPI)
+ RequireNPAPI();
+ RequireFeature(kFeatureCSS3d);
+
+ CreateExtension();
+ StartChecker();
+ EXPECT_TRUE(runner_.called());
+ EXPECT_EQ(0u, runner_.errors().size());
+ EXPECT_TRUE(checker_->GetErrorMessage().empty());
+}
+
+// Tests multiple requirements failing (on some builds).
+TEST_F(RequirementsCheckerTest, RequirementsFailMultiple) {
+ size_t expected_errors = 0u;
+ if (!kSupportsWindowShape) {
+ RequireWindowShape();
+ expected_errors++;
+ }
+ if (!kSupportsNPAPI) {
+ RequireNPAPI();
+ expected_errors++;
+ }
+ if (!MightSupportWebGL()) {
+ RequireFeature(kFeatureWebGL);
+ expected_errors++;
+ }
+ // css3d should always succeed.
+ RequireFeature(kFeatureCSS3d);
+
+ CreateExtension();
+ StartChecker();
+ EXPECT_TRUE(runner_.called());
+ EXPECT_EQ(expected_errors, runner_.errors().size());
+ EXPECT_EQ(expected_errors == 0, checker_->GetErrorMessage().empty());
+}
+
+// Tests a requirement that might fail asynchronously.
+TEST_F(RequirementsCheckerTest, RequirementsFailWebGL) {
+ content::GpuDataManager::GetInstance()->BlacklistWebGLForTesting();
+ RequireFeature(kFeatureWebGL);
+ CreateExtension();
+ StartChecker();
+
+ // TODO(michaelpg): Check that the runner actually finishes, which requires
+ // waiting for the GPU check to succeed: crbug.com/706204.
+ runner_.WaitForIdle();
+ if (runner_.errors().size()) {
+ EXPECT_THAT(runner_.errors(), testing::UnorderedElementsAre(
+ PreloadCheck::WEBGL_NOT_SUPPORTED));
+ EXPECT_FALSE(checker_->GetErrorMessage().empty());
+ }
+}
+
+} // namespace extensions
diff --git a/extensions/common/BUILD.gn b/extensions/common/BUILD.gn
index b711c37f..8af643d 100644
--- a/extensions/common/BUILD.gn
+++ b/extensions/common/BUILD.gn
@@ -180,6 +180,8 @@
"manifest_handlers/options_page_info.h",
"manifest_handlers/permissions_parser.cc",
"manifest_handlers/permissions_parser.h",
+ "manifest_handlers/plugins_handler.cc",
+ "manifest_handlers/plugins_handler.h",
"manifest_handlers/requirements_info.cc",
"manifest_handlers/requirements_info.h",
"manifest_handlers/sandboxed_page_info.cc",
diff --git a/extensions/common/common_manifest_handlers.cc b/extensions/common/common_manifest_handlers.cc
index a40be154..b4e4cc8 100644
--- a/extensions/common/common_manifest_handlers.cc
+++ b/extensions/common/common_manifest_handlers.cc
@@ -23,6 +23,8 @@
#include "extensions/common/manifest_handlers/nacl_modules_handler.h"
#include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
#include "extensions/common/manifest_handlers/offline_enabled_info.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
+#include "extensions/common/manifest_handlers/requirements_info.h"
#include "extensions/common/manifest_handlers/sandboxed_page_info.h"
#include "extensions/common/manifest_handlers/shared_module_info.h"
#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
@@ -58,6 +60,8 @@
#endif
(new OAuth2ManifestHandler)->Register();
(new OfflineEnabledHandler)->Register();
+ (new PluginsHandler)->Register();
+ (new RequirementsHandler)->Register(); // Depends on plugins.
(new SandboxedPageHandler)->Register();
(new SharedModuleHandler)->Register();
(new SocketsManifestHandler)->Register();
diff --git a/chrome/common/extensions/api/plugins/plugins_handler.cc b/extensions/common/manifest_handlers/plugins_handler.cc
similarity index 84%
rename from chrome/common/extensions/api/plugins/plugins_handler.cc
rename to extensions/common/manifest_handlers/plugins_handler.cc
index dedf995..d89fdbe 100644
--- a/chrome/common/extensions/api/plugins/plugins_handler.cc
+++ b/extensions/common/manifest_handlers/plugins_handler.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/common/extensions/api/plugins/plugins_handler.h"
+#include "extensions/common/manifest_handlers/plugins_handler.h"
#include <stddef.h>
@@ -13,13 +13,13 @@
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
-#include "chrome/grit/generated_resources.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/permissions_parser.h"
#include "extensions/common/permissions/api_permission.h"
#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/strings/grit/extensions_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace extensions {
@@ -36,11 +36,9 @@
} // namespace
PluginInfo::PluginInfo(const base::FilePath& plugin_path, bool plugin_is_public)
- : path(plugin_path), is_public(plugin_is_public) {
-}
+ : path(plugin_path), is_public(plugin_is_public) {}
-PluginInfo::~PluginInfo() {
-}
+PluginInfo::~PluginInfo() {}
// static
const PluginInfo::PluginVector* PluginInfo::GetPlugins(
@@ -57,11 +55,9 @@
return data && !data->plugins.empty() ? true : false;
}
-PluginsHandler::PluginsHandler() {
-}
+PluginsHandler::PluginsHandler() {}
-PluginsHandler::~PluginsHandler() {
-}
+PluginsHandler::~PluginsHandler() {}
const std::vector<std::string> PluginsHandler::Keys() const {
return SingleKey(keys::kPlugins);
@@ -100,10 +96,10 @@
}
}
- // We don't allow extensions to load NPAPI plugins on Chrome OS, but still
- // parse the entries to display consistent error messages. If the extension
- // actually requires the plugins then LoadRequirements will prevent it
- // loading.
+// We don't allow extensions to load NPAPI plugins on Chrome OS, but still
+// parse the entries to display consistent error messages. If the extension
+// actually requires the plugins then LoadRequirements will prevent it
+// loading.
#if defined(OS_CHROMEOS)
continue;
#endif // defined(OS_CHROMEOS).
@@ -132,10 +128,10 @@
plugins->begin();
plugin != plugins->end(); ++plugin) {
if (!base::PathExists(plugin->path)) {
- *error = l10n_util::GetStringFUTF8(
- IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED,
- plugin->path.LossyDisplayName());
- return false;
+ *error =
+ l10n_util::GetStringFUTF8(IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED,
+ plugin->path.LossyDisplayName());
+ return false;
}
}
}
diff --git a/chrome/common/extensions/api/plugins/plugins_handler.h b/extensions/common/manifest_handlers/plugins_handler.h
similarity index 83%
rename from chrome/common/extensions/api/plugins/plugins_handler.h
rename to extensions/common/manifest_handlers/plugins_handler.h
index 6568b38..c2a580096 100644
--- a/chrome/common/extensions/api/plugins/plugins_handler.h
+++ b/extensions/common/manifest_handlers/plugins_handler.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_COMMON_EXTENSIONS_API_PLUGINS_PLUGINS_HANDLER_H_
-#define CHROME_COMMON_EXTENSIONS_API_PLUGINS_PLUGINS_HANDLER_H_
+#ifndef EXTENSIONS_COMMON_MANIFEST_HANDLERS_PLUGINS_HANDLER_H_
+#define EXTENSIONS_COMMON_MANIFEST_HANDLERS_PLUGINS_HANDLER_H_
#include <memory>
#include <string>
@@ -22,7 +22,7 @@
~PluginInfo();
base::FilePath path; // Path to the plugin.
- bool is_public; // False if only this extension can load this plugin.
+ bool is_public; // False if only this extension can load this plugin.
// Return the plugins for a given |extensions|, or NULL if none exist.
static const PluginVector* GetPlugins(const Extension* extension);
@@ -50,4 +50,4 @@
} // namespace extensions
-#endif // CHROME_COMMON_EXTENSIONS_API_PLUGINS_PLUGINS_HANDLER_H_
+#endif // EXTENSIONS_COMMON_MANIFEST_HANDLERS_PLUGINS_HANDLER_H_
diff --git a/extensions/strings/extensions_strings.grd b/extensions/strings/extensions_strings.grd
index bc58dba..ad0f8918 100644
--- a/extensions/strings/extensions_strings.grd
+++ b/extensions/strings/extensions_strings.grd
@@ -163,6 +163,9 @@
<message name="IDS_EXTENSION_LOAD_OPTIONS_PAGE_FAILED" desc="">
Could not load options page '<ph name="OPTIONS_PAGE">$1<ex>page.html</ex></ph>'.
</message>
+ <message name="IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED" desc="">
+ Could not load '<ph name="PLUGIN_PATH">$1<ex>/path/to/file</ex></ph>' for plugin.
+ </message>
<message name="IDS_EXTENSION_LOCALES_NO_DEFAULT_LOCALE_SPECIFIED" desc="">
Localization used, but default_locale wasn't specified in the manifest.
</message>
@@ -308,6 +311,11 @@
<message name="IDS_EXTENSION_INSTALL_PROCESS_CRASHED" desc="Error message in case package fails to install because a utility process crashed.">
Could not install package because a utility process crashed. Try restarting Chrome and trying again.
</message>
+ <if expr="is_posix and not is_macosx">
+ <message name="IDS_EXTENSION_NPAPI_NOT_SUPPORTED" desc="Error message when an extension has a requirement for plugins that the system does not support.">
+ NPAPI plugins are not supported.
+ </message>
+ </if>
<message name="IDS_EXTENSION_PACKAGE_ERROR_CODE" desc="Error message in cases where we fail to install the extension because the crx file is invalid. For example, because the crx header or signature is invalid.">
Package is invalid: '<ph name="ERROR_CODE">$1<ex>error</ex></ph>'.
</message>
@@ -327,6 +335,14 @@
Can not unpack extension. To safely unpack an extension, there must be a path to your profile directory that does not contain a symlink. No such path exists for your profile.
</message>
</if>
+ <message name="IDS_EXTENSION_WEBGL_NOT_SUPPORTED" desc="Error message when an extension has a requirement for WebGL that the system does not support.">
+ WebGL is not supported.
+ </message>
+ <if expr="not use_aura">
+ <message name="IDS_EXTENSION_WINDOW_SHAPE_NOT_SUPPORTED" desc="Error message when an extension has a requirement for shaped windows that the system does not support.">
+ Shaped windows are not supported.
+ </message>
+ </if>
<!-- Utility process names. Please keep alphabetized. -->
<message name="IDS_UTILITY_PROCESS_EXTENSION_UNPACKER_NAME" desc="The name of the utility process used for unpacking extensions.">