Use extension API features instead of kNonPermissionModulesNames.

This migrates the constants in permission_set.cc to _api_features.json.

This includes a slight behavior change. Some modules with manifest keys, like
browserAction, omnibox, and commands, used to be accessible even without the
manifest key present. After this patch, they will be inaccessible. I don't
think that should be an issue in practice, because the modules wouldn't do
anything if there was no manifest key present.

BUG=234790,265006

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@215161 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/declarative/declarative_api.cc b/chrome/browser/extensions/api/declarative/declarative_api.cc
index 4274b20..9f2f5cc 100644
--- a/chrome/browser/extensions/api/declarative/declarative_api.cc
+++ b/chrome/browser/extensions/api/declarative/declarative_api.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/events.h"
+#include "chrome/common/extensions/api/extension_api.h"
 #include "content/public/browser/browser_thread.h"
 
 using extensions::api::events::Rule;
@@ -29,7 +30,11 @@
 bool RulesFunction::HasPermission() {
   std::string event_name;
   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
-  return extension_->HasAPIPermission(event_name);
+  Feature::Availability availability =
+      ExtensionAPI::GetSharedInstance()->IsAvailable(
+          event_name, extension_, Feature::BLESSED_EXTENSION_CONTEXT,
+          source_url());
+  return availability.is_available();
 }
 
 bool RulesFunction::RunImpl() {
diff --git a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
index 5684f63..aa9bf22d 100644
--- a/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_webrequest/webrequest_rules_registry_unittest.cc
@@ -33,11 +33,12 @@
 const char kRuleId4[] = "rule4";
 }  // namespace
 
+using extension_test_util::LoadManifest;
+using extension_test_util::LoadManifestUnchecked;
+
 namespace extensions {
 
 using base::Value;
-using extension_test_util::LoadManifest;
-using extension_test_util::LoadManifestUnchecked;
 using testing::HasSubstr;
 
 namespace helpers = extension_web_request_api_helpers;
diff --git a/chrome/browser/extensions/api/management/management_api_browsertest.cc b/chrome/browser/extensions/api/management/management_api_browsertest.cc
index 9f73188..51663c9 100644
--- a/chrome/browser/extensions/api/management/management_api_browsertest.cc
+++ b/chrome/browser/extensions/api/management/management_api_browsertest.cc
@@ -95,6 +95,16 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
+                       SelfUninstallNoPermissions) {
+  ExtensionTestMessageListener listener1("success", false);
+  ASSERT_TRUE(LoadExtension(
+      test_data_dir_.AppendASCII("management/self_uninstall_helper")));
+  ASSERT_TRUE(LoadExtension(
+      test_data_dir_.AppendASCII("management/self_uninstall_noperm")));
+  ASSERT_TRUE(listener1.WaitUntilSatisfied());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionManagementApiBrowserTest,
                        UninstallWithConfirmDialog) {
   ExtensionService* service = ExtensionSystem::Get(browser()->profile())->
       extension_service();
diff --git a/chrome/browser/extensions/api/management/management_apitest.cc b/chrome/browser/extensions/api/management/management_apitest.cc
index 0203b2f..6e98c56 100644
--- a/chrome/browser/extensions/api/management/management_apitest.cc
+++ b/chrome/browser/extensions/api/management/management_apitest.cc
@@ -108,6 +108,11 @@
   ASSERT_TRUE(RunExtensionSubtest("management/test", "basics.html"));
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, NoPermission) {
+  LoadExtensions();
+  ASSERT_TRUE(RunExtensionSubtest("management/no_permission", "test.html"));
+}
+
 // Disabled: http://crbug.com/174411
 #if defined(OS_WIN)
 #define MAYBE_Uninstall DISABLED_Uninstall
