Move permission warning message handling from PermissionSet to PermissionMessageProvider.

This refactors PermissionSet to be closer to just a set of permissions and moves the understanding of permission message strings to a utility class.

BUG=162530

Review URL: https://codereview.chromium.org/27446002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@229565 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc
index 9fc65368..cf23aa049 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -14,6 +14,7 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/permissions/permission_message_provider.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/url_pattern_set.h"
 #include "url/gurl.h"
@@ -205,8 +206,9 @@
   // We don't need to show the prompt if there are no new warnings, or if
   // we're skipping the confirmation UI. All extension types but INTERNAL
   // are allowed to silently increase their permission level.
-  bool has_no_warnings = requested_permissions_->GetWarningMessages(
-      GetExtension()->GetType()).empty();
+  bool has_no_warnings =
+      PermissionMessageProvider::Get()->GetWarningMessages(
+          requested_permissions_, GetExtension()->GetType()).empty();
   if (auto_confirm_for_tests == PROCEED || has_no_warnings ||
       extension_->location() == Manifest::COMPONENT) {
     InstallUIProceed();
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 2526a535..5b45c47 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -48,6 +48,7 @@
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/user_metrics.h"
 #include "extensions/common/manifest.h"
+#include "extensions/common/permissions/permission_message_provider.h"
 #include "extensions/common/user_script.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -300,9 +301,10 @@
         if (error.empty()) {
           scoped_refptr<const PermissionSet> expected_permissions =
               PermissionsData::GetActivePermissions(dummy_extension.get());
-          valid = !(expected_permissions->HasLessPrivilegesThan(
-              PermissionsData::GetActivePermissions(extension),
-              extension->GetType()));
+          valid = !(PermissionMessageProvider::Get()->IsPrivilegeIncrease(
+                        expected_permissions,
+                        PermissionsData::GetActivePermissions(extension),
+                        extension->GetType()));
         }
       }
     }
diff --git a/chrome/browser/extensions/extension_disabled_ui.cc b/chrome/browser/extensions/extension_disabled_ui.cc
index 42767a1b..0192142 100644
--- a/chrome/browser/extensions/extension_disabled_ui.cc
+++ b/chrome/browser/extensions/extension_disabled_ui.cc
@@ -34,6 +34,7 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_source.h"
+#include "extensions/common/permissions/permission_message_provider.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
@@ -265,8 +266,8 @@
   messages.push_back(l10n_util::GetStringUTF16(
       IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO));
   std::vector<string16> permission_warnings =
