Move BrowserAction out of Extension

BUG=159265

Review URL: https://chromiumcodereview.appspot.com/11644057

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179186 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
index f3cab931..398dcb5 100644
--- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc
+++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "chrome/common/extensions/api/extension_action/browser_action_handler.h"
 #include "chrome/common/extensions/api/extension_action/script_badge_handler.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/extensions/manifest_handler.h"
@@ -186,10 +187,39 @@
     g_factory = LAZY_INSTANCE_INITIALIZER;
 
 ExtensionActionAPI::ExtensionActionAPI(Profile* profile) {
+  ManifestHandler::Register(extension_manifest_keys::kBrowserAction,
+                            new BrowserActionHandler);
   ManifestHandler::Register(extension_manifest_keys::kScriptBadge,
                             new ScriptBadgeHandler);
+
   ExtensionFunctionRegistry* registry =
       ExtensionFunctionRegistry::GetInstance();
+
+  // Browser Actions
+  registry->RegisterFunction<BrowserActionSetIconFunction>();
+  registry->RegisterFunction<BrowserActionSetTitleFunction>();
+  registry->RegisterFunction<BrowserActionSetBadgeTextFunction>();
+  registry->RegisterFunction<BrowserActionSetBadgeBackgroundColorFunction>();
+  registry->RegisterFunction<BrowserActionSetPopupFunction>();
+  registry->RegisterFunction<BrowserActionGetTitleFunction>();
+  registry->RegisterFunction<BrowserActionGetBadgeTextFunction>();
+  registry->RegisterFunction<BrowserActionGetBadgeBackgroundColorFunction>();
+  registry->RegisterFunction<BrowserActionGetPopupFunction>();
+  registry->RegisterFunction<BrowserActionEnableFunction>();
+  registry->RegisterFunction<BrowserActionDisableFunction>();
+
+  // Page Actions
+  registry->RegisterFunction<EnablePageActionsFunction>();
+  registry->RegisterFunction<DisablePageActionsFunction>();
+  registry->RegisterFunction<PageActionShowFunction>();
+  registry->RegisterFunction<PageActionHideFunction>();
+  registry->RegisterFunction<PageActionSetIconFunction>();
+  registry->RegisterFunction<PageActionSetTitleFunction>();
+  registry->RegisterFunction<PageActionSetPopupFunction>();
+  registry->RegisterFunction<PageActionGetTitleFunction>();
+  registry->RegisterFunction<PageActionGetPopupFunction>();
+
+  // Script Badges
   registry->RegisterFunction<ScriptBadgeGetAttentionFunction>();
   registry->RegisterFunction<ScriptBadgeGetPopupFunction>();
   registry->RegisterFunction<ScriptBadgeSetPopupFunction>();
diff --git a/chrome/browser/extensions/extension_action_manager.cc b/chrome/browser/extensions/extension_action_manager.cc
index bcdcc5b..468cf74 100644
--- a/chrome/browser/extensions/extension_action_manager.cc
+++ b/chrome/browser/extensions/extension_action_manager.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/profiles/profile_keyed_service_factory.h"
 #include "chrome/common/chrome_notification_types.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
-#include "chrome/common/extensions/api/extension_action/script_badge_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/feature_switch.h"
 #include "content/public/browser/notification_service.h"
@@ -130,7 +129,7 @@
 
 ExtensionAction* ExtensionActionManager::GetBrowserAction(
     const extensions::Extension& extension) const {
-  const ActionInfo* action_info = extension.browser_action_info();
+  const ActionInfo* action_info = ActionInfo::GetBrowserActionInfo(&extension);
   ActionInfo::Type action_type = ActionInfo::TYPE_BROWSER;
   if (FeatureSwitch::script_badges()->IsEnabled() &&
       extension.page_action_info()) {
diff --git a/chrome/browser/extensions/extension_function_registry.cc b/chrome/browser/extensions/extension_function_registry.cc
index 4dc056c..a121881c 100644
--- a/chrome/browser/extensions/extension_function_registry.cc
+++ b/chrome/browser/extensions/extension_function_registry.cc
@@ -52,30 +52,6 @@
 
   // Register all functions here.
 
-  // Page Actions.
-  RegisterFunction<EnablePageActionsFunction>();
-  RegisterFunction<DisablePageActionsFunction>();
-  RegisterFunction<PageActionShowFunction>();
-  RegisterFunction<PageActionHideFunction>();
-  RegisterFunction<PageActionSetIconFunction>();
-  RegisterFunction<PageActionSetTitleFunction>();
-  RegisterFunction<PageActionSetPopupFunction>();
-  RegisterFunction<PageActionGetTitleFunction>();
-  RegisterFunction<PageActionGetPopupFunction>();
-
-  // Browser Actions.
-  RegisterFunction<extensions::BrowserActionSetIconFunction>();
-  RegisterFunction<extensions::BrowserActionSetTitleFunction>();
-  RegisterFunction<extensions::BrowserActionSetBadgeTextFunction>();
-  RegisterFunction<extensions::BrowserActionSetBadgeBackgroundColorFunction>();
-  RegisterFunction<extensions::BrowserActionSetPopupFunction>();
-  RegisterFunction<extensions::BrowserActionGetTitleFunction>();
-  RegisterFunction<extensions::BrowserActionGetBadgeTextFunction>();
-  RegisterFunction<extensions::BrowserActionGetBadgeBackgroundColorFunction>();
-  RegisterFunction<extensions::BrowserActionGetPopupFunction>();
-  RegisterFunction<extensions::BrowserActionEnableFunction>();
-  RegisterFunction<extensions::BrowserActionDisableFunction>();
-
   // Browsing Data.
   RegisterFunction<RemoveBrowsingDataFunction>();
   RegisterFunction<RemoveAppCacheFunction>();
diff --git a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
index 3bc1b74..0a801151 100644
--- a/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/browser_actions_controller.mm
@@ -25,6 +25,7 @@
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
 #import "chrome/browser/ui/cocoa/menu_button.h"
 #include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -536,7 +537,7 @@
 }
 
 - (void)removeActionButtonForExtension:(const Extension*)extension {
-  if (!extension->browser_action_info())
+  if (!extensions::ActionInfo::GetBrowserActionInfo(extension))
     return;
 
   NSString* buttonKey = base::SysUTF8ToNSString(extension->id());
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index d37e3378..e991fa4 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -129,6 +129,8 @@
         'common/descriptors_android.h',
         'common/extensions/api/commands/commands_handler.cc',
         'common/extensions/api/commands/commands_handler.h',
+        'common/extensions/api/extension_action/browser_action_handler.cc',
+        'common/extensions/api/extension_action/browser_action_handler.h',
         'common/extensions/api/extension_action/script_badge_handler.cc',
         'common/extensions/api/extension_action/script_badge_handler.h',
         'common/extensions/api/extension_action/action_info.cc',
@@ -474,6 +476,8 @@
             ['include', 'common/extensions/api/extension_api_stub.cc'],
             ['include', 'common/extensions/api/extension_action/action_info.cc'],
             ['include', 'common/extensions/api/extension_action/action_info.h'],
+            ['include', 'common/extensions/api/extension_action/browser_action_handler.cc'],
+            ['include', 'common/extensions/api/extension_action/browser_action_handler.h'],
           ],
         }],
         ['remoting==1', {
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index d5add6a..7fa9baea 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -1457,6 +1457,8 @@
         'common/content_settings_pattern_parser_unittest.cc',
         'common/content_settings_pattern_unittest.cc',
         'common/extensions/api/commands/commands_manifest_unittest.cc',
+        'common/extensions/api/extension_action/browser_action_manifest_unittest.cc',
+        'common/extensions/api/extension_action/page_action_manifest_unittest.cc',
         'common/extensions/api/extension_action/script_badge_manifest_unittest.cc',
         'common/extensions/command_unittest.cc',
         'common/extensions/csp_validator_unittest.cc',
@@ -1476,7 +1478,6 @@
         'common/extensions/manifest_tests/extension_manifest_test.cc',
         'common/extensions/manifest_tests/extension_manifests_auth_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_background_unittest.cc',
-        'common/extensions/manifest_tests/extension_manifests_browseraction_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_contentscript_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc',
@@ -1494,7 +1495,6 @@
         'common/extensions/manifest_tests/extension_manifests_old_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_options_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_override_unittest.cc',
-        'common/extensions/manifest_tests/extension_manifests_pageaction_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_portsinpermissions_unittest.cc',
         'common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc',
diff --git a/chrome/common/extensions/api/extension_action/action_info.cc b/chrome/common/extensions/api/extension_action/action_info.cc
index 7d7ac10..5201575 100644
--- a/chrome/common/extensions/api/extension_action/action_info.cc
+++ b/chrome/common/extensions/api/extension_action/action_info.cc
@@ -29,6 +29,13 @@
 ActionInfoData::~ActionInfoData() {
 }
 
+static const ActionInfo* GetActionInfo(const Extension* extension,
+                                       const std::string& key) {
+  ActionInfoData* data = static_cast<ActionInfoData*>(
+      extension->GetManifestData(key));
+  return data ? data->action_info.get() : NULL;
+}
+
 }  // namespace
 
 ActionInfo::ActionInfo() {
@@ -38,10 +45,19 @@
 }
 
 // static
+const ActionInfo* ActionInfo::GetBrowserActionInfo(const Extension* extension) {
+  return GetActionInfo(extension, extension_manifest_keys::kBrowserAction);
+}
+
+// static
 const ActionInfo* ActionInfo::GetScriptBadgeInfo(const Extension* extension) {
-  ActionInfoData* data = static_cast<ActionInfoData*>(
-      extension->GetManifestData(extension_manifest_keys::kScriptBadge));
-  return data ? data->action_info.get() : NULL;
+  return GetActionInfo(extension, extension_manifest_keys::kScriptBadge);
+}
+
+// static
+void ActionInfo::SetBrowserActionInfo(Extension* extension, ActionInfo* info) {
+  extension->SetManifestData(extension_manifest_keys::kBrowserAction,
+                             new ActionInfoData(info));
 }
 
 // static
diff --git a/chrome/common/extensions/api/extension_action/action_info.h b/chrome/common/extensions/api/extension_action/action_info.h
index 09e7ecc..c17759a4 100644
--- a/chrome/common/extensions/api/extension_action/action_info.h
+++ b/chrome/common/extensions/api/extension_action/action_info.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "googleurl/src/gurl.h"
 
@@ -26,12 +27,17 @@
     TYPE_SYSTEM_INDICATOR,
   };
 