diff --git a/chrome/browser/extensions/api/storage/settings_test_util.cc b/chrome/browser/extensions/api/storage/settings_test_util.cc
index 3d8d110..07b635e 100644
--- a/chrome/browser/extensions/api/storage/settings_test_util.cc
+++ b/chrome/browser/extensions/api/storage/settings_test_util.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/extensions/api/storage/settings_frontend.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/permissions/permissions_data.h"
 
 namespace extensions {
 
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index 3e6a3972..766a106 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/api/extension_api.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
@@ -23,6 +24,8 @@
 
 using content::BrowserThread;
 using content::RenderViewHost;
+using extensions::ExtensionAPI;
+using extensions::Feature;
 
 // static
 void ExtensionFunctionDeleteTraits::Destruct(const ExtensionFunction* x) {
@@ -70,7 +73,10 @@
 }
 
 bool ExtensionFunction::HasPermission() {
-  return extension_->HasAPIPermission(name_);
+  Feature::Availability availability =
+      ExtensionAPI::GetSharedInstance()->IsAvailable(
+          name_, extension_, Feature::BLESSED_EXTENSION_CONTEXT, source_url());
+  return availability.is_available();
 }
 
 void ExtensionFunction::OnQuotaExceeded(const std::string& violation_error) {
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 18f6c81f..e846c00e 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -41,6 +41,7 @@
 using extensions::api::activity_log_private::BlockedChromeActivityDetail;
 using extensions::Extension;
 using extensions::ExtensionAPI;
+using extensions::Feature;
 using content::RenderViewHost;
 
 namespace {
@@ -473,8 +474,8 @@
 // to just the permissions they explicitly request. They should not have access
 // to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally
 // are available without permission.
-// TODO(asargent/kalman) - get rid of this when the features system can express
-// the "non permission" permissions.
+// TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove
+// it altogether).
 bool AllowHostedAppAPICall(const Extension& extension,
                            const GURL& source_url,
                            const std::string& function_name) {
@@ -484,11 +485,11 @@
   if (!extension.web_extent().MatchesURL(source_url))
     return false;
 
-  // We just allow the hosted app's explicit permissions, plus chrome.test.
-  scoped_refptr<const extensions::PermissionSet> permissions =
-      extension.GetActivePermissions();
-  return (permissions->HasAccessToFunction(function_name, false) ||
-          StartsWithASCII(function_name, "test.", true /*case_sensitive*/));
+  Feature::Availability availability =
+      ExtensionAPI::GetSharedInstance()->IsAvailable(
+          function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT,
+          source_url);
+  return availability.is_available();
 }
 
 }  // namespace
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 94d2972..26e0d7a 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -44,6 +44,26 @@
     "channel": "stable",
     "contexts": ["blessed_extension", "unblessed_extension", "content_script"]
   },
+  "app.getDetails": {
+    "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+    "matches": []
+  },
+  "app.getDetailsForFrame": {
+    "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+    "matches": []
+  },
+  "app.getIsInstalled": {
+    "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+    "matches": []
+  },
+  "app.installState": {
+    "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+    "matches": []
+  },
+  "app.runningState": {
+    "contexts": ["blessed_extension", "unblessed_extension", "content_script"],
+    "matches": []
+  },
   "audio": {
     "dependencies": ["permission:audio"],
     "contexts": ["blessed_extension"]
@@ -300,6 +320,16 @@
     "dependencies": ["permission:management"],
     "contexts": ["blessed_extension"]
   },
+  "management.getPermissionWarningsByManifest": {
+    "dependencies": [],
+    "channel": "stable",
+    "extension_types": ["extension", "packaged_app", "platform_app"]
+  },
+  "management.uninstallSelf": {
+    "dependencies": [],
+    "channel": "stable",
+    "extension_types": ["extension", "packaged_app", "platform_app"]
+  },
   "mediaGalleries": {
     "dependencies": ["permission:mediaGalleries"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index 4d0d45f2..360db62 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -309,10 +309,6 @@
                                                 const Extension* extension,
                                                 Feature::Context context,
                                                 const GURL& url) {
-  std::string feature_type;
-  std::string feature_name;
-  SplitDependencyName(full_name, &feature_type, &feature_name);
-
   Feature* feature = GetFeatureDependency(full_name);
   CHECK(feature) << full_name;
 
diff --git a/chrome/common/extensions/api/extension_api_unittest.cc b/chrome/common/extensions/api/extension_api_unittest.cc
index a424674..89d6129 100644
--- a/chrome/common/extensions/api/extension_api_unittest.cc
+++ b/chrome/common/extensions/api/extension_api_unittest.cc
@@ -19,6 +19,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
+#include "chrome/common/extensions/extension_test_util.h"
 #include "chrome/common/extensions/features/api_feature.h"
 #include "chrome/common/extensions/features/base_feature_provider.h"
 #include "chrome/common/extensions/features/simple_feature.h"
@@ -27,6 +28,8 @@
 
 namespace extensions {
 
+using extension_test_util::BuildExtension;
+
 SimpleFeature* CreateAPIFeature() {
   return new APIFeature();
 }
@@ -480,7 +483,7 @@
   scoped_ptr<ExtensionAPI> extension_api(
       ExtensionAPI::CreateWithDefaultConfiguration());
 
-  // "runtime" should not be available in hosted apps.
+  // "runtime" and "tabs" should not be available in hosted apps.
   EXPECT_FALSE(extension_api->IsAvailable("runtime",
                                           extension.get(),
                                           Feature::BLESSED_EXTENSION_CONTEXT,
@@ -497,6 +500,10 @@
                                           extension.get(),
                                           Feature::BLESSED_EXTENSION_CONTEXT,
                                           GURL()).is_available());
+  EXPECT_FALSE(extension_api->IsAvailable("tabs.create",
+                                          extension.get(),
+                                          Feature::BLESSED_EXTENSION_CONTEXT,
+                                          GURL()).is_available());
 }
 
 TEST(ExtensionAPITest, AppAndFriendsAvailability) {
@@ -783,4 +790,83 @@
   EXPECT_EQ("fully.qualified.Type", type);
 }
 
+// Tests API availability with an empty manifest.
+TEST(ExtensionAPITest, NoPermissions) {
+  const struct {
+    const char* permission_name;
+    bool expect_success;
+  } kTests[] = {
+    // Test default module/package permission.
+    { "extension",      true },
+    { "i18n",           true },
+    { "permissions",    true },
+    { "runtime",        true },
+    { "test",           true },
+    // These require manifest keys.
+    { "browserAction",  false },
+    { "pageAction",     false },
+    { "pageActions",    false },
+    // Some negative tests.
+    { "bookmarks",      false },
+    { "cookies",        false },
+    { "history",        false },
+    // Make sure we find the module name after stripping '.'
+    { "runtime.abcd.onStartup",  true },
+    // Test Tabs functions.
+    { "tabs.create",      true },
+    { "tabs.duplicate",   true },
+    { "tabs.onRemoved",   true },
+    { "tabs.remove",      true },
+    { "tabs.update",      true },
+    { "tabs.getSelected", true },
+    { "tabs.onUpdated",   true },
+    // Test some whitelisted functions. These require no permissions.
+    { "app.getDetails",           true },
+    { "app.getDetailsForFrame",   true },
+    { "app.getIsInstalled",       true },
+    { "app.installState",         true },
+    { "app.runningState",         true },
+    { "management.getPermissionWarningsByManifest", true },
+    { "management.uninstallSelf", true },
+    // But other functions in those modules do.
+    { "management.getPermissionWarningsById", false },
+  };
+
+  scoped_ptr<ExtensionAPI> extension_api(
+      ExtensionAPI::CreateWithDefaultConfiguration());
+  scoped_refptr<Extension> extension =
+      BuildExtension(ExtensionBuilder().Pass()).Build();
+
+  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
+    EXPECT_EQ(kTests[i].expect_success,
+              extension_api->IsAvailable(kTests[i].permission_name,
+                                         extension.get(),
+                                         Feature::BLESSED_EXTENSION_CONTEXT,
+                                         GURL()).is_available())
+        << "Permission being tested: " << kTests[i].permission_name;
+  }
+}
+
+// Tests that permissions that require manifest keys are available when those
+// keys are present.
+TEST(ExtensionAPITest, ManifestKeys) {
+  scoped_ptr<ExtensionAPI> extension_api(
+      ExtensionAPI::CreateWithDefaultConfiguration());
+
+  scoped_refptr<Extension> extension =
+      BuildExtension(ExtensionBuilder().Pass())
+      .MergeManifest(DictionaryBuilder().Set("browser_action",
+                                             DictionaryBuilder().Pass()))
+      .Build();
+
+  EXPECT_TRUE(extension_api->IsAvailable("browserAction",
+                                         extension.get(),
+                                         Feature::BLESSED_EXTENSION_CONTEXT,
+                                         GURL()).is_available());
+  EXPECT_FALSE(extension_api->IsAvailable("pageAction",
+                                          extension.get(),
+                                          Feature::BLESSED_EXTENSION_CONTEXT,
+                                          GURL()).is_available());
+}
+
 }  // namespace extensions
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 9c94936..a5f9f2f 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -335,8 +335,8 @@
   return PermissionsData::HasAPIPermission(this, permission);
 }
 