-      extension_->GetActivePermissions()->GetWarningMessages(
-          extension_->GetType());
+      extensions::PermissionMessageProvider::Get()->GetWarningMessages(
+          extension_->GetActivePermissions(), extension_->GetType());
   for (size_t i = 0; i < permission_warnings.size(); ++i) {
     messages.push_back(l10n_util::GetStringFUTF16(
         IDS_EXTENSION_PERMISSION_LINE, permission_warnings[i]));
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index ae201f1..66c7ab9 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -36,6 +36,7 @@
 #include "extensions/common/extension_resource.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_message_provider.h"
 #include "extensions/common/url_pattern.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
@@ -801,9 +802,11 @@
     Manifest::Type extension_type = extension_ ?
         extension_->GetType() : Manifest::TYPE_UNKNOWN;
     prompt_.SetPermissions(
-        permissions_->GetWarningMessages(extension_type));
+        extensions::PermissionMessageProvider::Get()->
+            GetWarningMessages(permissions_, extension_type));
     prompt_.SetPermissionsDetails(
-        permissions_->GetWarningMessagesDetails(extension_type));
+        extensions::PermissionMessageProvider::Get()->
+            GetWarningMessagesDetails(permissions_, extension_type));
   }
 
   switch (prompt_.type()) {
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 52df5fe..c560220 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -99,6 +99,7 @@
 #include "extensions/common/error_utils.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_message_provider.h"
 #include "grit/generated_resources.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "sync/api/sync_change.h"
@@ -2214,8 +2215,11 @@
     // that requires the user's approval. This could occur because the browser
     // upgraded and recognized additional privileges, or an extension upgrades
     // to a version that requires additional privileges.
-    is_privilege_increase = granted_permissions->HasLessPrivilegesThan(
-        extension->GetActivePermissions().get(), extension->GetType());
+    is_privilege_increase =
+        extensions::PermissionMessageProvider::Get()->IsPrivilegeIncrease(
+                granted_permissions,
+                extension->GetActivePermissions().get(),
+                extension->GetType());
   }
 
   if (is_extension_installed) {
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index cbd4ec3..05ee3b14 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -251,6 +251,8 @@
         'common/extensions/permissions/chrome_api_permissions.h',
         'common/extensions/permissions/chrome_scheme_hosts.cc',
         'common/extensions/permissions/chrome_scheme_hosts.h',
+        'common/extensions/permissions/chrome_permission_message_provider.cc',
+        'common/extensions/permissions/chrome_permission_message_provider.h',
         'common/extensions/permissions/media_galleries_permission.cc',
         'common/extensions/permissions/media_galleries_permission.h',
         'common/extensions/permissions/media_galleries_permission_data.cc',
diff --git a/chrome/common/extensions/chrome_extensions_client.cc b/chrome/common/extensions/chrome_extensions_client.cc
index fbebb8c..dcc4d5f 100644
--- a/chrome/common/extensions/chrome_extensions_client.cc
+++ b/chrome/common/extensions/chrome_extensions_client.cc
@@ -26,20 +26,25 @@
 ChromeExtensionsClient::~ChromeExtensionsClient() {
 }
 
+void ChromeExtensionsClient::Initialize() {
+  RegisterChromeManifestHandlers();
+}
+
 const PermissionsProvider&
 ChromeExtensionsClient::GetPermissionsProvider() const {
   return chrome_api_permissions_;
 }
 
+const PermissionMessageProvider&
+ChromeExtensionsClient::GetPermissionMessageProvider() const {
+  return permission_message_provider_;
+}
+
 FeatureProvider* ChromeExtensionsClient::GetFeatureProviderByName(
     const std::string& name) const {
   return BaseFeatureProvider::GetByName(name);
 }
 
-void ChromeExtensionsClient::RegisterManifestHandlers() const {
-  RegisterChromeManifestHandlers();
-}
-
 void ChromeExtensionsClient::FilterHostPermissions(
     const URLPatternSet& hosts,
     URLPatternSet* new_hosts,
diff --git a/chrome/common/extensions/chrome_extensions_client.h b/chrome/common/extensions/chrome_extensions_client.h
index 4f14a9c..f832172 100644
--- a/chrome/common/extensions/chrome_extensions_client.h
+++ b/chrome/common/extensions/chrome_extensions_client.h
@@ -9,8 +9,8 @@
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "chrome/common/extensions/permissions/chrome_api_permissions.h"
+#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
 #include "extensions/common/extensions_client.h"
-#include "extensions/common/permissions/permissions_provider.h"
 
 namespace extensions {
 
@@ -21,8 +21,11 @@
   ChromeExtensionsClient();
   virtual ~ChromeExtensionsClient();
 
+  virtual void Initialize() OVERRIDE;
+
   virtual const PermissionsProvider& GetPermissionsProvider() const OVERRIDE;
-  virtual void RegisterManifestHandlers() const OVERRIDE;
+  virtual const PermissionMessageProvider& GetPermissionMessageProvider() const
+      OVERRIDE;
   virtual FeatureProvider* GetFeatureProviderByName(const std::string& name)
       const OVERRIDE;
   virtual void FilterHostPermissions(
@@ -35,6 +38,7 @@
 
  private:
   const ChromeAPIPermissions chrome_api_permissions_;
+  const ChromePermissionMessageProvider permission_message_provider_;
 
   friend struct base::DefaultLazyInstanceTraits<ChromeExtensionsClient>;
 
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.cc b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
new file mode 100644
index 0000000..53f8700
--- /dev/null
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.cc
@@ -0,0 +1,261 @@
+// 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.
+
+#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
+
+#include "base/stl_util.h"
+#include "chrome/common/extensions/permissions/permission_message_util.h"
+#include "chrome/common/extensions/permissions/permission_set.h"
+#include "extensions/common/extensions_client.h"
+#include "extensions/common/permissions/permission_message.h"
+#include "extensions/common/url_pattern_set.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+ChromePermissionMessageProvider::ChromePermissionMessageProvider() {
+}
+
+ChromePermissionMessageProvider::~ChromePermissionMessageProvider() {
+}
+
+// static
+PermissionMessages ChromePermissionMessageProvider::GetPermissionMessages(
+    const PermissionSet* permissions,
+    Manifest::Type extension_type) const {
+  PermissionMessages messages;
+
+  if (permissions->HasEffectiveFullAccess()) {
+    messages.push_back(PermissionMessage(
+        PermissionMessage::kFullAccess,
+        l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
+    return messages;
+  }
+
+  std::set<PermissionMessage> host_msgs =
+      GetHostPermissionMessages(permissions, extension_type);
+  std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages(permissions);
+  messages.insert(messages.end(), host_msgs.begin(), host_msgs.end());
+  messages.insert(messages.end(), api_msgs.begin(), api_msgs.end());
+
+  return messages;
+}
+
+// static
+std::vector<string16> ChromePermissionMessageProvider::GetWarningMessages(
+    const PermissionSet* permissions,
+    Manifest::Type extension_type) const {
+  std::vector<string16> message_strings;
+  PermissionMessages messages =
+      GetPermissionMessages(permissions, extension_type);
+
+  bool audio_capture = false;
+  bool video_capture = false;
+  for (PermissionMessages::const_iterator i = messages.begin();
+       i != messages.end(); ++i) {
+    switch (i->id()) {
+      case PermissionMessage::kAudioCapture:
+        audio_capture = true;
+        break;
+      case PermissionMessage::kVideoCapture:
+        video_capture = true;
+        break;
+      default:
+        break;
+    }
+  }
+
+  for (PermissionMessages::const_iterator i = messages.begin();
+       i != messages.end(); ++i) {
+    int id = i->id();
+    if (audio_capture && video_capture) {
+      if (id == PermissionMessage::kAudioCapture) {
+        message_strings.push_back(l10n_util::GetStringUTF16(
+            IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE));
+        continue;
+      } else if (id == PermissionMessage::kVideoCapture) {
+        // The combined message will be pushed above.
+        continue;
+      }
+    }
+
+    message_strings.push_back(i->message());
+  }
+
+  return message_strings;
+}
+
+// static
+std::vector<string16>
+ChromePermissionMessageProvider::GetWarningMessagesDetails(
+    const PermissionSet* permissions,
+    Manifest::Type extension_type) const {
+  std::vector<string16> message_strings;
+  PermissionMessages messages =
+      GetPermissionMessages(permissions, extension_type);
+
+  for (PermissionMessages::const_iterator i = messages.begin();
+       i != messages.end(); ++i)
+    message_strings.push_back(i->details());
+
+  return message_strings;
+}
+
+// static
+bool ChromePermissionMessageProvider::IsPrivilegeIncrease(
+    const PermissionSet* old_permissions,
+    const PermissionSet* new_permissions,
+    Manifest::Type extension_type) const {
+  // Things can't get worse than native code access.
+  if (old_permissions->HasEffectiveFullAccess())
+    return false;
+
+  // Otherwise, it's a privilege increase if the new one has full access.
+  if (new_permissions->HasEffectiveFullAccess())
+    return true;
+
+  if (IsHostPrivilegeIncrease(old_permissions, new_permissions, extension_type))
+    return true;
+
+  if (IsAPIPrivilegeIncrease(old_permissions, new_permissions))
+    return true;
+
+  return false;
+}
+
+std::set<PermissionMessage>
+ChromePermissionMessageProvider::GetAPIPermissionMessages(
+    const PermissionSet* permissions) const {
+  std::set<PermissionMessage> messages;
+  for (APIPermissionSet::const_iterator permission_it =
+           permissions->apis().begin();
+       permission_it != permissions->apis().end(); ++permission_it) {
+    if (permission_it->HasMessages()) {
+      PermissionMessages new_messages = permission_it->GetMessages();
+      messages.insert(new_messages.begin(), new_messages.end());
+    }
+  }
+
+  // A special hack: If kFileSystemWriteDirectory would be displayed, hide
+  // kFileSystemDirectory and and kFileSystemWrite as the write directory
+  // message implies the other two.
+  // TODO(sammc): Remove this. See http://crbug.com/284849.
+  std::set<PermissionMessage>::iterator write_directory_message =
+      messages.find(PermissionMessage(
+          PermissionMessage::kFileSystemWriteDirectory, string16()));
+  if (write_directory_message != messages.end()) {
+    messages.erase(
+        PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
+    messages.erase(
+        PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
+  }
+
+  // A special hack: The warning message for declarativeWebRequest
+  // permissions speaks about blocking parts of pages, which is a
+  // subset of what the "<all_urls>" access allows. Therefore we
+  // display only the "<all_urls>" warning message if both permissions
+  // are required.
+  if (permissions->HasEffectiveAccessToAllHosts()) {
+    messages.erase(
+        PermissionMessage(
+            PermissionMessage::kDeclarativeWebRequest, string16()));
+  }
+
+  return messages;
+}
+
+std::set<PermissionMessage>
+ChromePermissionMessageProvider::GetHostPermissionMessages(
+    const PermissionSet* permissions,
+    Manifest::Type extension_type) const {
+  std::set<PermissionMessage> messages;
+  // Since platform apps always use isolated storage, they can't (silently)
+  // access user data on other domains, so there's no need to prompt.
+  // Note: this must remain consistent with IsHostPrivilegeIncrease.
+  // See crbug.com/255229.
+  if (extension_type == Manifest::TYPE_PLATFORM_APP)
+    return messages;
+
+  if (permissions->HasEffectiveAccessToAllHosts()) {
+    messages.insert(PermissionMessage(
+        PermissionMessage::kHostsAll,
+        l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
+  } else {
+    URLPatternSet regular_hosts;
+    ExtensionsClient::Get()->FilterHostPermissions(
+        permissions->effective_hosts(), &regular_hosts, &messages);
+
+    std::set<std::string> hosts =
+        permission_message_util::GetDistinctHosts(regular_hosts, true, true);
+    if (!hosts.empty())
+      messages.insert(permission_message_util::CreateFromHostList(hosts));
+  }
+  return messages;
+}
+
+bool ChromePermissionMessageProvider::IsAPIPrivilegeIncrease(
+    const PermissionSet* old_permissions,
+    const PermissionSet* new_permissions) const {
+  if (new_permissions == NULL)
+    return false;
+
+  typedef std::set<PermissionMessage> PermissionMsgSet;
+  PermissionMsgSet old_warnings = GetAPIPermissionMessages(old_permissions);
+  PermissionMsgSet new_warnings = GetAPIPermissionMessages(new_permissions);
+  PermissionMsgSet delta_warnings =
+      base::STLSetDifference<PermissionMsgSet>(new_warnings, old_warnings);
+
+  // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and
+  // kFileSystemWrite.
+  // TODO(sammc): Remove this. See http://crbug.com/284849.
+  if (old_warnings.find(PermissionMessage(
+          PermissionMessage::kFileSystemWriteDirectory, string16())) !=
+      old_warnings.end()) {
+    delta_warnings.erase(
+        PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
+    delta_warnings.erase(
+        PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
+  }
+
+  // We have less privileges if there are additional warnings present.
+  return !delta_warnings.empty();
+}
+
+bool ChromePermissionMessageProvider::IsHostPrivilegeIncrease(
+    const PermissionSet* old_permissions,
+    const PermissionSet* new_permissions,
+    Manifest::Type extension_type) const {
+  // Platform apps host permission changes do not count as privilege increases.
+  // Note: this must remain consistent with GetHostPermissionMessages.
+  if (extension_type == Manifest::TYPE_PLATFORM_APP)
+    return false;
+
+  // If the old permission set can access any host, then it can't be elevated.
+  if (old_permissions->HasEffectiveAccessToAllHosts())
+    return false;
+
+  // Likewise, if the new permission set has full host access, then it must be
+  // a privilege increase.
+  if (new_permissions->HasEffectiveAccessToAllHosts())
+    return true;
+
+  const URLPatternSet& old_list = old_permissions->effective_hosts();
+  const URLPatternSet& new_list = new_permissions->effective_hosts();
+
+  // TODO(jstritar): This is overly conservative with respect to subdomains.
+  // For example, going from *.google.com to www.google.com will be
+  // considered an elevation, even though it is not (http://crbug.com/65337).
+  std::set<std::string> new_hosts_set(
+      permission_message_util::GetDistinctHosts(new_list, false, false));
+  std::set<std::string> old_hosts_set(
+      permission_message_util::GetDistinctHosts(old_list, false, false));
+  std::set<std::string> new_hosts_only =
+      base::STLSetDifference<std::set<std::string> >(new_hosts_set,
+                                                     old_hosts_set);
+
+  return !new_hosts_only.empty();
+}
+
+}  // namespace extensions
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_provider.h b/chrome/common/extensions/permissions/chrome_permission_message_provider.h
new file mode 100644
index 0000000..05125f43
--- /dev/null
+++ b/chrome/common/extensions/permissions/chrome_permission_message_provider.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_PERMISSION_MESSAGE_PROVIDER_H_
+#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_PERMISSION_MESSAGE_PROVIDER_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/strings/string16.h"
+#include "extensions/common/permissions/permission_message_provider.h"
+
+namespace extensions {
+
+class ChromePermissionMessageProvider : public PermissionMessageProvider {
+ public:
+  ChromePermissionMessageProvider();
+  virtual ~ChromePermissionMessageProvider();
+
+  // PermissionMessageProvider implementation.
+  virtual PermissionMessages GetPermissionMessages(
+      const PermissionSet* permissions,
+      Manifest::Type extension_type) const OVERRIDE;
+  virtual std::vector<string16> GetWarningMessages(
+      const PermissionSet* permissions,
+      Manifest::Type extension_type) const OVERRIDE;
+  virtual std::vector<string16> GetWarningMessagesDetails(
+      const PermissionSet* permissions,
+      Manifest::Type extension_type) const OVERRIDE;
+  virtual bool IsPrivilegeIncrease(
+      const PermissionSet* old_permissions,
+      const PermissionSet* new_permissions,
+      Manifest::Type extension_type) const OVERRIDE;
+
+ private:
+  // Gets the permission messages for the API permissions.
+  std::set<PermissionMessage> GetAPIPermissionMessages(
+      const PermissionSet* permissions) const;
+
+  // Gets the permission messages for the host permissions.
+  std::set<PermissionMessage> GetHostPermissionMessages(
+      const PermissionSet* permissions,
+      Manifest::Type extension_type) const;
+
+  // Returns true if |new_permissions| has an elevated API privilege level
+  // compared to |old_permissions|.
+  bool IsAPIPrivilegeIncrease(
+      const PermissionSet* old_permissions,
+      const PermissionSet* new_permissions) const;
+
+  // Returns true if |new_permissions| has more host permissions compared to
+  // |old_permissions|.
+  bool IsHostPrivilegeIncrease(
+      const PermissionSet* old_permissions,
+      const PermissionSet* new_permissions,
+      Manifest::Type extension_type) const;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromePermissionMessageProvider);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_COMMON_EXTENSIONS_PERMISSIONS_CHROME_PERMISSION_MESSAGE_PROVIDER_H_
diff --git a/chrome/common/extensions/permissions/permission_message_util.cc b/chrome/common/extensions/permissions/permission_message_util.cc
index 272ad49..bb43236 100644
--- a/chrome/common/extensions/permissions/permission_message_util.cc
+++ b/chrome/common/extensions/permissions/permission_message_util.cc
@@ -6,11 +6,34 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/common/extensions/permissions/permission_set.h"
+#include "content/public/common/url_constants.h"
 #include "extensions/common/permissions/permission_message.h"
+#include "extensions/common/url_pattern_set.h"
 #include "grit/generated_resources.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using extensions::PermissionMessage;
+using extensions::PermissionSet;
+using extensions::URLPatternSet;
+
+namespace {
+
+// Helper for GetDistinctHosts(): com > net > org > everything else.
+bool RcdBetterThan(const std::string& a, const std::string& b) {
+  if (a == b)
+    return false;
+  if (a == "com")
+    return true;
+  if (a == "net")
+    return b != "com";
+  if (a == "org")
+    return b != "com" && b != "net";
+  return false;
+}
+
+}  // namespace
 
 namespace permission_message_util {
 
@@ -69,4 +92,59 @@
   return PermissionMessage(message_id, message, details);
 }
 
+std::set<std::string> GetDistinctHosts(
+    const URLPatternSet& host_patterns,
+    bool include_rcd,
+    bool exclude_file_scheme) {
+  // Use a vector to preserve order (also faster than a map on small sets).
+  // Each item is a host split into two parts: host without RCDs and
+  // current best RCD.
+  typedef std::vector<std::pair<std::string, std::string> > HostVector;
+  HostVector hosts_best_rcd;
+  for (URLPatternSet::const_iterator i = host_patterns.begin();
+       i != host_patterns.end(); ++i) {
+    if (exclude_file_scheme && i->scheme() == chrome::kFileScheme)
+      continue;
+
+    std::string host = i->host();
+
+    // Add the subdomain wildcard back to the host, if necessary.
+    if (i->match_subdomains())
+      host = "*." + host;
+
+    // If the host has an RCD, split it off so we can detect duplicates.
+    std::string rcd;
+    size_t reg_len = net::registry_controlled_domains::GetRegistryLength(
+        host,
+        net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
+        net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+    if (reg_len && reg_len != std::string::npos) {
+      if (include_rcd)  // else leave rcd empty
+        rcd = host.substr(host.size() - reg_len);
+      host = host.substr(0, host.size() - reg_len);
+    }
+
+    // Check if we've already seen this host.
+    HostVector::iterator it = hosts_best_rcd.begin();
+    for (; it != hosts_best_rcd.end(); ++it) {
+      if (it->first == host)
+        break;
+    }
+    // If this host was found, replace the RCD if this one is better.
+    if (it != hosts_best_rcd.end()) {
+      if (include_rcd && RcdBetterThan(rcd, it->second))
+        it->second = rcd;
+    } else {  // Previously unseen host, append it.
+      hosts_best_rcd.push_back(std::make_pair(host, rcd));
+    }
+  }
+
+  // Build up the final vector by concatenating hosts and RCDs.
+  std::set<std::string> distinct_hosts;
+  for (HostVector::iterator it = hosts_best_rcd.begin();
+       it != hosts_best_rcd.end(); ++it)
+    distinct_hosts.insert(it->first + it->second);
+  return distinct_hosts;
+}
+
 }  // namespace permission_message_util
diff --git a/chrome/common/extensions/permissions/permission_message_util.h b/chrome/common/extensions/permissions/permission_message_util.h
index 1ff5a5a..13b41c19 100644
--- a/chrome/common/extensions/permissions/permission_message_util.h
+++ b/chrome/common/extensions/permissions/permission_message_util.h
@@ -10,6 +10,8 @@
 
 namespace extensions {
 class PermissionMessage;
+class PermissionSet;
+class URLPatternSet;
 }
 
 namespace permission_message_util {
@@ -19,6 +21,11 @@
 extensions::PermissionMessage CreateFromHostList(
     const std::set<std::string>& hosts);
 
+std::set<std::string> GetDistinctHosts(
+    const extensions::URLPatternSet& host_patterns,
+    bool include_rcd,
+    bool exclude_file_scheme);
+
 }  // namespace permission_message_util
 
 #endif  // CHROME_COMMON_EXTENSIONS_PERMISSIONS_PERMISSION_MESSAGE_UTIL_H_
diff --git a/chrome/common/extensions/permissions/permission_set.cc b/chrome/common/extensions/permissions/permission_set.cc
index 103a80c2..9c97014 100644
--- a/chrome/common/extensions/permissions/permission_set.cc
+++ b/chrome/common/extensions/permissions/permission_set.cc
@@ -8,35 +8,15 @@
 #include <iterator>
 #include <string>
 
-#include "base/stl_util.h"
-#include "chrome/common/extensions/permissions/permission_message_util.h"
-#include "content/public/common/url_constants.h"
-#include "extensions/common/extensions_client.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/url_pattern.h"
 #include "extensions/common/url_pattern_set.h"
-#include "grit/generated_resources.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
 
 using extensions::URLPatternSet;
 
 namespace {
 
-// Helper for GetDistinctHosts(): com > net > org > everything else.
-bool RcdBetterThan(const std::string& a, const std::string& b) {
-  if (a == b)
-    return false;
-  if (a == "com")
-    return true;
-  if (a == "net")
-    return b != "com";
-  if (a == "org")
-    return b != "com" && b != "net";
-  return false;
-}
-
 void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
   DCHECK(out);
   for (URLPatternSet::const_iterator i = set.begin(); i != set.end(); ++i) {
@@ -161,79 +141,6 @@
   return apis_str;
 }
 
-PermissionMessages PermissionSet::GetPermissionMessages(
-    Manifest::Type extension_type) const {
-  PermissionMessages messages;
-
-  if (HasEffectiveFullAccess()) {
-    messages.push_back(PermissionMessage(
-        PermissionMessage::kFullAccess,
-        l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
-    return messages;
-  }
-
-  std::set<PermissionMessage> host_msgs =
-      GetHostPermissionMessages(extension_type);
-  std::set<PermissionMessage> api_msgs = GetAPIPermissionMessages();
-  messages.insert(messages.end(), host_msgs.begin(), host_msgs.end());
-  messages.insert(messages.end(), api_msgs.begin(), api_msgs.end());
-
-  return messages;
-}
-
-std::vector<string16> PermissionSet::GetWarningMessages(
-    Manifest::Type extension_type) const {
-  std::vector<string16> messages;
-  PermissionMessages permissions = GetPermissionMessages(extension_type);
-
-  bool audio_capture = false;
-  bool video_capture = false;
-  for (PermissionMessages::const_iterator i = permissions.begin();
-       i != permissions.end(); ++i) {
-    switch (i->id()) {
-      case PermissionMessage::kAudioCapture:
-        audio_capture = true;
-        break;
-      case PermissionMessage::kVideoCapture:
-        video_capture = true;
-        break;
-      default:
-        break;
-    }
-  }
-
-  for (PermissionMessages::const_iterator i = permissions.begin();
-       i != permissions.end(); ++i) {
-    int id = i->id();
-    if (audio_capture && video_capture) {
-      if (id == PermissionMessage::kAudioCapture) {
-        messages.push_back(l10n_util::GetStringUTF16(
-            IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE));
-        continue;
-      } else if (id == PermissionMessage::kVideoCapture) {
-        // The combined message will be pushed above.
-        continue;
-      }
-    }
-
-    messages.push_back(i->message());
-  }
-
-  return messages;
-}
-
-std::vector<string16> PermissionSet::GetWarningMessagesDetails(
-    Manifest::Type extension_type) const {
-  std::vector<string16> messages;
-  PermissionMessages permissions = GetPermissionMessages(extension_type);
-
-  for (PermissionMessages::const_iterator i = permissions.begin();
-       i != permissions.end(); ++i)
-    messages.push_back(i->details());
-
-  return messages;
-}
-
 bool PermissionSet::IsEmpty() const {
   // Not default if any host permissions are present.
   if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
@@ -313,84 +220,8 @@
   return false;
 }
 
-bool PermissionSet::HasLessPrivilegesThan(
-    const PermissionSet* permissions,
-    Manifest::Type extension_type) const {
-  // Things can't get worse than native code access.
-  if (HasEffectiveFullAccess())
-    return false;
-
-  // Otherwise, it's a privilege increase if the new one has full access.
-  if (permissions->HasEffectiveFullAccess())
-    return true;
-
-  if (HasLessHostPrivilegesThan(permissions, extension_type))
-    return true;
-
-  if (HasLessAPIPrivilegesThan(permissions))
-    return true;
-
-  return false;
-}
-
 PermissionSet::~PermissionSet() {}
 
-// static
-std::set<std::string> PermissionSet::GetDistinctHosts(
-    const URLPatternSet& host_patterns,
-    bool include_rcd,
-    bool exclude_file_scheme) {
-  // Use a vector to preserve order (also faster than a map on small sets).
-  // Each item is a host split into two parts: host without RCDs and
-  // current best RCD.
-  typedef std::vector<std::pair<std::string, std::string> > HostVector;
-  HostVector hosts_best_rcd;
-  for (URLPatternSet::const_iterator i = host_patterns.begin();
-       i != host_patterns.end(); ++i) {
-    if (exclude_file_scheme && i->scheme() == chrome::kFileScheme)
-      continue;
-
-    std::string host = i->host();
-
-    // Add the subdomain wildcard back to the host, if necessary.
-    if (i->match_subdomains())
-      host = "*." + host;
-
-    // If the host has an RCD, split it off so we can detect duplicates.
-    std::string rcd;
-    size_t reg_len = net::registry_controlled_domains::GetRegistryLength(
-        host,
-        net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
-        net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
-    if (reg_len && reg_len != std::string::npos) {
-      if (include_rcd)  // else leave rcd empty
-        rcd = host.substr(host.size() - reg_len);
-      host = host.substr(0, host.size() - reg_len);
-    }
-
-    // Check if we've already seen this host.
-    HostVector::iterator it = hosts_best_rcd.begin();
-    for (; it != hosts_best_rcd.end(); ++it) {
-      if (it->first == host)
-        break;
-    }
-    // If this host was found, replace the RCD if this one is better.
-    if (it != hosts_best_rcd.end()) {
-      if (include_rcd && RcdBetterThan(rcd, it->second))
-        it->second = rcd;
-    } else {  // Previously unseen host, append it.
-      hosts_best_rcd.push_back(std::make_pair(host, rcd));
-    }
-  }
-
-  // Build up the final vector by concatenating hosts and RCDs.
-  std::set<std::string> distinct_hosts;
-  for (HostVector::iterator it = hosts_best_rcd.begin();
-       it != hosts_best_rcd.end(); ++it)
-    distinct_hosts.insert(it->first + it->second);
-  return distinct_hosts;
-}
-
 void PermissionSet::InitImplicitPermissions() {
   // The downloads permission implies the internal version as well.
   if (apis_.find(APIPermission::kDownloads) != apis_.end())
@@ -417,127 +248,4 @@
       explicit_hosts(), scriptable_hosts(), &effective_hosts_);
 }
 
-std::set<PermissionMessage> PermissionSet::GetAPIPermissionMessages() const {
-  std::set<PermissionMessage> messages;
-  for (APIPermissionSet::const_iterator permission_it = apis_.begin();
-       permission_it != apis_.end(); ++permission_it) {
-    if (permission_it->HasMessages()) {
-      PermissionMessages new_messages = permission_it->GetMessages();
-      messages.insert(new_messages.begin(), new_messages.end());
-    }
-  }
-
-  // A special hack: If kFileSystemWriteDirectory would be displayed, hide
-  // kFileSystemDirectory and and kFileSystemWrite as the write directory
-  // message implies the other two.
-  // TODO(sammc): Remove this. See http://crbug.com/284849.
-  std::set<PermissionMessage>::iterator write_directory_message =
-      messages.find(PermissionMessage(
-          PermissionMessage::kFileSystemWriteDirectory, string16()));
-  if (write_directory_message != messages.end()) {
-    messages.erase(
-        PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
-    messages.erase(
-        PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
-  }
-
-  // A special hack: The warning message for declarativeWebRequest
-  // permissions speaks about blocking parts of pages, which is a
-  // subset of what the "<all_urls>" access allows. Therefore we
-  // display only the "<all_urls>" warning message if both permissions
-  // are required.
-  if (HasEffectiveAccessToAllHosts()) {
-    messages.erase(
-        PermissionMessage(
-            PermissionMessage::kDeclarativeWebRequest, string16()));
-  }
-
-  return messages;
-}
-
-std::set<PermissionMessage> PermissionSet::GetHostPermissionMessages(
-    Manifest::Type extension_type) const {
-  // Since platform apps always use isolated storage, they can't (silently)
-  // access user data on other domains, so there's no need to prompt.
-  // Note: this must remain consistent with HasLessHostPrivilegesThan.
-  // See crbug.com/255229.
-  std::set<PermissionMessage> messages;
-  if (extension_type == Manifest::TYPE_PLATFORM_APP)
-    return messages;
-
-  if (HasEffectiveAccessToAllHosts()) {
-    messages.insert(PermissionMessage(
-        PermissionMessage::kHostsAll,
-        l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
-  } else {
-    URLPatternSet regular_hosts;
-    ExtensionsClient::Get()->FilterHostPermissions(
-        effective_hosts_, &regular_hosts, &messages);
-
-    std::set<std::string> hosts = GetDistinctHosts(regular_hosts, true, true);
-    if (!hosts.empty())
-      messages.insert(permission_message_util::CreateFromHostList(hosts));
-  }
-  return messages;
-}
-
-bool PermissionSet::HasLessAPIPrivilegesThan(
-    const PermissionSet* permissions) const {
-  if (permissions == NULL)
-    return false;
-
-  typedef std::set<PermissionMessage> PermissionMsgSet;
-  PermissionMsgSet current_warnings = GetAPIPermissionMessages();
-  PermissionMsgSet new_warnings = permissions->GetAPIPermissionMessages();
-  PermissionMsgSet delta_warnings =
-      base::STLSetDifference<PermissionMsgSet>(new_warnings, current_warnings);
-
-  // A special hack: kFileSystemWriteDirectory implies kFileSystemDirectory and
-  // kFileSystemWrite.
-  // TODO(sammc): Remove this. See http://crbug.com/284849.
-  if (current_warnings.find(PermissionMessage(
-          PermissionMessage::kFileSystemWriteDirectory, string16())) !=
-      current_warnings.end()) {
-    delta_warnings.erase(
-        PermissionMessage(PermissionMessage::kFileSystemDirectory, string16()));
-    delta_warnings.erase(
-        PermissionMessage(PermissionMessage::kFileSystemWrite, string16()));
-  }
-
-  // We have less privileges if there are additional warnings present.
-  return !delta_warnings.empty();
-}
-
-bool PermissionSet::HasLessHostPrivilegesThan(
-    const PermissionSet* permissions,
-    Manifest::Type extension_type) const {
-  // Platform apps host permission changes do not count as privilege increases.
-  // Note: this must remain consistent with GetHostPermissionMessages.
-  if (extension_type == Manifest::TYPE_PLATFORM_APP)
-    return false;
-
-  // If this permission set can access any host, then it can't be elevated.
-  if (HasEffectiveAccessToAllHosts())
-    return false;
-
-  // Likewise, if the other permission set has full host access, then it must be
-  // a privilege increase.
-  if (permissions->HasEffectiveAccessToAllHosts())
-    return true;
-
-  const URLPatternSet& old_list = effective_hosts();
-  const URLPatternSet& new_list = permissions->effective_hosts();
-
-  // TODO(jstritar): This is overly conservative with respect to subdomains.
-  // For example, going from *.google.com to www.google.com will be
-  // considered an elevation, even though it is not (http://crbug.com/65337).
-  std::set<std::string> new_hosts_set(GetDistinctHosts(new_list, false, false));
-  std::set<std::string> old_hosts_set(GetDistinctHosts(old_list, false, false));
-  std::set<std::string> new_hosts_only =
-      base::STLSetDifference<std::set<std::string> >(new_hosts_set,
-                                                     old_hosts_set);
-
-  return !new_hosts_only.empty();
-}
-
 }  // namespace extensions
diff --git a/chrome/common/extensions/permissions/permission_set.h b/chrome/common/extensions/permissions/permission_set.h
index 0f78bda..e4cbd43 100644
--- a/chrome/common/extensions/permissions/permission_set.h
+++ b/chrome/common/extensions/permissions/permission_set.h
@@ -17,7 +17,6 @@
 #include "extensions/common/manifest.h"
 #include "extensions/common/permissions/api_permission.h"
 #include "extensions/common/permissions/api_permission_set.h"
-#include "extensions/common/permissions/permission_message.h"
 #include "extensions/common/url_pattern_set.h"
 
 namespace extensions {
@@ -65,20 +64,6 @@
   // Gets the API permissions in this set as a set of strings.
   std::set<std::string> GetAPIsAsStrings() 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;
-
-  // Gets the localized permission messages that represent this set (represented
-  // as strings). The set of permission messages shown varies by extension type.
-  std::vector<string16> GetWarningMessages(Manifest::Type extension_type) const;
-
-  // Gets the localized permission details for messages that represent this set
-  // (represented as strings). The set of permission messages shown varies by
-  // extension type.
-  std::vector<string16> GetWarningMessagesDetails(
-      Manifest::Type extension_type) const;
-
   // Returns true if this is an empty set (e.g., the default permission set).
   bool IsEmpty() const;
 
@@ -115,12 +100,6 @@
   // (e.g. native code).
   bool HasEffectiveFullAccess() const;
 
-  // Returns true if |permissions| has a greater privilege level than this
-  // permission set (e.g., this permission set has less permissions).
-  // Whether certain permissions are considered varies by extension type.
-  bool HasLessPrivilegesThan(const PermissionSet* permissions,
-                             Manifest::Type extension_type) const;
-
   const APIPermissionSet& apis() const { return apis_; }
 
   const URLPatternSet& effective_hosts() const { return effective_hosts_; }
@@ -130,50 +109,19 @@
   const URLPatternSet& scriptable_hosts() const { return scriptable_hosts_; }
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(PermissionsTest, HasLessHostPrivilegesThan);
   FRIEND_TEST_ALL_PREFIXES(PermissionsTest, GetWarningMessages_AudioVideo);
-  FRIEND_TEST_ALL_PREFIXES(PermissionsTest, GetDistinctHosts);
-  FRIEND_TEST_ALL_PREFIXES(PermissionsTest,
-                           GetDistinctHosts_ComIsBestRcd);
-  FRIEND_TEST_ALL_PREFIXES(PermissionsTest,
-                           GetDistinctHosts_NetIs2ndBestRcd);
-  FRIEND_TEST_ALL_PREFIXES(PermissionsTest,
-                           GetDistinctHosts_OrgIs3rdBestRcd);
-  FRIEND_TEST_ALL_PREFIXES(PermissionsTest,
-                           GetDistinctHosts_FirstInListIs4thBestRcd);
   friend class base::RefCountedThreadSafe<PermissionSet>;
 
   ~PermissionSet();
 
   void AddAPIPermission(APIPermission::ID id);
 
-  static std::set<std::string> GetDistinctHosts(
-      const URLPatternSet& host_patterns,
-      bool include_rcd,
-      bool exclude_file_scheme);
-
   // Adds permissions implied independently of other context.
   void InitImplicitPermissions();
 
   // Initializes the effective host permission based on the data in this set.
   void InitEffectiveHosts();
 
-  // Gets the permission messages for the API permissions.
-  std::set<PermissionMessage> GetAPIPermissionMessages() const;
-
-  // Gets the permission messages for the host permissions.
-  std::set<PermissionMessage> GetHostPermissionMessages(
-      Manifest::Type extension_type) const;
-
-  // Returns true if |permissions| has an elevated API privilege level than
-  // this set.
-  bool HasLessAPIPrivilegesThan(const PermissionSet* permissions) const;
-
-  // Returns true if |permissions| has more host permissions compared to this
-  // set.
-  bool HasLessHostPrivilegesThan(const PermissionSet* permissions,
-                                 Manifest::Type extension_type) const;
-
   // The api list is used when deciding if an extension can access certain
   // extension APIs and features.
   APIPermissionSet apis_;
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index ef0610f..175b0f7 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -12,10 +12,13 @@
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_test_util.h"
 #include "chrome/common/extensions/features/feature_channel.h"
+#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
+#include "chrome/common/extensions/permissions/permission_message_util.h"
 #include "chrome/common/extensions/permissions/permission_set.h"
 #include "chrome/common/extensions/permissions/permissions_data.h"
 #include "chrome/common/extensions/permissions/socket_permission.h"
 #include "extensions/common/error_utils.h"
+#include "extensions/common/permissions/permission_message_provider.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -565,7 +568,7 @@
   EXPECT_TRUE(set1->IsEmpty());
 }
 
-TEST(PermissionsTest, HasLessPrivilegesThan) {
+TEST(PermissionsTest, IsPrivilegeIncrease) {
   const struct {
     const char* base_name;
     bool expect_increase;
@@ -621,7 +624,8 @@
     Manifest::Type extension_type = old_extension->GetType();
 
     EXPECT_EQ(kTests[i].expect_increase,
-              old_p->HasLessPrivilegesThan(new_p.get(), extension_type))
+              PermissionMessageProvider::Get()->IsPrivilegeIncrease(
+                  old_p.get(), new_p.get(), extension_type))
         << kTests[i].base_name;
   }
 }
@@ -769,7 +773,8 @@
   scoped_refptr<PermissionSet> permissions(
       new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet()));
   PermissionMessages messages =
-      permissions->GetPermissionMessages(Manifest::TYPE_PLATFORM_APP);
+      PermissionMessageProvider::Get()->GetPermissionMessages(
+          permissions, Manifest::TYPE_PLATFORM_APP);
   ASSERT_EQ(2u, messages.size());
   std::sort(messages.begin(), messages.end());
   std::set<PermissionMessage::ID> ids;
@@ -789,7 +794,8 @@
   scoped_refptr<PermissionSet> permissions(
       new PermissionSet(api_permissions, URLPatternSet(), URLPatternSet()));
   PermissionMessages messages =
-      permissions->GetPermissionMessages(Manifest::TYPE_PLATFORM_APP);
+      PermissionMessageProvider::Get()->GetPermissionMessages(
+          permissions, Manifest::TYPE_PLATFORM_APP);
   ASSERT_EQ(1u, messages.size());
   EXPECT_EQ(PermissionMessage::kFileSystemWriteDirectory, messages[0].id());
 }
@@ -811,18 +817,25 @@
   scoped_refptr<PermissionSet> write_directory_permissions(new PermissionSet(
       write_directory_api_permissions, URLPatternSet(), URLPatternSet()));
 
-  EXPECT_FALSE(write_directory_permissions->HasLessPrivilegesThan(
-      write_permissions, Manifest::TYPE_PLATFORM_APP));
-  EXPECT_FALSE(write_directory_permissions->HasLessPrivilegesThan(
-      directory_permissions, Manifest::TYPE_PLATFORM_APP));
-  EXPECT_TRUE(write_permissions->HasLessPrivilegesThan(
-      directory_permissions, Manifest::TYPE_PLATFORM_APP));
-  EXPECT_TRUE(write_permissions->HasLessPrivilegesThan(
-      write_directory_permissions, Manifest::TYPE_PLATFORM_APP));
-  EXPECT_TRUE(directory_permissions->HasLessPrivilegesThan(
-      write_permissions, Manifest::TYPE_PLATFORM_APP));
-  EXPECT_TRUE(directory_permissions->HasLessPrivilegesThan(
-      write_directory_permissions, Manifest::TYPE_PLATFORM_APP));
+  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(write_directory_permissions,
+                                             write_permissions,
+                                             Manifest::TYPE_PLATFORM_APP));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(write_directory_permissions,
+                                             directory_permissions,
+                                             Manifest::TYPE_PLATFORM_APP));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(write_permissions,
+                                            directory_permissions,
+                                            Manifest::TYPE_PLATFORM_APP));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(write_permissions,
+                                            write_directory_permissions,
+                                            Manifest::TYPE_PLATFORM_APP));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions,
+                                            write_permissions,
+                                            Manifest::TYPE_PLATFORM_APP));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(directory_permissions,
+                                            write_directory_permissions,
+                                            Manifest::TYPE_PLATFORM_APP));
 }
 
 TEST(PermissionsTest, GetWarningMessages_ManyHosts) {
@@ -858,11 +871,12 @@
   // Both audio and video present.
   scoped_refptr<Extension> extension =
       LoadManifest("permissions", "audio-video.json");
+  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
   PermissionSet* set =
       const_cast<PermissionSet*>(
           extension->GetActivePermissions().get());
   std::vector<string16> warnings =
-      set->GetWarningMessages(extension->GetType());
+      provider->GetWarningMessages(set, extension->GetType());
   EXPECT_FALSE(Contains(warnings, "Use your microphone"));
   EXPECT_FALSE(Contains(warnings, "Use your camera"));
   EXPECT_TRUE(Contains(warnings, "Use your microphone and camera"));
@@ -871,7 +885,7 @@
 
   // Just audio present.
   set->apis_.erase(APIPermission::kVideoCapture);
-  warnings = set->GetWarningMessages(extension->GetType());
+  warnings = provider->GetWarningMessages(set, extension->GetType());
   EXPECT_EQ(combined_size, warnings.size());
   EXPECT_EQ(combined_index, IndexOf(warnings, "Use your microphone"));
   EXPECT_FALSE(Contains(warnings, "Use your camera"));
@@ -880,7 +894,7 @@
   // Just video present.
   set->apis_.erase(APIPermission::kAudioCapture);
   set->apis_.insert(APIPermission::kVideoCapture);
-  warnings = set->GetWarningMessages(extension->GetType());
+  warnings = provider->GetWarningMessages(set, extension->GetType());
   EXPECT_EQ(combined_size, warnings.size());
   EXPECT_FALSE(Contains(warnings, "Use your microphone"));
   EXPECT_FALSE(Contains(warnings, "Use your microphone and camera"));
@@ -901,9 +915,10 @@
   // permissions do not cover all hosts.
   scoped_refptr<Extension> extension =
       LoadManifest("permissions", "web_request_com_host_permissions.json");
+  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
   const PermissionSet* set = extension->GetActivePermissions().get();
   std::vector<string16> warnings =
-      set->GetWarningMessages(extension->GetType());
+      provider->GetWarningMessages(set, extension->GetType());
   EXPECT_TRUE(Contains(warnings, "Block parts of web pages"));
   EXPECT_FALSE(Contains(warnings, "Access your data on all websites"));
 
@@ -912,7 +927,7 @@
   extension =
       LoadManifest("permissions", "web_request_all_host_permissions.json");
   set = extension->GetActivePermissions().get();
-  warnings = set->GetWarningMessages(extension->GetType());
+  warnings = provider->GetWarningMessages(set, extension->GetType());
   EXPECT_FALSE(Contains(warnings, "Block parts of web pages"));
   EXPECT_TRUE(Contains(warnings, "Access your data on all websites"));
 }
@@ -1027,7 +1042,8 @@
     explicit_hosts.AddPattern(
         URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 
   {
@@ -1039,7 +1055,8 @@
     explicit_hosts.AddPattern(
         URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 
   {
@@ -1049,7 +1066,8 @@
     explicit_hosts.AddPattern(
         URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path"));
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 
   {
@@ -1059,7 +1077,8 @@
     explicit_hosts.AddPattern(
         URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath"));
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 
   {
@@ -1075,7 +1094,8 @@
     expected.insert("bar.com");
 
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 
   {
@@ -1105,7 +1125,8 @@
     expected.insert("www.foo.xyzzy");
 
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 
   {
@@ -1117,7 +1138,8 @@
     expected.insert("*.google.com");
 
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 
   {
@@ -1139,8 +1161,8 @@
     scoped_refptr<PermissionSet> perm_set(new PermissionSet(
         empty_perms, explicit_hosts, scriptable_hosts));
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(perm_set->effective_hosts(),
-                                              true, true));
+              permission_message_util::GetDistinctHosts(
+                  perm_set->effective_hosts(), true, true));
   }
 
   {
@@ -1154,7 +1176,8 @@
         URLPattern(URLPattern::SCHEME_FILE, "file:///*"));
 
     EXPECT_EQ(expected,
-              PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+              permission_message_util::GetDistinctHosts(
+                  explicit_hosts, true, true));
   }
 }
 
@@ -1176,7 +1199,8 @@
   std::set<std::string> expected;
   expected.insert("www.foo.com");
   EXPECT_EQ(expected,
-            PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+            permission_message_util::GetDistinctHosts(
+                explicit_hosts, true, true));
 }
 
 TEST(PermissionsTest, GetDistinctHosts_NetIs2ndBestRcd) {
@@ -1196,7 +1220,8 @@
   std::set<std::string> expected;
   expected.insert("www.foo.net");
   EXPECT_EQ(expected,
-            PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+            permission_message_util::GetDistinctHosts(
+                explicit_hosts, true, true));
 }
 
 TEST(PermissionsTest, GetDistinctHosts_OrgIs3rdBestRcd) {
@@ -1215,7 +1240,8 @@
   std::set<std::string> expected;
   expected.insert("www.foo.org");
   EXPECT_EQ(expected,
-            PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+            permission_message_util::GetDistinctHosts(
+                explicit_hosts, true, true));
 }
 
 TEST(PermissionsTest, GetDistinctHosts_FirstInListIs4thBestRcd) {
@@ -1233,11 +1259,13 @@
   std::set<std::string> expected;
   expected.insert("www.foo.ca");
   EXPECT_EQ(expected,
-            PermissionSet::GetDistinctHosts(explicit_hosts, true, true));
+            permission_message_util::GetDistinctHosts(
+                explicit_hosts, true, true));
 }
 
-TEST(PermissionsTest, HasLessHostPrivilegesThan) {
-  Manifest::Type extension_type = Manifest::TYPE_EXTENSION;
+TEST(PermissionsTest, IsHostPrivilegeIncrease) {
+  Manifest::Type type = Manifest::TYPE_EXTENSION;
+  const PermissionMessageProvider* provider = PermissionMessageProvider::Get();
   URLPatternSet elist1;
   URLPatternSet elist2;
   URLPatternSet slist1;
@@ -1259,33 +1287,33 @@
   set1 = new PermissionSet(empty_perms, elist1, slist1);
   set2 = new PermissionSet(empty_perms, elist2, slist2);
 
-  EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type));
-  EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
 
   // Test that paths are ignored.
   elist2.ClearPatterns();
   elist2.AddPattern(
       URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*"));
   set2 = new PermissionSet(empty_perms, elist2, slist2);
-  EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type));
-  EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
 
   // Test that RCDs are ignored.
   elist2.ClearPatterns();
   elist2.AddPattern(
       URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*"));
   set2 = new PermissionSet(empty_perms, elist2, slist2);
-  EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type));
-  EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
 
   // Test that subdomain wildcards are handled properly.
   elist2.ClearPatterns();
   elist2.AddPattern(
       URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*"));
   set2 = new PermissionSet(empty_perms, elist2, slist2);
-  EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
   // TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337
-  // EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get()));
+  // EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
 
   // Test that different domains count as different hosts.
   elist2.ClearPatterns();
@@ -1294,21 +1322,21 @@
   elist2.AddPattern(
       URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path"));
   set2 = new PermissionSet(empty_perms, elist2, slist2);
-  EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type));
-  EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
 
   // Test that different subdomains count as different hosts.
   elist2.ClearPatterns();
   elist2.AddPattern(
       URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*"));
   set2 = new PermissionSet(empty_perms, elist2, slist2);
-  EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type));
-  EXPECT_TRUE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(set1, set2, type));
+  EXPECT_TRUE(provider->IsPrivilegeIncrease(set2, set1, type));
 
   // Test that platform apps do not have host permissions increases.
-  extension_type = Manifest::TYPE_PLATFORM_APP;
-  EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get(), extension_type));
-  EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get(), extension_type));
+  type = Manifest::TYPE_PLATFORM_APP;
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set1, set2, type));
+  EXPECT_FALSE(provider->IsPrivilegeIncrease(set2, set1, type));
 }
 
 TEST(PermissionsTest, GetAPIsAsStrings) {
@@ -1400,10 +1428,11 @@
       URLPattern(URLPattern::SCHEME_ALL, "chrome://thumb/"));
   scoped_refptr<PermissionSet> permissions(
       new PermissionSet(APIPermissionSet(), allowed_hosts, URLPatternSet()));