-  // Returns the appropriate ActionInfo for the given |extension|.
-  static const ActionInfo* GetScriptBadgeInfo(const Extension* extension);
+  // Returns the extension's browser action, if any.
+  static const ActionInfo* GetBrowserActionInfo(const Extension* extension);
 
-  // Sets the appropriate ActionInfo as ManifestData for the given |extension|.
-  // This is static since |extension| takes ownership of |info|.
-  static void SetScriptBadgeInfo(Extension* extension, ActionInfo* info);
+  // Returns the extension's script badge.
+  static const ActionInfo* GetScriptBadgeInfo(const Extension* etxension);
+
+  // Sets the extension's browser action. |extension| takes ownership of |info|.
+  static void SetBrowserActionInfo(Extension* extension, ActionInfo* info);
+
+  // Sets the extension's script badge. |extension| takes ownership of |info|.
+  static void SetScriptBadgeInfo(Extension* etxension, ActionInfo* info);
 
   // Empty implies the key wasn't present.
   ExtensionIconSet default_icon;
diff --git a/chrome/common/extensions/api/extension_action/browser_action_handler.cc b/chrome/common/extensions/api/extension_action/browser_action_handler.cc
new file mode 100644
index 0000000..45ec188
--- /dev/null
+++ b/chrome/common/extensions/api/extension_action/browser_action_handler.cc
@@ -0,0 +1,43 @@
+// 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/common/extensions/api/extension_action/browser_action_handler.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/feature_switch.h"
+#include "chrome/common/extensions/manifest_handler_helpers.h"
+
+namespace extensions {
+
+BrowserActionHandler::BrowserActionHandler() {
+}
+
+BrowserActionHandler::~BrowserActionHandler() {
+}
+
+bool BrowserActionHandler::Parse(const base::Value* value,
+                                 Extension* extension,
+                                 string16* error) {
+  const DictionaryValue* dict = NULL;
+  if (!value->GetAsDictionary(&dict)) {
+    *error = ASCIIToUTF16(extension_manifest_errors::kInvalidBrowserAction);
+    return false;
+  }
+
+  scoped_ptr<ActionInfo> action_info =
+      manifest_handler_helpers::LoadActionInfo(extension, dict, error);
+  if (!action_info.get())
+    return false;  // Failed to parse browser action definition.
+
+  ActionInfo::SetBrowserActionInfo(extension, action_info.release());
+
+  return true;
+}
+
+}  // namespace extensions
diff --git a/chrome/common/extensions/api/extension_action/browser_action_handler.h b/chrome/common/extensions/api/extension_action/browser_action_handler.h
new file mode 100644
index 0000000..e9794454
--- /dev/null
+++ b/chrome/common/extensions/api/extension_action/browser_action_handler.h
@@ -0,0 +1,29 @@
+// 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_COMMON_EXTENSIONS_API_EXTENSION_ACTION_BROWSER_ACTION_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_API_EXTENSION_ACTION_BROWSER_ACTION_HANDLER_H_
+
+#include <string>
+
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/manifest_handler.h"
+
+namespace extensions {
+
+// Parses the "browser_action" manifest key.
+class BrowserActionHandler : public ManifestHandler {
+ public:
+  BrowserActionHandler();
+  virtual ~BrowserActionHandler();
+
+  virtual bool Parse(const base::Value* value,
+                     Extension* extension,
+                     string16* error) OVERRIDE;
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_COMMON_EXTENSIONS_API_EXTENSION_ACTION_BROWSER_ACTION_HANDLER_H_
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_browseraction_unittest.cc b/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc
similarity index 66%
rename from chrome/common/extensions/manifest_tests/extension_manifests_browseraction_unittest.cc
rename to chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc
index d6e9fb72..01ead27 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_browseraction_unittest.cc
+++ b/chrome/common/extensions/api/extension_action/browser_action_manifest_unittest.cc
@@ -2,9 +2,12 @@
 // 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/extension_action/action_info.h"
+#include "chrome/common/extensions/api/extension_action/browser_action_handler.h"
 #include "chrome/common/extensions/extension_builder.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/manifest_handler.h"
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 #include "chrome/common/extensions/value_builder.h"
 #include "extensions/common/error_utils.h"
@@ -15,7 +18,17 @@
 namespace extensions {
 namespace {
 
-TEST_F(ExtensionManifestTest, BrowserActionManifestIcons_NoDefaultIcons) {
+class BrowserActionManifestTest : public ExtensionManifestTest {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    ExtensionManifestTest::SetUp();
+    ManifestHandler::Register(extension_manifest_keys::kBrowserAction,
+                              new BrowserActionHandler);
+  }
+};
+
+TEST_F(BrowserActionManifestTest,
+       BrowserActionManifestIcons_NoDefaultIcons) {
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
       .SetManifest(DictionaryBuilder()
@@ -27,12 +40,14 @@
       .Build();
 
   ASSERT_TRUE(extension.get());
-  ASSERT_TRUE(extension->browser_action_info());
-  EXPECT_TRUE(extension->browser_action_info()->default_icon.empty());
+  const ActionInfo* browser_action_info =
+      ActionInfo::GetBrowserActionInfo(extension);
+  ASSERT_TRUE(browser_action_info);
+  EXPECT_TRUE(browser_action_info->default_icon.empty());
 }
 
-
-TEST_F(ExtensionManifestTest, BrowserActionManifestIcons_StringDefaultIcon) {
+TEST_F(BrowserActionManifestTest,
+       BrowserActionManifestIcons_StringDefaultIcon) {
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
       .SetManifest(DictionaryBuilder()
@@ -44,17 +59,19 @@
       .Build();
 
   ASSERT_TRUE(extension.get());
-  ASSERT_TRUE(extension->browser_action_info());
-  ASSERT_FALSE(extension->browser_action_info()->default_icon.empty());
+  const ActionInfo* browser_action_info =
+      ActionInfo::GetBrowserActionInfo(extension);
+  ASSERT_TRUE(browser_action_info);
+  ASSERT_FALSE(browser_action_info->default_icon.empty());
 
-  const ExtensionIconSet& icons =
-      extension->browser_action_info()->default_icon;
+  const ExtensionIconSet& icons = browser_action_info->default_icon;
 
   EXPECT_EQ(1u, icons.map().size());
   EXPECT_EQ("icon.png", icons.Get(19, ExtensionIconSet::MATCH_EXACTLY));
 }
 
-TEST_F(ExtensionManifestTest, BrowserActionManifestIcons_DictDefaultIcon) {
+TEST_F(BrowserActionManifestTest,
+       BrowserActionManifestIcons_DictDefaultIcon) {
   scoped_refptr<const Extension> extension =
       ExtensionBuilder()
       .SetManifest(DictionaryBuilder()
@@ -69,11 +86,12 @@
       .Build();
 
   ASSERT_TRUE(extension.get());
-  ASSERT_TRUE(extension->browser_action_info());
-  ASSERT_FALSE(extension->browser_action_info()->default_icon.empty());
+  const ActionInfo* browser_action_info =
+      ActionInfo::GetBrowserActionInfo(extension);
+  ASSERT_TRUE(browser_action_info);
+  ASSERT_FALSE(browser_action_info->default_icon.empty());
 
-  const ExtensionIconSet& icons =
-      extension->browser_action_info()->default_icon;
+  const ExtensionIconSet& icons = browser_action_info->default_icon;
 
   // 24px icon should be ignored.
   EXPECT_EQ(2u, icons.map().size());
@@ -81,7 +99,8 @@
   EXPECT_EQ("icon38.png", icons.Get(38, ExtensionIconSet::MATCH_EXACTLY));
 }
 
-TEST_F(ExtensionManifestTest, BrowserActionManifestIcons_InvalidDefaultIcon) {
+TEST_F(BrowserActionManifestTest,
+       BrowserActionManifestIcons_InvalidDefaultIcon) {
   scoped_ptr<DictionaryValue> manifest_value = DictionaryBuilder()
       .Set("name", "Invalid default icon")
       .Set("version", "1.0.0")
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_pageaction_unittest.cc b/chrome/common/extensions/api/extension_action/page_action_manifest_unittest.cc
similarity index 75%
rename from chrome/common/extensions/manifest_tests/extension_manifests_pageaction_unittest.cc
rename to chrome/common/extensions/api/extension_action/page_action_manifest_unittest.cc
index b77092b..f19e37e2 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_pageaction_unittest.cc
+++ b/chrome/common/extensions/api/extension_action/page_action_manifest_unittest.cc
@@ -4,13 +4,15 @@
 
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace errors = extension_manifest_errors;
+namespace extensions {
 
 TEST_F(ExtensionManifestTest, PageActionManifestVersion2) {
-  scoped_refptr<extensions::Extension> extension(
+  scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("page_action_manifest_version_2.json"));
   ASSERT_TRUE(extension.get());
   ASSERT_TRUE(extension->page_action_info());
@@ -21,5 +23,7 @@
   EXPECT_TRUE(extension->page_action_info()->default_popup_url.is_empty());
 
   LoadAndExpectError("page_action_manifest_version_2b.json",
-                     errors::kInvalidPageActionPopup);
+                     extension_manifest_errors::kInvalidPageActionPopup);
 }
+
+}  // namespace extensions
diff --git a/chrome/common/extensions/api/omnibox/omnibox_handler.cc b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
index ece5388b..287021dd 100644
--- a/chrome/common/extensions/api/omnibox/omnibox_handler.cc
+++ b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
@@ -9,6 +9,7 @@
 #include "base/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/common/extensions/api/commands/commands_handler.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 
@@ -31,7 +32,7 @@
 // static
 bool OmniboxInfo::IsVerboseInstallMessage(const Extension* extension) {
   return !GetKeyword(extension).empty() ||
-      extension->browser_action_info() ||
+      ActionInfo::GetBrowserActionInfo(extension) ||
       (extension->page_action_info() &&
        (CommandsInfo::GetPageActionCommand(extension) ||
         !extension->page_action_info()->default_icon.empty()));
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 60a7970..ab66dc9 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -916,10 +916,11 @@
     }
   }
 
-  if (browser_action_info() && !browser_action_info()->default_icon.empty()) {
+  const ActionInfo* browser_action = ActionInfo::GetBrowserActionInfo(this);
+  if (browser_action && !browser_action->default_icon.empty()) {
     for (ExtensionIconSet::IconMap::const_iterator iter =
-             browser_action_info()->default_icon.map().begin();
-         iter != browser_action_info()->default_icon.map().end();
+             browser_action->default_icon.map().begin();
+         iter != browser_action->default_icon.map().end();
          ++iter) {
        image_paths.insert(FilePath::FromWStringHack(UTF8ToWide(iter->second)));
     }
@@ -2381,7 +2382,6 @@
   if (!LoadManifestHandlerFeatures(error) ||
       !LoadContentScripts(error) ||
       !LoadPageAction(error) ||
-      !LoadBrowserAction(error) ||
       !LoadSystemIndicator(api_permissions, error) ||
       !LoadIncognitoMode(error) ||
       !LoadContentSecurityPolicy(error))
@@ -2476,22 +2476,6 @@
   return true;
 }
 
-bool Extension::LoadBrowserAction(string16* error) {
-  if (!manifest_->HasKey(keys::kBrowserAction))
-    return true;
-  DictionaryValue* browser_action_value = NULL;
-  if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) {
-    *error = ASCIIToUTF16(errors::kInvalidBrowserAction);
-    return false;
-  }
-
-  browser_action_info_ = LoadExtensionActionInfoHelper(
-      this, browser_action_value, error);
-  if (!browser_action_info_.get())
-    return false;  // Failed to parse browser action definition.
-  return true;
-}
-
 bool Extension::LoadSystemIndicator(APIPermissionSet* api_permissions,
                                     string16* error) {
   if (!manifest_->HasKey(keys::kSystemIndicator)) {
@@ -2980,7 +2964,7 @@
   if (page_action_info())
     ++num_surfaces;
 
-  if (browser_action_info())
+  if (ActionInfo::GetBrowserActionInfo(this))
     ++num_surfaces;
 
   if (is_app())
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 429bc03..45f943b 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -21,7 +21,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
-#include "chrome/common/extensions/api/extension_action/action_info.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_icon_set.h"
 #include "chrome/common/extensions/permissions/api_permission.h"
@@ -51,7 +50,7 @@
 FORWARD_DECLARE_TEST(TabStripModelTest, Apps);
 
 namespace extensions {
-
+struct ActionInfo;
 class Manifest;
 class PermissionSet;
 
@@ -606,9 +605,6 @@
   }
   const UserScriptList& content_scripts() const { return content_scripts_; }
   const ActionInfo* page_action_info() const { return page_action_info_.get(); }
-  const ActionInfo* browser_action_info() const {
-    return browser_action_info_.get();
-  }
   const ActionInfo* system_indicator_info() const {
     return system_indicator_info_.get();
   }
@@ -959,9 +955,6 @@
   // The extension's page action, if any.
   scoped_ptr<ActionInfo> page_action_info_;
 
-  // The extension's browser action, if any.
-  scoped_ptr<ActionInfo> browser_action_info_;
-
   // The extension's system indicator, if any.
   scoped_ptr<ActionInfo> system_indicator_info_;
 
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
index 59f8b35f4..f6d2e22 100644
--- a/chrome/common/extensions/extension_file_util.cc
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -20,6 +20,7 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "chrome/common/extensions/api/extension_action/browser_action_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
@@ -336,7 +337,7 @@
     return false;
   }
 
-  action = extension->browser_action_info();
+  action = extensions::ActionInfo::GetBrowserActionInfo(extension);
   if (action && !action->default_icon.empty() &&
       !ValidateExtensionIconSet(action->default_icon, extension,
           IDS_EXTENSION_LOAD_ICON_FOR_BROWSER_ACTION_FAILED, error)) {
diff --git a/chrome/common/extensions/extension_file_util_unittest.cc b/chrome/common/extensions/extension_file_util_unittest.cc
index d445fce..5418066 100644
--- a/chrome/common/extensions/extension_file_util_unittest.cc
+++ b/chrome/common/extensions/extension_file_util_unittest.cc
@@ -11,8 +11,10 @@
 #include "base/stringprintf.h"
 #include "base/utf_string_conversions.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/api/extension_action/browser_action_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/manifest_handler.h"
 #include "grit/generated_resources.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -22,11 +24,21 @@
 
 namespace keys = extension_manifest_keys;
 
+class ExtensionFileUtilTest : public testing::Test {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    testing::Test::SetUp();
+    extensions::ManifestHandler::Register(
+        extension_manifest_keys::kBrowserAction,
+        new extensions::BrowserActionHandler);
+  }
+};
+
 #if defined(OS_WIN)
 // http://crbug.com/106381
 #define InstallUninstallGarbageCollect DISABLED_InstallUninstallGarbageCollect
 #endif
-TEST(ExtensionFileUtil, InstallUninstallGarbageCollect) {
+TEST_F(ExtensionFileUtilTest, InstallUninstallGarbageCollect) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -97,7 +109,7 @@
   ASSERT_TRUE(file_util::DirectoryExists(all_extensions));
 }
 
-TEST(ExtensionFileUtil, LoadExtensionWithValidLocales) {
+TEST_F(ExtensionFileUtilTest, LoadExtensionWithValidLocales) {
   FilePath install_dir;
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
   install_dir = install_dir.AppendASCII("extensions")
@@ -113,7 +125,7 @@
   EXPECT_EQ("The first extension that I made.", extension->description());
 }
 
-TEST(ExtensionFileUtil, LoadExtensionWithoutLocalesFolder) {
+TEST_F(ExtensionFileUtilTest, LoadExtensionWithoutLocalesFolder) {
   FilePath install_dir;
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
   install_dir = install_dir.AppendASCII("extensions")
@@ -134,7 +146,7 @@
 #define CheckIllegalFilenamesNoUnderscores \
     DISABLED_CheckIllegalFilenamesNoUnderscores
 #endif
-TEST(ExtensionFileUtil, CheckIllegalFilenamesNoUnderscores) {
+TEST_F(ExtensionFileUtilTest, CheckIllegalFilenamesNoUnderscores) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -154,7 +166,7 @@
 #define CheckIllegalFilenamesOnlyReserved \
     DISABLED_CheckIllegalFilenamesOnlyReserved
 #endif
-TEST(ExtensionFileUtil, CheckIllegalFilenamesOnlyReserved) {
+TEST_F(ExtensionFileUtilTest, CheckIllegalFilenamesOnlyReserved) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -171,7 +183,7 @@
 #define CheckIllegalFilenamesReservedAndIllegal \
     DISABLED_CheckIllegalFilenamesReservedAndIllegal
 #endif
-TEST(ExtensionFileUtil, CheckIllegalFilenamesReservedAndIllegal) {
+TEST_F(ExtensionFileUtilTest, CheckIllegalFilenamesReservedAndIllegal) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -186,7 +198,8 @@
                                                              &error));
 }
 
-TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnMissingManifest) {
+TEST_F(ExtensionFileUtilTest,
+       LoadExtensionGivesHelpfullErrorOnMissingManifest) {
   FilePath install_dir;
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
   install_dir = install_dir.AppendASCII("extensions")
@@ -203,7 +216,7 @@
   ASSERT_STREQ("Manifest file is missing or unreadable.", error.c_str());
 }
 
-TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnBadManifest) {
+TEST_F(ExtensionFileUtilTest, LoadExtensionGivesHelpfullErrorOnBadManifest) {
   FilePath install_dir;
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
   install_dir = install_dir.AppendASCII("extensions")
@@ -221,7 +234,7 @@
                "Line: 2, column: 16, Syntax error.", error.c_str());
 }
 
-TEST(ExtensionFileUtil, FailLoadingNonUTF8Scripts) {
+TEST_F(ExtensionFileUtilTest, FailLoadingNonUTF8Scripts) {
   FilePath install_dir;
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
   install_dir = install_dir.AppendASCII("extensions")
@@ -236,7 +249,7 @@
                "It isn't UTF-8 encoded.", error.c_str());
 }
 
-TEST(ExtensionFileUtil, ExtensionURLToRelativeFilePath) {
+TEST_F(ExtensionFileUtilTest, ExtensionURLToRelativeFilePath) {
 #define URL_PREFIX "chrome-extension://extension-id/"
   struct TestCase {
     const char* url;
@@ -282,7 +295,7 @@
   }
 }
 
-TEST(ExtensionFileUtil, ExtensionResourceURLToFilePath) {
+TEST_F(ExtensionFileUtilTest, ExtensionResourceURLToFilePath) {
   // Setup filesystem for testing.
   FilePath root_path;
   ASSERT_TRUE(file_util::CreateNewTempDirectory(
@@ -381,7 +394,7 @@
 // http://crbug.com/108279
 #define ValidateThemeUTF8 DISABLED_ValidateThemeUTF8
 #endif
-TEST(ExtensionFileUtil, ValidateThemeUTF8) {
+TEST_F(ExtensionFileUtilTest, ValidateThemeUTF8) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -414,7 +427,7 @@
 #else
 #define MAYBE_BackgroundScriptsMustExist BackgroundScriptsMustExist
 #endif
-TEST(ExtensionFileUtil, MAYBE_BackgroundScriptsMustExist) {
+TEST_F(ExtensionFileUtilTest, MAYBE_BackgroundScriptsMustExist) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -477,7 +490,7 @@
     "g==\n"
     "-----END PRIVATE KEY-----\n";
 
-TEST(ExtensionFileUtil, FindPrivateKeyFiles) {
+TEST_F(ExtensionFileUtilTest, FindPrivateKeyFiles) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -503,7 +516,7 @@
               testing::Contains(src_path.AppendASCII("second_key.pem")));
 }
 
-TEST(ExtensionFileUtil, WarnOnPrivateKey) {
+TEST_F(ExtensionFileUtilTest, WarnOnPrivateKey) {
   base::ScopedTempDir temp;
   ASSERT_TRUE(temp.CreateUniqueTempDir());
 
@@ -546,7 +559,7 @@
                   "extension includes the key file.*ext_root.a_key.pem"));
 }
 
-TEST(ExtensionFileUtil, CheckZeroLengthImageFile) {
+TEST_F(ExtensionFileUtilTest, CheckZeroLengthImageFile) {
   FilePath install_dir;
   ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
 
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc
index 5e051c5a..800b0e83 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc
@@ -4,11 +4,24 @@
 
 #include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
 
+#include "chrome/common/extensions/api/extension_action/browser_action_handler.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/manifest_handler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace errors = extension_manifest_errors;
+namespace extensions {
 
-TEST_F(ExtensionManifestTest, DisallowMultipleUISurfaces) {
-  LoadAndExpectError("multiple_ui_surfaces.json", errors::kOneUISurfaceOnly);
+class UIManifestTest : public ExtensionManifestTest {
+ protected:
+  virtual void SetUp() OVERRIDE {
+    ManifestHandler::Register(extension_manifest_keys::kBrowserAction,
+                              new BrowserActionHandler);
+  }
+};
+
+TEST_F(UIManifestTest, DisallowMultipleUISurfaces) {
+  LoadAndExpectError("multiple_ui_surfaces.json",
+                     extension_manifest_errors::kOneUISurfaceOnly);
 }
+
+}  // namespace extensions
diff --git a/chrome/renderer/extensions/page_actions_custom_bindings.cc b/chrome/renderer/extensions/page_actions_custom_bindings.cc
index 5f1735e..6bc09c4 100644
--- a/chrome/renderer/extensions/page_actions_custom_bindings.cc
+++ b/chrome/renderer/extensions/page_actions_custom_bindings.cc
@@ -6,6 +6,8 @@
 
 #include <string>
 
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "chrome/common/extensions/extension.h"
 #include "chrome/renderer/extensions/dispatcher.h"
 #include "grit/renderer_resources.h"
 #include "v8/include/v8.h"
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index e372ebf..3d710c5 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -17,8 +17,11 @@
 #include "chrome/common/child_process_logging.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_utility_messages.h"
+#include "chrome/common/extensions/api/extension_action/browser_action_handler.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/manifest_handler.h"
 #include "chrome/common/extensions/unpacker.h"
 #include "chrome/common/extensions/update_manifest.h"
 #include "chrome/common/web_resource/web_resource_unpacker.h"
@@ -42,6 +45,17 @@
 #include "ui/gfx/gdi_util.h"
 #endif  // defined(OS_WIN)
 
+namespace {
+
+// Explicitly register all ManifestHandlers needed in the utility process.
+void RegisterExtensionManifestHandlers() {
+  extensions::ManifestHandler::Register(
+      extension_manifest_keys::kBrowserAction,
+      new extensions::BrowserActionHandler);
+}
+
+}  // namespace
+
 namespace chrome {
 
 ChromeContentUtilityClient::ChromeContentUtilityClient() {
@@ -116,6 +130,7 @@
     int creation_flags) {
   CHECK(location > extensions::Extension::INVALID);
   CHECK(location < extensions::Extension::NUM_LOCATIONS);
+  RegisterExtensionManifestHandlers();
   extensions::Unpacker unpacker(
       extension_path,
       extension_id,