-bool Extension::HasAPIPermission(const std::string& function_name) const {
-  return PermissionsData::HasAPIPermission(this, function_name);
+bool Extension::HasAPIPermission(const std::string& permission_name) const {
+  return PermissionsData::HasAPIPermission(this, permission_name);
 }
 
 scoped_refptr<const PermissionSet> Extension::GetActivePermissions() const {
@@ -480,7 +480,7 @@
 }
 
 bool Extension::force_incognito_enabled() const {
-  return GetActivePermissions()->HasAnyAccessToAPI("proxy");
+  return PermissionsData::HasAPIPermission(this, APIPermission::kProxy);
 }
 
 void Extension::AddWebExtentPattern(const URLPattern& pattern) {
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 7f759a1..f9134d45 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -228,7 +228,7 @@
   // DEPRECATED: These methods have been moved to PermissionsData.
   // TODO(rdevlin.cronin): remove these once all calls have been updated.
   bool HasAPIPermission(APIPermission::ID permission) const;
-  bool HasAPIPermission(const std::string& function_name) const;
+  bool HasAPIPermission(const std::string& permission_name) const;
   scoped_refptr<const PermissionSet> GetActivePermissions() const;
 
   // Whether context menu should be shown for page and browser actions.
diff --git a/chrome/common/extensions/extension_builder.cc b/chrome/common/extensions/extension_builder.cc
index 22739aa..c7786f8b 100644
--- a/chrome/common/extensions/extension_builder.cc
+++ b/chrome/common/extensions/extension_builder.cc
@@ -43,6 +43,11 @@
   return *this;
 }
 
+ExtensionBuilder& ExtensionBuilder::MergeManifest(DictionaryBuilder& builder) {
+  manifest_->MergeDictionary(builder.Build().get());
+  return *this;
+}
+
 ExtensionBuilder& ExtensionBuilder::AddFlags(int init_from_value_flags) {
   flags_ |= init_from_value_flags;
   return *this;
diff --git a/chrome/common/extensions/extension_builder.h b/chrome/common/extensions/extension_builder.h
index aca5b1b..c55eb73 100644
--- a/chrome/common/extensions/extension_builder.h
+++ b/chrome/common/extensions/extension_builder.h
@@ -26,6 +26,10 @@
   // CHECKs that the extension was created successfully.
   scoped_refptr<Extension> Build();
 
+  // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
+  // other functions, e.g. UseBuilder(ExtensionBuilder().Pass())
+  ExtensionBuilder& Pass() { return *this; }
+
   // Defaults to FilePath().
   ExtensionBuilder& SetPath(const base::FilePath& path);
 
@@ -37,6 +41,10 @@
     return SetManifest(manifest_builder.Build());
   }
 
+  // Adds the keys from the DictionaryBuilder to the manifest, with new keys
+  // taking precedence.
+  ExtensionBuilder& MergeManifest(DictionaryBuilder& builder);
+
   ExtensionBuilder& AddFlags(int init_from_value_flags);
 
   // Defaults to the default extension ID created in Extension::Create.
diff --git a/chrome/common/extensions/extension_test_util.cc b/chrome/common/extensions/extension_test_util.cc
index b0e13e3..02e9b22 100644
--- a/chrome/common/extensions/extension_test_util.cc
+++ b/chrome/common/extensions/extension_test_util.cc
@@ -10,12 +10,38 @@
 #include "base/values.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_builder.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::DictionaryBuilder;
 using extensions::Extension;
+using extensions::ExtensionBuilder;
+using extensions::ListBuilder;
 using extensions::Manifest;
 
+namespace extensions {
+namespace extension_test_util {
+
+ExtensionBuilder& BuildExtension(ExtensionBuilder& builder) {
+  return builder
+         .SetManifest(DictionaryBuilder()
+                      .Set("name", "Test extension")
+                      .Set("version", "1.0")
+                      .Set("manifest_version", 2));
+}
+
+ExtensionBuilder& BuildExtensionWithPermissions(ExtensionBuilder& builder,
+                                                ListBuilder& permissions) {
+  return
+      BuildExtension(builder)
+      .MergeManifest(
+           DictionaryBuilder().Set("permissions", permissions));
+}
+
+}  // namespace extension_test_util
+}  // namespace extensions
+
 namespace extension_test_util {
 
 scoped_refptr<Extension> CreateExtensionWithID(std::string id) {
diff --git a/chrome/common/extensions/extension_test_util.h b/chrome/common/extensions/extension_test_util.h
index 12e5104..500bdb7 100644
--- a/chrome/common/extensions/extension_test_util.h
+++ b/chrome/common/extensions/extension_test_util.h
@@ -8,11 +8,22 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
+#include "chrome/common/extensions/extension_builder.h"
 #include "chrome/common/extensions/manifest.h"
 
 namespace extensions {
 class Extension;
-}
+
+// Newer functions go here.
+// TODO(mpcomplete): migrate older functions over.
+namespace extension_test_util {
+
+ExtensionBuilder& BuildExtension(ExtensionBuilder& builder);
+ExtensionBuilder& BuildExtensionWithPermissions(ExtensionBuilder& builder,
+                                                ListBuilder& permissions);
+
+}  // namespace extension_test_util
+}  // namespace extensions
 
 namespace extension_test_util {
 
diff --git a/chrome/common/extensions/features/permission_feature.cc b/chrome/common/extensions/features/permission_feature.cc
index 90e53a8..5beb26f 100644
--- a/chrome/common/extensions/features/permission_feature.cc
+++ b/chrome/common/extensions/features/permission_feature.cc
@@ -27,7 +27,7 @@
   if (!availability.is_available())
     return availability;
 
-  if (extension && !extension->HasAPIPermission(name()))
+  if (extension && !PermissionsData::HasAPIPermission(extension, name()))
     return CreateAvailability(NOT_PRESENT, extension->GetType());
 
   return CreateAvailability(IS_AVAILABLE);
@@ -49,4 +49,4 @@
   return std::string();
 }
 
-}  // namespace
+}  // namespace extensions
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index d965aaa..5f25934 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -87,6 +87,7 @@
     kIdentity,
     kIdentityPrivate,
     kIdle,