-  permissions->GetPermissionMessages(Manifest::TYPE_EXTENSION);
+  PermissionMessageProvider::Get()->
+      GetPermissionMessages(permissions, Manifest::TYPE_EXTENSION);
 }
 
-TEST(PermissionsTest, HasLessPrivilegesThan_DeclarativeWebRequest) {
+TEST(PermissionsTest, IsPrivilegeIncrease_DeclarativeWebRequest) {
   scoped_refptr<Extension> extension(
       LoadManifest("permissions", "permissions_all_urls.json"));
   scoped_refptr<const PermissionSet> permissions(
@@ -1414,7 +1443,10 @@
   scoped_refptr<const PermissionSet> permissions_dwr(
       extension_dwr->GetActivePermissions());
 
-  EXPECT_FALSE(permissions->HasLessPrivilegesThan(permissions_dwr.get(),
-                                                  extension->GetType()));
+  EXPECT_FALSE(PermissionMessageProvider::Get()->
+                   IsPrivilegeIncrease(permissions.get(),
+                                       permissions_dwr.get(),
+                                       extension->GetType()));
 }
+
 }  // namespace extensions
diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc
index 817259f..f252bd1e 100644
--- a/chrome/common/extensions/permissions/permissions_data.cc
+++ b/chrome/common/extensions/permissions/permissions_data.cc
@@ -23,6 +23,7 @@
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permission_message_provider.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/switches.h"
 #include "extensions/common/url_pattern_set.h"
@@ -422,8 +423,8 @@
   if (ShouldSkipPermissionWarnings(extension)) {
     return PermissionMessages();
   } else {
-    return GetActivePermissions(extension)->GetPermissionMessages(
-        extension->GetType());
+    return PermissionMessageProvider::Get()->GetPermissionMessages(
+        GetActivePermissions(extension), extension->GetType());
   }
 }
 
@@ -434,8 +435,8 @@
   if (ShouldSkipPermissionWarnings(extension)) {
     return std::vector<string16>();
   } else {
-    return GetActivePermissions(extension)->GetWarningMessages(
-        extension->GetType());
+    return PermissionMessageProvider::Get()->GetWarningMessages(
+        GetActivePermissions(extension), extension->GetType());
   }
 }
 
@@ -446,8 +447,8 @@
   if (ShouldSkipPermissionWarnings(extension)) {
     return std::vector<string16>();
   } else {
-    return GetActivePermissions(extension)->GetWarningMessagesDetails(
-        extension->GetType());
+    return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
+        GetActivePermissions(extension), extension->GetType());
   }
 }