summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrdevlin.cronin <rdevlin.cronin@chromium.org>2015-02-24 12:21:10 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-24 20:21:38 +0000
commit69bf75316e7ae533c0a0dccc1a56ca019aa95a1e (patch)
tree19c73070991a2965d12a784760136c3247be45b6
parent1d7ceee2bfb36e0a21e2d224a3bd13c447d293d7 (diff)
downloadchromium_src-69bf75316e7ae533c0a0dccc1a56ca019aa95a1e.zip
chromium_src-69bf75316e7ae533c0a0dccc1a56ca019aa95a1e.tar.gz
chromium_src-69bf75316e7ae533c0a0dccc1a56ca019aa95a1e.tar.bz2
[Extensions] Start making chrome://extensions use extensions APIs
Allow chrome://extensions to use the developerPrivate and management apis, and make it do so for enabling/disabling extensions. Also, shave yaks: - Make management api check requirements for extensions. - Make feature provider aware of complex parents. And bonus: - Remove WeakPtr interface from RequirementsChecker BUG=461039 Review URL: https://codereview.chromium.org/951633002 Cr-Commit-Position: refs/heads/master@{#317871}
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api.cc47
-rw-r--r--chrome/browser/extensions/api/developer_private/developer_private_api.h7
-rw-r--r--chrome/browser/extensions/api/management/chrome_management_api_delegate.cc6
-rw-r--r--chrome/browser/extensions/api/management/chrome_management_api_delegate.h2
-rw-r--r--chrome/browser/extensions/api/management/management_api_unittest.cc140
-rw-r--r--chrome/browser/extensions/chrome_requirements_checker.cc (renamed from chrome/browser/extensions/requirements_checker.cc)23
-rw-r--r--chrome/browser/extensions/chrome_requirements_checker.h (renamed from chrome/browser/extensions/requirements_checker.h)32
-rw-r--r--chrome/browser/extensions/extension_install_checker.cc6
-rw-r--r--chrome/browser/extensions/extension_install_checker.h2
-rw-r--r--chrome/browser/extensions/requirements_checker_browsertest.cc25
-rw-r--r--chrome/browser/resources/extensions/extension_list.js3
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_handler.cc61
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_handler.h13
-rw-r--r--chrome/chrome_browser_extensions.gypi4
-rw-r--r--chrome/chrome_tests_unit.gypi3
-rw-r--r--chrome/common/extensions/api/_api_features.json12
-rw-r--r--chrome/test/data/extensions/webui/sanity_check_available_apis.js2
-rw-r--r--extensions/browser/api/management/management_api.cc66
-rw-r--r--extensions/browser/api/management/management_api.h9
-rw-r--r--extensions/browser/api/management/management_api_constants.cc1
-rw-r--r--extensions/browser/api/management/management_api_constants.h1
-rw-r--r--extensions/browser/api/management/management_api_delegate.h4
-rw-r--r--extensions/browser/requirements_checker.h38
-rw-r--r--extensions/common/api/_api_features.json15
-rw-r--r--extensions/common/features/base_feature_provider.cc15
-rw-r--r--extensions/extensions.gypi1
26 files changed, 353 insertions, 185 deletions
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index b87d566..001c068 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/api/developer_private/entry_picker.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "chrome/browser/extensions/chrome_requirements_checker.h"
#include "chrome/browser/extensions/devtools_util.h"
#include "chrome/browser/extensions/extension_disabled_ui.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
@@ -802,7 +803,7 @@ bool DeveloperPrivateEnableFunction::RunSync() {
scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
- std::string extension_id = params->item_id;
+ const std::string& extension_id = params->item_id;
const Extension* extension =
ExtensionRegistry::Get(GetProfile())->GetExtensionById(
@@ -814,11 +815,11 @@ bool DeveloperPrivateEnableFunction::RunSync() {
ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
ManagementPolicy* policy = system->management_policy();
bool enable = params->enable;
- if (!policy->UserMayModifySettings(extension, NULL) ||
- (!enable && policy->MustRemainEnabled(extension, NULL)) ||
- (enable && policy->MustRemainDisabled(extension, NULL, NULL))) {
+ if (!policy->UserMayModifySettings(extension, nullptr) ||
+ (!enable && policy->MustRemainEnabled(extension, nullptr)) ||
+ (enable && policy->MustRemainDisabled(extension, nullptr, nullptr))) {
LOG(ERROR) << "Attempt to change enable state denied by management policy. "
- << "Extension id: " << extension_id.c_str();
+ << "Extension id: " << extension_id;
return false;
}
@@ -826,37 +827,29 @@ bool DeveloperPrivateEnableFunction::RunSync() {
if (enable) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
if (prefs->DidExtensionEscalatePermissions(extension_id)) {
- AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
- CHECK(registry);
- AppWindow* app_window =
- registry->GetAppWindowForRenderViewHost(render_view_host());
- if (!app_window) {
+ // If the extension escalated permissions, we have to show a dialog.
+ content::WebContents* web_contents = render_view_host() ?
+ content::WebContents::FromRenderViewHost(render_view_host()) :
+ nullptr;
+ if (!web_contents)
return false;
- }
- ShowExtensionDisabledDialog(
- service, app_window->web_contents(), extension);
+ ShowExtensionDisabledDialog(service, web_contents, extension);
} else if ((prefs->GetDisableReasons(extension_id) &
- Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
- !requirements_checker_.get()) {
+ Extension::DISABLE_UNSUPPORTED_REQUIREMENT)) {
// Recheck the requirements.
- scoped_refptr<const Extension> extension =
- service->GetExtensionById(extension_id, true);
- requirements_checker_.reset(new RequirementsChecker);
- // Released by OnRequirementsChecked.
- AddRef();
+ requirements_checker_.reset(new ChromeRequirementsChecker());
+ AddRef(); // Released in OnRequirementsChecked.
+ // TODO(devlin): Uh... asynchronous code in a sync extension function?
requirements_checker_->Check(
- extension,
+ make_scoped_refptr(extension),
base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked,
this, extension_id));
} else {
+ // Otherwise, we're good to re-enable the extension.
service->EnableExtension(extension_id);
-
- // Make sure any browser action contained within it is not hidden.
- ExtensionActionAPI::SetBrowserActionVisibility(
- prefs, extension->id(), true);
}
- } else {
+ } else { // !enable (i.e., disable)
service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
}
return true;
@@ -864,7 +857,7 @@ bool DeveloperPrivateEnableFunction::RunSync() {
void DeveloperPrivateEnableFunction::OnRequirementsChecked(
const std::string& extension_id,
- std::vector<std::string> requirements_errors) {
+ const std::vector<std::string>& requirements_errors) {
if (requirements_errors.empty()) {
GetExtensionService(GetProfile())->EnableExtension(extension_id);
} else {
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index 58e661c..c6f33b4 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -16,7 +16,6 @@
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/extensions/pack_extension_job.h"
-#include "chrome/browser/extensions/requirements_checker.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/render_view_host.h"
@@ -35,6 +34,7 @@ class ExtensionError;
class ExtensionRegistry;
class ExtensionSystem;
class ManagementPolicy;
+class RequirementsChecker;
namespace api {
@@ -300,8 +300,9 @@ class DeveloperPrivateEnableFunction
~DeveloperPrivateEnableFunction() override;
// Callback for requirements checker.
- void OnRequirementsChecked(const std::string& extension_id,
- std::vector<std::string> requirements_errors);
+ void OnRequirementsChecked(
+ const std::string& extension_id,
+ const std::vector<std::string>& requirements_errors);
// ExtensionFunction:
bool RunSync() override;
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 ea174a7..46289d3 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.cc
@@ -7,6 +7,7 @@
#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"
@@ -207,6 +208,11 @@ ChromeManagementAPIDelegate::SetEnabledFunctionDelegate(
extension));
}
+scoped_ptr<extensions::RequirementsChecker>
+ChromeManagementAPIDelegate::CreateRequirementsChecker() const {
+ return make_scoped_ptr(new extensions::ChromeRequirementsChecker());
+}
+
scoped_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 4d0f19e..09b5578 100644
--- a/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
+++ b/chrome/browser/extensions/api/management/chrome_management_api_delegate.h
@@ -33,6 +33,8 @@ class ChromeManagementAPIDelegate : public extensions::ManagementAPIDelegate {
scoped_ptr<extensions::InstallPromptDelegate> SetEnabledFunctionDelegate(
extensions::ManagementSetEnabledFunction* function,
const extensions::Extension* extension) const override;
+ scoped_ptr<extensions::RequirementsChecker> CreateRequirementsChecker()
+ const override;
scoped_ptr<extensions::UninstallDialogDelegate> UninstallFunctionDelegate(
extensions::ManagementUninstallFunctionBase* function,
const std::string& target_extension_id) const override;
diff --git a/chrome/browser/extensions/api/management/management_api_unittest.cc b/chrome/browser/extensions/api/management/management_api_unittest.cc
new file mode 100644
index 0000000..48fb40e
--- /dev/null
+++ b/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright 2015 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/extension_function_test_utils.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_service_test_base.h"
+#include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/host_desktop.h"
+#include "chrome/test/base/test_browser_window.h"
+#include "extensions/browser/api/management/management_api.h"
+#include "extensions/browser/api/management/management_api_constants.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/management_policy.h"
+#include "extensions/browser/test_management_policy.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_set.h"
+#include "extensions/common/test_util.h"
+
+namespace extensions {
+
+namespace {
+
+KeyedService* BuildManagementApi(content::BrowserContext* context) {
+ return new ManagementAPI(context);
+}
+
+} // namespace
+
+namespace constants = extension_management_api_constants;
+
+// TODO(devlin): Unittests are awesome. Test more with unittests and less with
+// heavy api/browser tests.
+class ManagementApiUnitTest : public ExtensionServiceTestBase {
+ protected:
+ ManagementApiUnitTest() {}
+ ~ManagementApiUnitTest() override {}
+
+ // A wrapper around extension_function_test_utils::RunFunction that runs with
+ // the associated browser, no flags, and can take stack-allocated arguments.
+ bool RunFunction(const scoped_refptr<UIThreadExtensionFunction>& function,
+ const base::ListValue& args);
+
+ Browser* browser() { return browser_.get(); }
+
+ private:
+ // ExtensionServiceTestBase:
+ void SetUp() override;
+ void TearDown() override;
+
+ // The browser (and accompanying window).
+ scoped_ptr<TestBrowserWindow> browser_window_;
+ scoped_ptr<Browser> browser_;
+
+ DISALLOW_COPY_AND_ASSIGN(ManagementApiUnitTest);
+};
+
+bool ManagementApiUnitTest::RunFunction(
+ const scoped_refptr<UIThreadExtensionFunction>& function,
+ const base::ListValue& args) {
+ return extension_function_test_utils::RunFunction(
+ function.get(),
+ make_scoped_ptr(args.DeepCopy()),
+ browser(),
+ extension_function_test_utils::NONE);
+}
+
+void ManagementApiUnitTest::SetUp() {
+ ExtensionServiceTestBase::SetUp();
+ InitializeEmptyExtensionService();
+ ManagementAPI::GetFactoryInstance()->SetTestingFactory(profile(),
+ &BuildManagementApi);
+ static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile()))->
+ SetEventRouter(make_scoped_ptr(
+ new EventRouter(profile(), ExtensionPrefs::Get(profile()))));
+
+ browser_window_.reset(new TestBrowserWindow());
+ Browser::CreateParams params(profile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
+ params.type = Browser::TYPE_TABBED;
+ params.window = browser_window_.get();
+ browser_.reset(new Browser(params));
+}
+
+void ManagementApiUnitTest::TearDown() {
+ browser_.reset();
+ browser_window_.reset();
+ ExtensionServiceTestBase::TearDown();
+}
+
+// Test the basic parts of management.setEnabled.
+TEST_F(ManagementApiUnitTest, ManagementSetEnabled) {
+ scoped_refptr<const Extension> extension = test_util::CreateEmptyExtension();
+ service()->AddExtension(extension.get());
+ std::string extension_id = extension->id();
+ scoped_refptr<ManagementSetEnabledFunction> function(
+ new ManagementSetEnabledFunction());
+
+ base::ListValue disable_args;
+ disable_args.AppendString(extension_id);
+ disable_args.AppendBoolean(false);
+
+ // Test disabling an (enabled) extension.
+ EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+ EXPECT_TRUE(RunFunction(function, disable_args));
+ EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id));
+
+ base::ListValue enable_args;
+ enable_args.AppendString(extension_id);
+ enable_args.AppendBoolean(true);
+
+ // Test re-enabling it.
+ function = new ManagementSetEnabledFunction();
+ EXPECT_TRUE(RunFunction(function, enable_args));
+ EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id));
+
+ // Test that the enable function checks management policy, so that we can't
+ // disable an extension that is required.
+ TestManagementPolicyProvider provider(
+ TestManagementPolicyProvider::PROHIBIT_MODIFY_STATUS);
+ ManagementPolicy* policy =
+ ExtensionSystem::Get(profile())->management_policy();
+ policy->RegisterProvider(&provider);
+
+ function = new ManagementSetEnabledFunction();
+ EXPECT_FALSE(RunFunction(function, disable_args));
+ EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUserCantModifyError,
+ extension_id),
+ function->GetError());
+ policy->UnregisterProvider(&provider);
+
+ // TODO(devlin): We should also test enabling an extenion that has escalated
+ // permissions, but that needs a web contents (which is a bit of a pain in a
+ // unit test).
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/requirements_checker.cc b/chrome/browser/extensions/chrome_requirements_checker.cc
index 23a3e77..811bfdd 100644
--- a/chrome/browser/extensions/requirements_checker.cc
+++ b/chrome/browser/extensions/chrome_requirements_checker.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/browser/extensions/requirements_checker.h"
+#include "chrome/browser/extensions/chrome_requirements_checker.h"
#include "base/bind.h"
#include "chrome/browser/gpu/gpu_feature_checker.h"
@@ -20,15 +20,16 @@
namespace extensions {
-RequirementsChecker::RequirementsChecker()
- : pending_requirement_checks_(0) {
+ChromeRequirementsChecker::ChromeRequirementsChecker()
+ : pending_requirement_checks_(0), weak_ptr_factory_(this) {
}
-RequirementsChecker::~RequirementsChecker() {
+ChromeRequirementsChecker::~ChromeRequirementsChecker() {
}
-void RequirementsChecker::Check(scoped_refptr<const Extension> extension,
- base::Callback<void(std::vector<std::string> errors)> callback) {
+void ChromeRequirementsChecker::Check(
+ const scoped_refptr<const Extension>& extension,
+ const RequirementsCheckedCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
callback_ = callback;
@@ -58,9 +59,9 @@ void RequirementsChecker::Check(scoped_refptr<const Extension> extension,
if (requirements.webgl) {
++pending_requirement_checks_;
webgl_checker_ = new GPUFeatureChecker(
- gpu::GPU_FEATURE_TYPE_WEBGL,
- base::Bind(&RequirementsChecker::SetWebGLAvailability,
- AsWeakPtr()));
+ gpu::GPU_FEATURE_TYPE_WEBGL,
+ base::Bind(&ChromeRequirementsChecker::SetWebGLAvailability,
+ weak_ptr_factory_.GetWeakPtr()));
}
if (pending_requirement_checks_ == 0) {
@@ -76,7 +77,7 @@ void RequirementsChecker::Check(scoped_refptr<const Extension> extension,
webgl_checker_->CheckGPUFeatureAvailability();
}
-void RequirementsChecker::SetWebGLAvailability(bool available) {
+void ChromeRequirementsChecker::SetWebGLAvailability(bool available) {
if (!available) {
errors_.push_back(
l10n_util::GetStringUTF8(IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
@@ -84,7 +85,7 @@ void RequirementsChecker::SetWebGLAvailability(bool available) {
MaybeRunCallback();
}
-void RequirementsChecker::MaybeRunCallback() {
+void ChromeRequirementsChecker::MaybeRunCallback() {
if (--pending_requirement_checks_ == 0) {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(callback_, errors_));
diff --git a/chrome/browser/extensions/requirements_checker.h b/chrome/browser/extensions/chrome_requirements_checker.h
index 1626789..b892377 100644
--- a/chrome/browser/extensions/requirements_checker.h
+++ b/chrome/browser/extensions/chrome_requirements_checker.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_EXTENSIONS_REQUIREMENTS_CHECKER_H_
-#define CHROME_BROWSER_EXTENSIONS_REQUIREMENTS_CHECKER_H_
+#ifndef CHROME_BROWSER_EXTENSIONS_CHROME_REQUIREMENTS_CHECKER_H_
+#define CHROME_BROWSER_EXTENSIONS_CHROME_REQUIREMENTS_CHECKER_H_
#include <vector>
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "chrome/browser/extensions/extension_service.h"
+#include "extensions/browser/requirements_checker.h"
class GPUFeatureChecker;
@@ -21,20 +21,16 @@ class Extension;
// 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 : public base::SupportsWeakPtr<RequirementsChecker> {
+class ChromeRequirementsChecker : public RequirementsChecker {
public:
- RequirementsChecker();
- ~RequirementsChecker();
-
- // 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.
- void Check(scoped_refptr<const Extension> extension,
- base::Callback<void(std::vector<std::string> requirement)> callback);
+ 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);
@@ -48,9 +44,13 @@ class RequirementsChecker : public base::SupportsWeakPtr<RequirementsChecker> {
scoped_refptr<GPUFeatureChecker> webgl_checker_;
- base::Callback<void(std::vector<std::string> requirement_errorss)> callback_;
+ RequirementsCheckedCallback callback_;
+
+ base::WeakPtrFactory<ChromeRequirementsChecker> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeRequirementsChecker);
};
} // namespace extensions
-#endif // CHROME_BROWSER_EXTENSIONS_REQUIREMENTS_CHECKER_H_
+#endif // CHROME_BROWSER_EXTENSIONS_CHROME_REQUIREMENTS_CHECKER_H_
diff --git a/chrome/browser/extensions/extension_install_checker.cc b/chrome/browser/extensions/extension_install_checker.cc
index 0901a00..313225df 100644
--- a/chrome/browser/extensions/extension_install_checker.cc
+++ b/chrome/browser/extensions/extension_install_checker.cc
@@ -6,7 +6,7 @@
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/blacklist.h"
-#include "chrome/browser/extensions/requirements_checker.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"
@@ -90,7 +90,7 @@ void ExtensionInstallChecker::CheckRequirements() {
DCHECK(extension_.get());
if (!requirements_checker_.get())
- requirements_checker_.reset(new RequirementsChecker());
+ requirements_checker_.reset(new ChromeRequirementsChecker());
requirements_checker_->Check(
extension_,
base::Bind(&ExtensionInstallChecker::OnRequirementsCheckDone,
@@ -100,7 +100,7 @@ void ExtensionInstallChecker::CheckRequirements() {
void ExtensionInstallChecker::OnRequirementsCheckDone(
int sequence_number,
- std::vector<std::string> errors) {
+ const std::vector<std::string>& errors) {
// Some pending results may arrive after fail fast.
if (sequence_number != current_sequence_number_)
return;
diff --git a/chrome/browser/extensions/extension_install_checker.h b/chrome/browser/extensions/extension_install_checker.h
index 17a517bd..a13bdff 100644
--- a/chrome/browser/extensions/extension_install_checker.h
+++ b/chrome/browser/extensions/extension_install_checker.h
@@ -84,7 +84,7 @@ class ExtensionInstallChecker {
virtual void CheckRequirements();
void OnRequirementsCheckDone(int sequence_number,
- std::vector<std::string> errors);
+ const std::vector<std::string>& errors);
virtual void CheckBlacklistState();
void OnBlacklistStateCheckDone(int sequence_number, BlacklistState state);
diff --git a/chrome/browser/extensions/requirements_checker_browsertest.cc b/chrome/browser/extensions/requirements_checker_browsertest.cc
index 7168151..efda739 100644
--- a/chrome/browser/extensions/requirements_checker_browsertest.cc
+++ b/chrome/browser/extensions/requirements_checker_browsertest.cc
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/extensions/requirements_checker.h"
-
#include <vector>
#include "base/bind.h"
@@ -12,6 +10,7 @@
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/strings/string_util.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"
@@ -27,6 +26,9 @@ 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;
@@ -40,10 +42,10 @@ class RequirementsCheckerBrowserTest : public ExtensionBrowserTest {
return extension;
}
- void ValidateRequirementErrors(std::vector<std::string> expected_errors,
- std::vector<std::string> actual_errors) {
+ void ValidateRequirementErrors(
+ const std::vector<std::string>& expected_errors,
+ const std::vector<std::string>& actual_errors) {
ASSERT_EQ(expected_errors, actual_errors);
- requirement_errors_.swap(actual_errors);
}
// This should only be called once per test instance. Calling more than once
@@ -73,15 +75,14 @@ class RequirementsCheckerBrowserTest : public ExtensionBrowserTest {
}
protected:
- std::vector<std::string> requirement_errors_;
- RequirementsChecker checker_;
+ scoped_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(
+ checker_->Check(extension, base::Bind(
&RequirementsCheckerBrowserTest::ValidateRequirementErrors,
base::Unretained(this), std::vector<std::string>()));
content::RunAllBlockingPoolTasksUntilIdle();
@@ -98,7 +99,7 @@ IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, CheckNpapiExtension) {
IDS_EXTENSION_NPAPI_NOT_SUPPORTED));
#endif
- checker_.Check(extension, base::Bind(
+ checker_->Check(extension, base::Bind(
&RequirementsCheckerBrowserTest::ValidateRequirementErrors,
base::Unretained(this), expected_errors));
content::RunAllBlockingPoolTasksUntilIdle();
@@ -116,7 +117,7 @@ IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest,
IDS_EXTENSION_WINDOW_SHAPE_NOT_SUPPORTED));
#endif // !defined(USE_AURA)
- checker_.Check(extension, base::Bind(
+ checker_->Check(extension, base::Bind(
&RequirementsCheckerBrowserTest::ValidateRequirementErrors,
base::Unretained(this), expected_errors));
content::RunAllBlockingPoolTasksUntilIdle();
@@ -137,7 +138,7 @@ IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, DisallowWebGL) {
expected_errors.push_back(l10n_util::GetStringUTF8(
IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
- checker_.Check(extension, base::Bind(
+ checker_->Check(extension, base::Bind(
&RequirementsCheckerBrowserTest::ValidateRequirementErrors,
base::Unretained(this), expected_errors));
content::RunAllBlockingPoolTasksUntilIdle();
@@ -155,7 +156,7 @@ IN_PROC_BROWSER_TEST_F(RequirementsCheckerBrowserTest, Check3DExtension) {
IDS_EXTENSION_WEBGL_NOT_SUPPORTED));
}
- checker_.Check(extension, base::Bind(
+ checker_->Check(extension, base::Bind(
&RequirementsCheckerBrowserTest::ValidateRequirementErrors,
base::Unretained(this), expected_errors));
content::RunAllBlockingPoolTasksUntilIdle();
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
index 6083af0..6bd4f0a 100644
--- a/chrome/browser/resources/extensions/extension_list.js
+++ b/chrome/browser/resources/extensions/extension_list.js
@@ -271,7 +271,8 @@ cr.define('options', function() {
// The 'Enabled' checkbox.
this.addListener_('change', node, '.enable-checkbox input', function(e) {
var checked = e.target.checked;
- chrome.send('extensionSettingsEnable', [extension.id, String(checked)]);
+ // TODO(devlin): What should we do if this fails?
+ chrome.management.setEnabled(extension.id, checked);
// This may seem counter-intuitive (to not set/clear the checkmark)
// but this page will be updated asynchronously if the extension
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index 9537f61..64afdb0 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -29,7 +29,6 @@
#include "chrome/browser/extensions/devtools_util.h"
#include "chrome/browser/extensions/error_console/error_console.h"
#include "chrome/browser/extensions/extension_action_manager.h"
-#include "chrome/browser/extensions/extension_disabled_ui.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -693,9 +692,6 @@ void ExtensionSettingsHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback("extensionSettingsRepair",
base::Bind(&ExtensionSettingsHandler::HandleRepairMessage,
AsWeakPtr()));
- web_ui()->RegisterMessageCallback("extensionSettingsEnable",
- base::Bind(&ExtensionSettingsHandler::HandleEnableMessage,
- AsWeakPtr()));
web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito",
base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage,
AsWeakPtr()));
@@ -1065,50 +1061,6 @@ void ExtensionSettingsHandler::HandleRepairMessage(
reinstaller->BeginReinstall();
}
-void ExtensionSettingsHandler::HandleEnableMessage(
- const base::ListValue* args) {
- CHECK_EQ(2U, args->GetSize());
- std::string extension_id, enable_str;
- CHECK(args->GetString(0, &extension_id));
- CHECK(args->GetString(1, &enable_str));
-
- const Extension* extension =
- extension_service_->GetInstalledExtension(extension_id);
- if (!extension)
- return;
-
- if (!management_policy_->UserMayModifySettings(extension, NULL)) {
- LOG(ERROR) << "An attempt was made to enable an extension that is "
- << "non-usermanagable. Extension id: " << extension->id();
- return;
- }
-
- if (enable_str == "true") {
- ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile());
- if (prefs->DidExtensionEscalatePermissions(extension_id)) {
- ShowExtensionDisabledDialog(
- extension_service_, web_ui()->GetWebContents(), extension);
- } else if ((prefs->GetDisableReasons(extension_id) &
- Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
- !requirements_checker_.get()) {
- // Recheck the requirements.
- scoped_refptr<const Extension> extension =
- extension_service_->GetExtensionById(extension_id,
- true /* include disabled */);
- requirements_checker_.reset(new RequirementsChecker);
- requirements_checker_->Check(
- extension,
- base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked,
- AsWeakPtr(), extension_id));
- } else {
- extension_service_->EnableExtension(extension_id);
- }
- } else {
- extension_service_->DisableExtension(
- extension_id, Extension::DISABLE_USER_ACTION);
- }
-}
-
void ExtensionSettingsHandler::HandleEnableIncognitoMessage(
const base::ListValue* args) {
CHECK_EQ(2U, args->GetSize());
@@ -1521,17 +1473,4 @@ void ExtensionSettingsHandler::OnReinstallComplete(
MaybeUpdateAfterNotification();
}
-void ExtensionSettingsHandler::OnRequirementsChecked(
- std::string extension_id,
- std::vector<std::string> requirement_errors) {
- if (requirement_errors.empty()) {
- extension_service_->EnableExtension(extension_id);
- } else {
- ExtensionErrorReporter::GetInstance()->ReportError(
- base::UTF8ToUTF16(JoinString(requirement_errors, ' ')),
- true); // Be noisy.
- }
- requirements_checker_.reset();
-}
-
} // namespace extensions
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.h b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
index 779a484..1a99f98 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
@@ -15,7 +15,6 @@
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
-#include "chrome/browser/extensions/requirements_checker.h"
#include "chrome/common/extensions/webstore_install_result.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/notification_observer.h"
@@ -171,9 +170,6 @@ class ExtensionSettingsHandler
// Callback for "repair" message.
void HandleRepairMessage(const base::ListValue* args);
- // Callback for "enable" message.
- void HandleEnableMessage(const base::ListValue* args);
-
// Callback for "enableIncognito" message.
void HandleEnableIncognitoMessage(const base::ListValue* args);
@@ -240,10 +236,6 @@ class ExtensionSettingsHandler
const std::string& error,
webstore_install::Result result);
- // Callback for RequirementsChecker.
- void OnRequirementsChecked(std::string extension_id,
- std::vector<std::string> requirement_errors);
-
// Handles the load retry notification sent from
// ExtensionService::ReportExtensionLoadError. Attempts to retry loading
// extension from |path| if retry is true, otherwise removes |path| from the
@@ -288,11 +280,6 @@ class ExtensionSettingsHandler
content::NotificationRegistrar registrar_;
- // This will not be empty when a requirements check is in progress. Doing
- // another Check() before the previous one is complete will cause the first
- // one to abort.
- scoped_ptr<RequirementsChecker> requirements_checker_;
-
// The UI for showing what permissions the extension has.
scoped_ptr<ExtensionInstallPrompt> prompt_;
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 66e4e45b..0d8eec1 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -508,6 +508,8 @@
'browser/extensions/chrome_notification_observer.h',
'browser/extensions/chrome_process_manager_delegate.cc',
'browser/extensions/chrome_process_manager_delegate.h',
+ 'browser/extensions/chrome_requirements_checker.cc',
+ 'browser/extensions/chrome_requirements_checker.h',
'browser/extensions/chrome_url_request_util.cc',
'browser/extensions/chrome_url_request_util.h',
'browser/extensions/component_loader.cc',
@@ -722,8 +724,6 @@
'browser/extensions/plugin_manager.h',
'browser/extensions/proxy_overridden_bubble_controller.cc',
'browser/extensions/proxy_overridden_bubble_controller.h',
- 'browser/extensions/requirements_checker.cc',
- 'browser/extensions/requirements_checker.h',
'browser/extensions/settings_api_bubble_controller.cc',
'browser/extensions/settings_api_bubble_controller.h',
'browser/extensions/settings_api_helpers.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 5c98e09..371ce1e 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -27,6 +27,7 @@
'browser/autocomplete/builtin_provider_unittest.cc',
'browser/autocomplete/history_quick_provider_unittest.cc',
'browser/autocomplete/history_url_provider_unittest.cc',
+ 'browser/autocomplete/scored_history_match_builder_impl_unittest.cc',
'browser/autocomplete/search_provider_unittest.cc',
'browser/autocomplete/shortcuts_backend_unittest.cc',
'browser/autocomplete/shortcuts_database_unittest.cc',
@@ -111,7 +112,6 @@
'browser/history/history_querying_unittest.cc',
'browser/history/history_unittest.cc',
'browser/history/in_memory_url_index_unittest.cc',
- 'browser/autocomplete/scored_history_match_builder_impl_unittest.cc',
'browser/history/thumbnail_database_unittest.cc',
'browser/history/top_sites_impl_unittest.cc',
'browser/history/typed_url_syncable_service_unittest.cc',
@@ -692,6 +692,7 @@
'browser/extensions/api/image_writer_private/test_utils.cc',
'browser/extensions/api/image_writer_private/write_from_file_operation_unittest.cc',
'browser/extensions/api/image_writer_private/write_from_url_operation_unittest.cc',
+ 'browser/extensions/api/management/management_api_unittest.cc',
'browser/extensions/api/mdns/dns_sd_registry_unittest.cc',
'browser/extensions/api/omnibox/omnibox_unittest.cc',
'browser/extensions/api/permissions/permissions_api_helpers_unittest.cc',
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index ca31e20..251a48a 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -248,10 +248,18 @@
],
"contexts": ["blessed_extension"]
}],
- "developerPrivate": {
+ "developerPrivate": [{
"dependencies": ["permission:developerPrivate"],
"contexts": ["blessed_extension"]
- },
+ }, {
+ "channel": "stable",
+ "contexts": ["webui"],
+ "matches": [
+ "chrome://extensions/*",
+ "chrome://extensions-frame/*",
+ "chrome://chrome/extensions/*"
+ ]
+ }],
// All devtools APIs are implemented by hand, so don't compile them.
"devtools.inspectedWindow": {
"nocompile": true,
diff --git a/chrome/test/data/extensions/webui/sanity_check_available_apis.js b/chrome/test/data/extensions/webui/sanity_check_available_apis.js
index b345b3b..195b02a 100644
--- a/chrome/test/data/extensions/webui/sanity_check_available_apis.js
+++ b/chrome/test/data/extensions/webui/sanity_check_available_apis.js
@@ -14,8 +14,10 @@
var expected = [
'csi',
+ 'developerPrivate',
'getVariableValue',
'loadTimes',
+ 'management',
'runtime',
'send',
'test',
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc
index 08700dc..4d2292c 100644
--- a/extensions/browser/api/management/management_api.cc
+++ b/extensions/browser/api/management/management_api.cc
@@ -26,6 +26,7 @@
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/management_policy.h"
+#include "extensions/browser/requirements_checker.h"
#include "extensions/browser/uninstall_reason.h"
#include "extensions/common/api/management.h"
#include "extensions/common/constants.h"
@@ -419,7 +420,7 @@ ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
}
-bool ManagementSetEnabledFunction::RunAsync() {
+ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
scoped_ptr<management::SetEnabled::Params> params(
management::SetEnabled::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
@@ -432,36 +433,41 @@ bool ManagementSetEnabledFunction::RunAsync() {
const Extension* extension =
registry->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
- if (!extension || ShouldNotBeVisible(extension, browser_context())) {
- error_ =
- ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, extension_id_);
- return false;
- }
+ if (!extension || ShouldNotBeVisible(extension, browser_context()))
+ return RespondNow(Error(keys::kNoExtensionError, extension_id_));
+ bool enabled = params->enabled;
const ManagementPolicy* policy =
ExtensionSystem::Get(browser_context())->management_policy();
- if (!policy->UserMayModifySettings(extension, NULL) ||
- (!params->enabled && policy->MustRemainEnabled(extension, NULL)) ||
- (params->enabled && policy->MustRemainDisabled(extension, NULL, NULL))) {
- error_ = ErrorUtils::FormatErrorMessage(keys::kUserCantModifyError,
- extension_id_);
- return false;
+ if (!policy->UserMayModifySettings(extension, nullptr) ||
+ (!enabled && policy->MustRemainEnabled(extension, nullptr)) ||
+ (enabled && policy->MustRemainDisabled(extension, nullptr, nullptr))) {
+ return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
}
bool currently_enabled =
registry->enabled_extensions().Contains(extension_id_) ||
registry->terminated_extensions().Contains(extension_id_);
- if (!currently_enabled && params->enabled) {
+ if (!currently_enabled && enabled) {
ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
- if (!user_gesture()) {
- SetError(keys::kGestureNeededForEscalationError);
- return false;
- }
+ if (!user_gesture())
+ return RespondNow(Error(keys::kGestureNeededForEscalationError));
+
AddRef(); // Matched in InstallUIProceed/InstallUIAbort
install_prompt_ = delegate->SetEnabledFunctionDelegate(this, extension);
- return true;
+ return RespondLater();
+ }
+ if (prefs->GetDisableReasons(extension_id_) &
+ Extension::DISABLE_UNSUPPORTED_REQUIREMENT) {
+ // Recheck the requirements.
+ requirements_checker_ = delegate->CreateRequirementsChecker();
+ requirements_checker_->Check(
+ extension,
+ base::Bind(&ManagementSetEnabledFunction::OnRequirementsChecked,
+ this)); // This bind creates a reference.
+ return RespondLater();
}
delegate->EnableExtension(browser_context(), extension_id_);
} else if (currently_enabled && !params->enabled) {
@@ -469,11 +475,7 @@ bool ManagementSetEnabledFunction::RunAsync() {
Extension::DISABLE_USER_ACTION);
}
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true));
-
- return true;
+ return RespondNow(NoArguments());
}
void ManagementSetEnabledFunction::InstallUIProceed() {
@@ -481,16 +483,28 @@ void ManagementSetEnabledFunction::InstallUIProceed() {
->Get(browser_context())
->GetDelegate()
->EnableExtension(browser_context(), extension_id_);
- SendResponse(true);
+ Respond(OneArgument(new base::FundamentalValue(true)));
Release();
}
void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
- error_ = keys::kUserDidNotReEnableError;
- SendResponse(false);
+ Respond(Error(keys::kUserDidNotReEnableError));
Release();
}
+void ManagementSetEnabledFunction::OnRequirementsChecked(
+ const std::vector<std::string>& requirements_errors) {
+ if (requirements_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,
+ JoinString(requirements_errors, ' ')));
+ }
+}
+
ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
}
diff --git a/extensions/browser/api/management/management_api.h b/extensions/browser/api/management/management_api.h
index ab7fb84..e49789b 100644
--- a/extensions/browser/api/management/management_api.h
+++ b/extensions/browser/api/management/management_api.h
@@ -20,6 +20,7 @@ struct WebApplicationInfo;
namespace extensions {
class ExtensionRegistry;
+class RequirementsChecker;
class ManagementFunction : public SyncExtensionFunction {
protected:
@@ -104,7 +105,7 @@ class ManagementLaunchAppFunction : public ManagementFunction {
bool RunSync() override;
};
-class ManagementSetEnabledFunction : public AsyncManagementFunction {
+class ManagementSetEnabledFunction : public UIThreadExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("management.setEnabled", MANAGEMENT_SETENABLED)
@@ -117,12 +118,16 @@ class ManagementSetEnabledFunction : public AsyncManagementFunction {
~ManagementSetEnabledFunction() override;
// ExtensionFunction:
- bool RunAsync() override;
+ ResponseAction Run() override;
private:
+ void OnRequirementsChecked(const std::vector<std::string>& requirements);
+
std::string extension_id_;
scoped_ptr<InstallPromptDelegate> install_prompt_;
+
+ scoped_ptr<RequirementsChecker> requirements_checker_;
};
class ManagementUninstallFunctionBase : public AsyncManagementFunction {
diff --git a/extensions/browser/api/management/management_api_constants.cc b/extensions/browser/api/management/management_api_constants.cc
index f4fb8ff..924b357 100644
--- a/extensions/browser/api/management/management_api_constants.cc
+++ b/extensions/browser/api/management/management_api_constants.cc
@@ -25,6 +25,7 @@ const char kUninstallCanceledError[] =
"Extension * uninstall canceled by user.";
const char kUserDidNotReEnableError[] =
"The user did not accept the re-enable dialog.";
+const char kMissingRequirementsError[] = "There were missing requirements: *.";
const char kGestureNeededForCreateAppShortcutError[] =
"chrome.management.createAppShortcut requires a user gesture.";
const char kNoBrowserToCreateShortcut[] =
diff --git a/extensions/browser/api/management/management_api_constants.h b/extensions/browser/api/management/management_api_constants.h
index faadae1..bdbeffb 100644
--- a/extensions/browser/api/management/management_api_constants.h
+++ b/extensions/browser/api/management/management_api_constants.h
@@ -23,6 +23,7 @@ extern const char kNotAnAppError[];
extern const char kUserCantModifyError[];
extern const char kUninstallCanceledError[];
extern const char kUserDidNotReEnableError[];
+extern const char kMissingRequirementsError[];
extern const char kGestureNeededForCreateAppShortcutError[];
extern const char kNoBrowserToCreateShortcut[];
extern const char kCreateOnlyPackagedAppShortcutMac[];
diff --git a/extensions/browser/api/management/management_api_delegate.h b/extensions/browser/api/management/management_api_delegate.h
index 6311b3d..1af47bf 100644
--- a/extensions/browser/api/management/management_api_delegate.h
+++ b/extensions/browser/api/management/management_api_delegate.h
@@ -25,6 +25,7 @@ class ManagementGenerateAppForLinkFunction;
class ManagementGetPermissionWarningsByManifestFunction;
class ManagementSetEnabledFunction;
class ManagementUninstallFunctionBase;
+class RequirementsChecker;
// Manages the lifetime of the install prompt.
class InstallPromptDelegate {
@@ -76,6 +77,9 @@ class ManagementAPIDelegate {
ManagementSetEnabledFunction* function,
const Extension* extension) const = 0;
+ // Returns a new RequirementsChecker.
+ virtual scoped_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/requirements_checker.h b/extensions/browser/requirements_checker.h
new file mode 100644
index 0000000..a5c1614
--- /dev/null
+++ b/extensions/browser/requirements_checker.h
@@ -0,0 +1,38 @@
+// Copyright 2015 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_REQUIREMENTS_CHECKER_H_
+#define CHROME_BROWSER_EXTENSIONS_REQUIREMENTS_CHECKER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+
+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 RequirementsChecker {
+ public:
+ virtual ~RequirementsChecker() {}
+
+ using RequirementsCheckedCallback =
+ base::Callback<void(const std::vector<std::string>& /* requirements */)>;
+
+ // 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;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_REQUIREMENTS_CHECKER_H_
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index c2c16ed..76a6cdf 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -173,10 +173,19 @@
"dependencies": ["permission:idle"],
"contexts": ["blessed_extension"]
},
- "management": {
+ "management": [{
"dependencies": ["permission:management"],
- "contexts": ["blessed_extension"]
- },
+ "contexts": ["blessed_extension"],
+ "default_parent": true
+ }, {
+ "channel": "stable",
+ "contexts": ["webui"],
+ "matches": [
+ "chrome://extensions/*",
+ "chrome://extensions-frame/*",
+ "chrome://chrome/extensions/*"
+ ]
+ }],
"management.getPermissionWarningsByManifest": {
"dependencies": [],
"channel": "stable",
diff --git a/extensions/common/features/base_feature_provider.cc b/extensions/common/features/base_feature_provider.cc
index 9b927cc..40807f41 100644
--- a/extensions/common/features/base_feature_provider.cc
+++ b/extensions/common/features/base_feature_provider.cc
@@ -66,7 +66,20 @@ BaseFeatureProvider::BaseFeatureProvider(const base::DictionaryValue& root,
split.pop_back();
if (root.HasKey(parent_name)) {
const base::DictionaryValue* parent = nullptr;
- CHECK(root.GetDictionaryWithoutPathExpansion(parent_name, &parent));
+ if (!root.GetDictionaryWithoutPathExpansion(parent_name, &parent)) {
+ // If the parent is a complex feature, find the parent with the
+ // 'default_parent' flag.
+ const base::ListValue* parent_list = nullptr;
+ CHECK(root.GetListWithoutPathExpansion(parent_name, &parent_list));
+ for (size_t i = 0; i < parent_list->GetSize(); ++i) {
+ CHECK(parent_list->GetDictionary(i, &parent));
+ if (parent->HasKey("default_parent"))
+ break;
+ parent = nullptr;
+ }
+ CHECK(parent) << parent_name << " must declare one of its features"
+ << " the default parent, with {\"default_parent\": true}.";
+ }
parse_stack.push(std::make_pair(parent_name, parent));
bool no_parent = false;
parent->GetBoolean("noparent", &no_parent);
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index 7caee4a..b8641e0 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -707,6 +707,7 @@
'browser/quota_service.h',
'browser/renderer_startup_helper.cc',
'browser/renderer_startup_helper.h',
+ 'browser/requirements_checker.h',
'browser/runtime_data.cc',
'browser/runtime_data.h',
'browser/sandboxed_unpacker.cc',