+    kInfobars,
     kInput,
     kInputMethodPrivate,
     kLocation,
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index dd9c142..03e2808 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -97,6 +97,7 @@
       IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY,
       PermissionMessage::kBrowsingHistory },
     { APIPermission::kIdle, "idle" },
+    { APIPermission::kInfobars, "infobars" },
     { APIPermission::kInput, "input", APIPermissionInfo::kFlagNone,
       IDS_EXTENSION_PROMPT_WARNING_INPUT,
       PermissionMessage::kInput },
diff --git a/chrome/common/extensions/permissions/permission_set.cc b/chrome/common/extensions/permissions/permission_set.cc
index 39bed89..1ad56469 100644
--- a/chrome/common/extensions/permissions/permission_set.cc
+++ b/chrome/common/extensions/permissions/permission_set.cc
@@ -37,44 +37,6 @@
   return false;
 }
 
-// Names of API modules that can be used without listing it in the
-// permissions section of the manifest.
-const char* kNonPermissionModuleNames[] = {
-  "browserAction",
-  "commands",
-  "devtools",
-  "events",
-  "extension",
-  "i18n",
-  "omnibox",
-  "pageAction",
-  "pageActions",
-  "permissions",
-  "runtime",
-  "scriptBadge",
-  "tabs",
-  "test",
-  "types",
-  "windows"
-};
-const size_t kNumNonPermissionModuleNames =
-    arraysize(kNonPermissionModuleNames);
-
-// Names of functions (within modules requiring permissions) that can be used
-// without asking for the module permission. In other words, functions you can
-// use with no permissions specified.
-const char* kNonPermissionFunctionNames[] = {
-  "app.getDetails",
-  "app.getDetailsForFrame",
-  "app.getIsInstalled",
-  "app.installState",
-  "app.runningState",
-  "management.getPermissionWarningsByManifest",
-  "management.uninstallSelf",
-};
-const size_t kNumNonPermissionFunctionNames =
-    arraysize(kNonPermissionFunctionNames);
-
 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
   DCHECK(out);
   for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
@@ -84,19 +46,6 @@
   }
 }
 
-// Strips out the API name from a function or event name.
-// Functions will be of the form api_name.function
-// Events will be of the form api_name/id or api_name.optional.stuff
-std::string GetPermissionName(const std::string& function_name) {
-  size_t separator = function_name.find_first_of("./");
-  if (separator != std::string::npos)
-    return function_name.substr(0, separator);
-  else
-    return function_name;
-}
-
-
-
 }  // namespace
 
 namespace extensions {
@@ -229,21 +178,7 @@
   return apis_str;
 }
 
-bool PermissionSet::HasAnyAccessToAPI(
-    const std::string& api_name) const {
-  if (HasAccessToFunction(api_name, true))
-    return true;
-
-  for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) {
-    if (api_name == GetPermissionName(kNonPermissionFunctionNames[i]))
-      return true;
-  }
-
-  return false;
-}
-
-std::set<std::string>
-    PermissionSet::GetDistinctHostsForDisplay() const {
+std::set<std::string> PermissionSet::GetDistinctHostsForDisplay() const {
   URLPatternSet hosts_displayed_as_url;
   // Filters out every URL pattern that matches chrome:// scheme.
   for (URLPatternSet::const_iterator i = effective_hosts_.begin();
@@ -360,6 +295,13 @@
   return apis().find(id) != apis().end();
 }
 
+bool PermissionSet::HasAPIPermission(const std::string& permission_name) const {
+  const APIPermissionInfo* permission =
+      PermissionsInfo::GetInstance()->GetByName(permission_name);
+  CHECK(permission) << permission_name;
+  return (permission && apis_.count(permission->id()));
+}
+
 bool PermissionSet::CheckAPIPermission(APIPermission::ID permission) const {
   return CheckAPIPermissionWithParam(permission, NULL);
 }
@@ -373,45 +315,6 @@
   return iter->Check(param);
 }
 
-bool PermissionSet::HasAccessToFunction(
-    const std::string& function_name, bool allow_implicit) const {
-  // TODO(jstritar): Embed this information in each permission and add a method
-  // like GrantsAccess(function_name) to APIPermission. A "default"
-  // permission can then handle the modules and functions that everyone can
-  // access.
-  if (allow_implicit) {
-    for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) {
-      if (function_name == kNonPermissionFunctionNames[i])
-        return true;
-    }
-  }
-
-  // Search for increasingly smaller substrings of |function_name| to see if we
-  // find a matching permission or non-permission module name. E.g. for
-  // "a.b.c", we'll search on "a.b.c", then "a.b", and finally "a".
-  std::string name = function_name;
-  size_t lastdot;
-  do {
-    const APIPermissionInfo* permission =
-        PermissionsInfo::GetInstance()->GetByName(name);
-    if (permission && apis_.count(permission->id()))
-      return true;
-
-    if (allow_implicit) {
-      for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) {
-        if (name == kNonPermissionModuleNames[i]) {
-          return true;
-        }
-      }
-    }
-    lastdot = name.find_last_of("./");
-    if (lastdot != std::string::npos)
-      name = std::string(name, 0, lastdot);
-  } while (lastdot != std::string::npos);
-
-  return false;
-}
-
 bool PermissionSet::HasExplicitAccessToOrigin(
     const GURL& origin) const {
   return explicit_hosts().MatchesURL(origin);
diff --git a/chrome/common/extensions/permissions/permission_set.h b/chrome/common/extensions/permissions/permission_set.h
index 9d669da..10e4d86 100644
--- a/chrome/common/extensions/permissions/permission_set.h
+++ b/chrome/common/extensions/permissions/permission_set.h
@@ -70,12 +70,6 @@
   // Gets the API permissions in this set as a set of strings.
   std::set<std::string> GetAPIsAsStrings() const;
 
-  // Returns whether this namespace has any functions which the extension has
-  // permission to use.  For example, even though the extension may not have
-  // the "tabs" permission, "tabs.create" requires no permissions so
-  // HasAnyAccessToAPI("tabs") will return true.
-  bool HasAnyAccessToAPI(const std::string& api_name) const;
-
   // Gets the localized permission messages that represent this set.
   // The set of permission messages shown varies by extension type.
   PermissionMessages GetPermissionMessages(Manifest::Type extension_type) const;
@@ -96,6 +90,11 @@
   // Returns true if the set has the specified API permission.
   bool HasAPIPermission(APIPermission::ID permission) const;
 
+  // Returns true if the |extension| explicitly requests access to the given
+  // |permission_name|. Note this does not include APIs without no corresponding
+  // permission, like "runtime" or "browserAction".
+  bool HasAPIPermission(const std::string& permission_name) const;
+
   // Returns true if the set allows the given permission with the default
   // permission detal.
   bool CheckAPIPermission(APIPermission::ID permission) const;
@@ -104,13 +103,6 @@
   bool CheckAPIPermissionWithParam(APIPermission::ID permission,
       const APIPermission::CheckParam* param) const;
 
-  // Returns true if the permissions in this set grant access to the specified
-  // |function_name|. The |allow_implicit| flag controls whether we
-  // want to strictly check against just the explicit permissions, or also
-  // include implicit "no permission needed" namespaces/functions.
-  bool HasAccessToFunction(const std::string& function_name,
-                           bool allow_implicit) const;
-
   // Returns true if this includes permission to access |origin|.
   bool HasExplicitAccessToOrigin(const GURL& origin) const;
 
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 3076507b..8d5d7958 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -710,6 +710,7 @@
   skip.insert(APIPermission::kFileBrowserHandlerInternal);
   skip.insert(APIPermission::kFileBrowserPrivate);
   skip.insert(APIPermission::kIdentityPrivate);
+  skip.insert(APIPermission::kInfobars);
   skip.insert(APIPermission::kInputMethodPrivate);
   skip.insert(APIPermission::kMediaGalleriesPrivate);
   skip.insert(APIPermission::kMediaPlayerPrivate);
@@ -759,77 +760,6 @@
   }
 }
 
-// Tests the default permissions (empty API permission set).
-TEST(PermissionsTest, DefaultFunctionAccess) {
-  const struct {
-    const char* permission_name;
-    bool expect_success;
-  } kTests[] = {
-    // Negative test.
-    { "non_existing_permission", false },
-    // Test default module/package permission.
-    { "browserAction",  true },
-    { "devtools",       true },
-    { "extension",      true },
-    { "i18n",           true },
-    { "pageAction",     true },
-    { "pageActions",    true },
-    { "test",           true },
-    // Some negative tests.
-    { "bookmarks",      false },
-    { "cookies",        false },
-    { "history",        false },
-    // Make sure we find the module name after stripping '.' and '/'.
-    { "browserAction/abcd/onClick",  true },
-    { "browserAction.abcd.onClick",  true },
-    // Test Tabs functions.
-    { "tabs.create",      true},
-    { "tabs.duplicate",   true},
-    { "tabs.update",      true},
-    { "tabs.getSelected", true},
-    { "tabs.onUpdated",   true },
-  };
-
-  scoped_refptr<PermissionSet> empty = new PermissionSet();
-  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
-    EXPECT_EQ(kTests[i].expect_success,
-              empty->HasAccessToFunction(kTests[i].permission_name, true))
-                  << "Permission being tested: " << kTests[i].permission_name;
-  }
-}
-
-// Tests the default permissions (empty API permission set).
-TEST(PermissionsTest, DefaultAnyAPIAccess) {
-  const struct {
-    const char* api_name;
-    bool expect_success;
-  } kTests[] = {
-    // Negative test.
-    { "non_existing_permission", false },
-    // Test default module/package permission.
-    { "browserAction",  true },
-    { "devtools",       true },
-    { "extension",      true },
-    { "i18n",           true },
-    { "pageAction",     true },
-    { "pageActions",    true },
-    { "test",           true },
-    // Some negative tests.
-    { "bookmarks",      false },
-    { "cookies",        false },
-    { "history",        false },
-    // Negative APIs that have positive individual functions.
-    { "management",     true},
-    { "tabs",           true},
-  };
-
-  scoped_refptr<PermissionSet> empty = new PermissionSet();
-  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
-    EXPECT_EQ(kTests[i].expect_success,
-              empty->HasAnyAccessToAPI(kTests[i].api_name));
-  }
-}
-
 TEST(PermissionsTest, GetWarningMessages_ManyHosts) {
   scoped_refptr<Extension> extension;
 
diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc
index 6330620..8b5796eb 100644
--- a/chrome/common/extensions/permissions/permissions_data.cc
+++ b/chrome/common/extensions/permissions/permissions_data.cc
@@ -356,11 +356,11 @@
 }
 
 // static
-bool PermissionsData::HasAPIPermission(const Extension* extension,
-                                       const std::string& function_name) {
+bool PermissionsData::HasAPIPermission(
+    const Extension* extension,
+    const std::string& permission_name) {
   base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
-  return GetActivePermissions(extension)->HasAccessToFunction(
-      function_name, true);  // include implicit
+  return GetActivePermissions(extension)->HasAPIPermission(permission_name);
 }
 
 // static
diff --git a/chrome/common/extensions/permissions/permissions_data.h b/chrome/common/extensions/permissions/permissions_data.h
index 57f6555..18e3787 100644
--- a/chrome/common/extensions/permissions/permissions_data.h
+++ b/chrome/common/extensions/permissions/permissions_data.h
@@ -93,10 +93,13 @@
   // Returns true if the |extension| has the given |permission|. Prefer
   // IsExtensionWithPermissionOrSuggestInConsole when developers may be using an
   // api that requires a permission they didn't know about, e.g. open web apis.
+  // Note this does not include APIs with no corresponding permission, like
+  // "runtime" or "browserAction".
+  // TODO(mpcomplete): drop the "API" from these names, it's confusing.
   static bool HasAPIPermission(const Extension* extension,
                                APIPermission::ID permission);
   static bool HasAPIPermission(const Extension* extension,
-                               const std::string& function_name);
+                               const std::string& permission_name);
   static bool HasAPIPermissionForTab(const Extension* extension,
                                      int tab_id,
                                      APIPermission::ID permission);
diff --git a/chrome/common/extensions/permissions/permissions_data_unittest.cc b/chrome/common/extensions/permissions/permissions_data_unittest.cc
index b689006..a4d1cda 100644
--- a/chrome/common/extensions/permissions/permissions_data_unittest.cc
+++ b/chrome/common/extensions/permissions/permissions_data_unittest.cc
@@ -151,53 +151,6 @@
         "239.255.255.250", 1900));
 }
 
-// This tests the API permissions with an empty manifest (one that just
-// specifies a name and a version and nothing else).
-TEST(ExtensionPermissionsTest, ApiPermissions) {
-  const struct {
-    const char* permission_name;
-    bool expect_success;
-  } kTests[] = {
-    // Negative test.
-    { "non_existing_permission", false },
-    // Test default module/package permission.
-    { "browserAction",  true },
-    { "devtools",       true },
-    { "extension",      true },
-    { "i18n",           true },
-    { "pageAction",     true },
-    { "pageActions",    true },
-    { "test",           true },
-    // Some negative tests.
-    { "bookmarks",      false },
-    { "cookies",        false },
-    { "history",        false },
-    // Make sure we find the module name after stripping '.' and '/'.
-    { "browserAction/abcd/onClick",  true },
-    { "browserAction.abcd.onClick",  true },
-    // Test Tabs functions.
-    { "tabs.create",      true},
-    { "tabs.duplicate",   true},
-    { "tabs.onRemoved",   true},
-    { "tabs.remove",      true},
-    { "tabs.update",      true},
-    { "tabs.getSelected", true},
-    { "tabs.onUpdated",   true },
-    // Test getPermissionWarnings functions. Only one requires permissions.
-    { "management.getPermissionWarningsById", false },
-    { "management.getPermissionWarningsByManifest", true },
-  };
-
-  scoped_refptr<Extension> extension;
-  extension = LoadManifest("empty_manifest", "empty.json");
-
-  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
-    EXPECT_EQ(kTests[i].expect_success,
-              extension->HasAPIPermission(kTests[i].permission_name))
-                  << "Permission being tested: " << kTests[i].permission_name;
-  }
-}
-
 TEST(ExtensionPermissionsTest, GetPermissionMessages_ManyAPIPermissions) {
   scoped_refptr<Extension> extension;
   extension = LoadManifest("permissions", "many-apis.json");
diff --git a/chrome/common/extensions/value_builder.h b/chrome/common/extensions/value_builder.h
index 48e9133..db272c5 100644
--- a/chrome/common/extensions/value_builder.h
+++ b/chrome/common/extensions/value_builder.h
@@ -20,8 +20,8 @@
 //                         .Append("foo").Append("bar") /* No .Build() */);
 //
 // Because of limitations in C++03, and to avoid extra copies, you can't pass a
-// just-constructed Builder into another Builder's method without setting at
-// least 1 field.
+// just-constructed Builder into another Builder's method directly. Use the
+// Pass() method.
 //
 // The Build() method invalidates its builder, and returns ownership of the
 // built value.
@@ -49,6 +49,10 @@
   explicit DictionaryBuilder(const base::DictionaryValue& init);
   ~DictionaryBuilder();
 
+  // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
+  // other functions.
+  DictionaryBuilder& Pass() { return *this; }
+
   // Can only be called once, after which it's invalid to use the builder.
   scoped_ptr<base::DictionaryValue> Build() { return dict_.Pass(); }
 
@@ -73,6 +77,10 @@
   explicit ListBuilder(const base::ListValue& init);
   ~ListBuilder();
 
+  // Workaround to allow you to pass rvalue ExtensionBuilders by reference to
+  // other functions.
+  ListBuilder& Pass() { return *this; }
+
   // Can only be called once, after which it's invalid to use the builder.
   scoped_ptr<base::ListValue> Build() { return list_.Pass(); }
 
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js b/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js
index 2a2524d..8c29e62b 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js
+++ b/chrome/test/data/extensions/api_test/activity_log_private/friend/reply.js
@@ -58,11 +58,11 @@
 }
 
 // Makes an API call that the extension doesn't have permission for.
-// Don't add the management permission or this test won't test the code path.
+// Don't add the bookmarks permission or this test won't test the code path.
 function makeBlockedApiCall() {
   resetStatus();
   try {
-    var allExtensions = chrome.management.getAll();
+    var allExtensions = chrome.bookmarks.getTree();
   } catch (err) { }
   appendCompleted('makeBlockedApiCall');
 }
diff --git a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
index cf7af969..7a552b04 100644
--- a/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
+++ b/chrome/test/data/extensions/api_test/activity_log_private/test/test.js
@@ -45,9 +45,9 @@
                                'blocked_call', function response() { });
    },
    // Blocked api calls only log the api module name and not the
-   // function, so this is intentionally 'management' rather than
-   // 'management.getAll'.
-   expected_activity: ['management']
+   // function, so this is intentionally 'bookmarks' rather than
+   // 'bookmarks.getTree'.
+   expected_activity: ['bookmarks']
 });
 testCases.push({
   func: function triggerObjectMethods() {
diff --git a/chrome/test/data/extensions/api_test/management/no_permission/manifest.json b/chrome/test/data/extensions/api_test/management/no_permission/manifest.json
new file mode 100644
index 0000000..5ce966a
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/no_permission/manifest.json
@@ -0,0 +1,5 @@
+{
+  "name": "Test that permissionless management APIs work without permission",
+  "version": "0.1",
+  "manifest_version": 2
+}
diff --git a/chrome/test/data/extensions/api_test/management/no_permission/test.html b/chrome/test/data/extensions/api_test/management/no_permission/test.html
new file mode 100644
index 0000000..5000771
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/no_permission/test.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright (c) 2013 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.
+-->
+<script src="test.js"></script>
diff --git a/chrome/test/data/extensions/api_test/management/no_permission/test.js b/chrome/test/data/extensions/api_test/management/no_permission/test.js
new file mode 100644
index 0000000..07e1e07
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/no_permission/test.js
@@ -0,0 +1,18 @@
+// Copyright 2013 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.
+
+var tests = [
+  function permissionWarnings() {
+    var manifest_str = "{ \"name\": \"Location!\", \"version\": \"1.0\", " +
+                       "\"permissions\": [\"location\"] }";
+
+    chrome.management.getPermissionWarningsByManifest(
+        manifest_str, chrome.test.callback(function(warnings) {
+      chrome.test.assertEq(1, warnings.length);
+      chrome.test.assertEq("Detect your physical location", warnings[0]);
+    }));
+  },
+];
+
+chrome.test.runTests(tests);
diff --git a/chrome/test/data/extensions/management/self_uninstall_noperm/background.js b/chrome/test/data/extensions/management/self_uninstall_noperm/background.js
new file mode 100644
index 0000000..e13b844f
--- /dev/null
+++ b/chrome/test/data/extensions/management/self_uninstall_noperm/background.js
@@ -0,0 +1,9 @@
+// Copyright 2013 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.
+
+// Wait for the API test framework to decide we're done loading before
+// uninstalling, or it'll wait forever.
+chrome.runtime.onInstalled.addListener(function() {
+  chrome.management.uninstallSelf();
+});
diff --git a/chrome/test/data/extensions/management/self_uninstall_noperm/manifest.json b/chrome/test/data/extensions/management/self_uninstall_noperm/manifest.json
new file mode 100644
index 0000000..90c7d23
--- /dev/null
+++ b/chrome/test/data/extensions/management/self_uninstall_noperm/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "Self Uninstall Test (no permissions)",
+  "version": "0.1",
+  "manifest_version": 2,
+  "background": {
+    "scripts": ["background.js"]
+  }
+}
+