Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / installed_loader.cc
index e92d36d..49fc527 100644 (file)
@@ -6,33 +6,39 @@
 
 #include "base/files/file_path.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/api/runtime/runtime_api.h"
 #include "chrome/browser/extensions/extension_action_manager.h"
-#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/management_policy.h"
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/api/managed_mode_private/managed_mode_handler.h"
-#include "chrome/common/extensions/background_info.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/extensions/api/supervised_user_private/supervised_user_handler.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/manifest_url_handler.h"
 #include "chrome/common/pref_names.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/management_policy.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_l10n_util.h"
+#include "extensions/common/extension_set.h"
+#include "extensions/common/file_util.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/background_info.h"
 
+using base::UserMetricsAction;
 using content::BrowserThread;
-using content::UserMetricsAction;
 
 namespace extensions {
 
@@ -41,39 +47,43 @@ namespace errors = manifest_errors;
 namespace {
 
 // The following enumeration is used in histograms matching
-// Extensions.ManifestReload* .  Values may be added, as long as existing
-// values are not changed.
+// Extensions.ManifestReload*.
 enum ManifestReloadReason {
-  NOT_NEEDED = 0,  // Reload not needed.
-  UNPACKED_DIR,  // Unpacked directory.
+  NOT_NEEDED = 0,        // Reload not needed.
+  UNPACKED_DIR,          // Unpacked directory.
   NEEDS_RELOCALIZATION,  // The locale has changed since we read this extension.
-  CORRUPT_PREFERENCES,  // The manifest in the preferences is corrupt.
+  CORRUPT_PREFERENCES,   // The manifest in the preferences is corrupt.
+
+  // New enum values must go above here.
   NUM_MANIFEST_RELOAD_REASONS
 };
 
-// Used in histogram Extension.BackgroundPageType. Values may be added, as
-// long as existing values are not changed.
+// Used in histogram Extension.BackgroundPageType.
 enum BackgroundPageType {
   NO_BACKGROUND_PAGE = 0,
-  BACKGROUND_PAGE_PERSISTENT = 1,
-  EVENT_PAGE = 2,
+  BACKGROUND_PAGE_PERSISTENT,
+  EVENT_PAGE,
+
+  // New enum values must go above here.
+  NUM_BACKGROUND_PAGE_TYPES
 };
 
-// Used in histogram Extensions.ExternalItemState. Values may be added, as
-// long as existing values are not changed.
+// Used in histogram Extensions.ExternalItemState.
 enum ExternalItemState {
   DEPRECATED_EXTERNAL_ITEM_DISABLED = 0,
-  DEPRECATED_EXTERNAL_ITEM_ENABLED = 1,
-  EXTERNAL_ITEM_WEBSTORE_DISABLED = 2,
-  EXTERNAL_ITEM_WEBSTORE_ENABLED = 3,
-  EXTERNAL_ITEM_NONWEBSTORE_DISABLED = 4,
-  EXTERNAL_ITEM_NONWEBSTORE_ENABLED = 5,
-  EXTERNAL_ITEM_WEBSTORE_UNINSTALLED = 6,
-  EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED = 7,
-  EXTERNAL_ITEM_MAX_ITEMS = 8
+  DEPRECATED_EXTERNAL_ITEM_ENABLED,
+  EXTERNAL_ITEM_WEBSTORE_DISABLED,
+  EXTERNAL_ITEM_WEBSTORE_ENABLED,
+  EXTERNAL_ITEM_NONWEBSTORE_DISABLED,
+  EXTERNAL_ITEM_NONWEBSTORE_ENABLED,
+  EXTERNAL_ITEM_WEBSTORE_UNINSTALLED,
+  EXTERNAL_ITEM_NONWEBSTORE_UNINSTALLED,
+
+  // New enum values must go above here.
+  EXTERNAL_ITEM_MAX_ITEMS
 };
 
-bool IsManifestCorrupt(const DictionaryValue* manifest) {
+bool IsManifestCorrupt(const base::DictionaryValue* manifest) {
   if (!manifest)
     return false;
 
@@ -81,8 +91,8 @@ bool IsManifestCorrupt(const DictionaryValue* manifest) {
   // file, one particularly bad case resulting in having both a background page
   // and background scripts values. In those situations we want to reload the
   // manifest from the extension to fix this.
-  const Value* background_page;
-  const Value* background_scripts;
+  const base::Value* background_page;
+  const base::Value* background_scripts;
   return manifest->Get(manifest_keys::kBackgroundPage, &background_page) &&
       manifest->Get(manifest_keys::kBackgroundScripts, &background_scripts);
 }
@@ -113,27 +123,45 @@ BackgroundPageType GetBackgroundPageType(const Extension* extension) {
   return EVENT_PAGE;
 }
 
-void DispatchOnInstalledEvent(
-    Profile* profile,
-    const std::string& extension_id,
-    const Version& old_version,
-    bool chrome_updated) {
-  // profile manager can be NULL in unit tests.
-  if (!g_browser_process->profile_manager())
-    return;
-  if (!g_browser_process->profile_manager()->IsValidProfile(profile))
-    return;
+// Records the creation flags of an extension grouped by
+// Extension::InitFromValueFlags.
+void RecordCreationFlags(const Extension* extension) {
+  for (int i = 0; i < Extension::kInitFromValueFlagBits; ++i) {
+    int flag = 1 << i;
+    if (extension->creation_flags() & flag) {
+      UMA_HISTOGRAM_ENUMERATION(
+          "Extensions.LoadCreationFlags", i, Extension::kInitFromValueFlagBits);
+    }
+  }
+}
 
-  extensions::RuntimeEventRouter::DispatchOnInstalledEvent(
-      profile, extension_id, old_version, chrome_updated);
+// Helper to record a single disable reason histogram value (see
+// RecordDisableReasons below).
+void RecordDisbleReasonHistogram(int reason) {
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.DisableReason", reason);
+}
+
+// Records the disable reasons for a single extension grouped by
+// Extension::DisableReason.
+void RecordDisableReasons(int reasons) {
+  // |reasons| is a bitmask with values from Extension::DisabledReason
+  // which are increasing powers of 2.
+  if (reasons == Extension::DISABLE_NONE) {
+    RecordDisbleReasonHistogram(Extension::DISABLE_NONE);
+    return;
+  }
+  for (int reason = 1; reason < Extension::DISABLE_REASON_LAST; reason <<= 1) {
+    if (reasons & reason)
+      RecordDisbleReasonHistogram(reason);
+  }
 }
 
 }  // namespace
 
 InstalledLoader::InstalledLoader(ExtensionService* extension_service)
     : extension_service_(extension_service),
-      extension_prefs_(extension_service->extension_prefs()) {
-}
+      extension_registry_(ExtensionRegistry::Get(extension_service->profile())),
+      extension_prefs_(ExtensionPrefs::Get(extension_service->profile())) {}
 
 InstalledLoader::~InstalledLoader() {
 }
@@ -159,7 +187,6 @@ void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
       info.extension_id != extension->id()) {
     error = errors::kCannotChangeExtensionID;
     extension = NULL;
-    content::RecordAction(UserMetricsAction("Extensions.IDChangedError"));
   }
 
   // Check policy on every load in case an extension was blacklisted while
@@ -168,6 +195,7 @@ void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
       extension_service_->profile())->management_policy();
   if (extension.get()) {
     Extension::DisableReason disable_reason = Extension::DISABLE_NONE;
+    bool force_disabled = false;
     if (!policy->UserMayLoad(extension.get(), NULL)) {
       // The error message from UserMayInstall() often contains the extension ID
       // and is therefore not well suited to this UI.
@@ -177,12 +205,18 @@ void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
                policy->MustRemainDisabled(extension, &disable_reason, NULL)) {
       extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
       extension_prefs_->AddDisableReason(extension->id(), disable_reason);
+      force_disabled = true;
     }
+    UMA_HISTOGRAM_BOOLEAN("ExtensionInstalledLoader.ForceDisabled",
+                          force_disabled);
   }
 
   if (!extension.get()) {
-    extension_service_->ReportExtensionLoadError(
-        info.extension_path, error, false);
+    ExtensionErrorReporter::GetInstance()->ReportLoadError(
+        info.extension_path,
+        error,
+        extension_service_->profile(),
+        false);  // Be quiet.
     return;
   }
 
@@ -197,6 +231,7 @@ void InstalledLoader::LoadAllExtensions() {
 
   base::TimeTicks start_time = base::TimeTicks::Now();
 
+  Profile* profile = extension_service_->profile();
   scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
       extension_prefs_->GetInstalledExtensionsInfo());
 
@@ -213,8 +248,6 @@ void InstalledLoader::LoadAllExtensions() {
 
     ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
     ++reload_reason_counts[reload_reason];
-    UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
-                              reload_reason, 100);
 
     if (reload_reason != NOT_NEEDED) {
       // Reloading an extension reads files from disk.  We do this on the
@@ -227,29 +260,30 @@ void InstalledLoader::LoadAllExtensions() {
 
       std::string error;
       scoped_refptr<const Extension> extension(
-          extension_file_util::LoadExtension(
-              info->extension_path,
-              info->extension_location,
-              GetCreationFlags(info),
-              &error));
+          file_util::LoadExtension(info->extension_path,
+                                   info->extension_location,
+                                   GetCreationFlags(info),
+                                   &error));
 
       if (!extension.get()) {
-        extension_service_->ReportExtensionLoadError(
-            info->extension_path, error, false);
+        ExtensionErrorReporter::GetInstance()->ReportLoadError(
+            info->extension_path,
+            error,
+            profile,
+            false);  // Be quiet.
         continue;
       }
 
       extensions_info->at(i)->extension_manifest.reset(
-          static_cast<DictionaryValue*>(
+          static_cast<base::DictionaryValue*>(
               extension->manifest()->value()->DeepCopy()));
       should_write_prefs = true;
     }
   }
 
   for (size_t i = 0; i < extensions_info->size(); ++i) {
-    if (extensions_info->at(i)->extension_location == Manifest::COMMAND_LINE)
-      continue;
-    Load(*extensions_info->at(i), should_write_prefs);
+    if (extensions_info->at(i)->extension_location != Manifest::COMMAND_LINE)
+      Load(*extensions_info->at(i), should_write_prefs);
   }
 
   extension_service_->OnLoadedInstalledExtensions();
@@ -264,9 +298,9 @@ void InstalledLoader::LoadAllExtensions() {
                            reload_reason_counts[NEEDS_RELOCALIZATION]);
 
   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
-                           extension_service_->extensions()->size());
+                           extension_registry_->enabled_extensions().size());
   UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
-                           extension_service_->disabled_extensions()->size());
+                           extension_registry_->disabled_extensions().size());
 
   UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
                       base::TimeTicks::Now() - start_time);
@@ -284,27 +318,54 @@ void InstalledLoader::LoadAllExtensions() {
   int page_action_count = 0;
   int browser_action_count = 0;
   int disabled_for_permissions_count = 0;
-  int item_user_count = 0;
   int non_webstore_ntp_override_count = 0;
-  const ExtensionSet* extensions = extension_service_->extensions();
-  ExtensionSet::const_iterator ex;
-  for (ex = extensions->begin(); ex != extensions->end(); ++ex) {
-    Manifest::Location location = (*ex)->location();
-    Manifest::Type type = (*ex)->GetType();
-    if ((*ex)->is_app()) {
-      UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
-                                location, 100);
-    } else if (type == Manifest::TYPE_EXTENSION) {
-      UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
-                                location, 100);
-    }
-    if (!ManifestURL::UpdatesFromGallery(*ex)) {
-      UMA_HISTOGRAM_ENUMERATION("Extensions.NonWebstoreLocation",
-                                location, 100);
+  int incognito_allowed_count = 0;
+  int incognito_not_allowed_count = 0;
+  int file_access_allowed_count = 0;
+  int file_access_not_allowed_count = 0;
+
+  const ExtensionSet& extensions = extension_registry_->enabled_extensions();
+  ExtensionActionManager* extension_action_manager =
+      ExtensionActionManager::Get(profile);
+  for (ExtensionSet::const_iterator iter = extensions.begin();
+       iter != extensions.end();
+       ++iter) {
+    const Extension* extension = *iter;
+    Manifest::Location location = extension->location();
+    Manifest::Type type = extension->GetType();
+
+    // For the first few metrics, include all extensions and apps (component,
+    // unpacked, etc). It's good to know these locations, and it doesn't
+    // muck up any of the stats. Later, though, we want to omit component and
+    // unpacked, as they are less interesting.
+    if (extension->is_app())
+      UMA_HISTOGRAM_ENUMERATION(
+          "Extensions.AppLocation", location, Manifest::NUM_LOCATIONS);
+    else if (extension->is_extension())
+      UMA_HISTOGRAM_ENUMERATION(
+          "Extensions.ExtensionLocation", location, Manifest::NUM_LOCATIONS);
+
+    if (!ManifestURL::UpdatesFromGallery(extension)) {
+      UMA_HISTOGRAM_ENUMERATION(
+          "Extensions.NonWebstoreLocation", location, Manifest::NUM_LOCATIONS);
+
+      // Check for inconsistencies if the extension was supposedly installed
+      // from the webstore.
+      enum {
+        BAD_UPDATE_URL = 0,
+        // This value was a mistake. Turns out sideloaded extensions can
+        // have the from_webstore bit if they update from the webstore.
+        DEPRECATED_IS_EXTERNAL = 1,
+      };
+      if (extension->from_webstore()) {
+        UMA_HISTOGRAM_ENUMERATION(
+            "Extensions.FromWebstoreInconsistency", BAD_UPDATE_URL, 2);
+      }
     }
+
     if (Manifest::IsExternalLocation(location)) {
       // See loop below for DISABLED.
-      if (ManifestURL::UpdatesFromGallery(*ex)) {
+      if (ManifestURL::UpdatesFromGallery(extension)) {
         UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalItemState",
                                   EXTERNAL_ITEM_WEBSTORE_ENABLED,
                                   EXTERNAL_ITEM_MAX_ITEMS);
@@ -314,54 +375,42 @@ void InstalledLoader::LoadAllExtensions() {
                                   EXTERNAL_ITEM_MAX_ITEMS);
       }
     }
-    if ((*ex)->from_webstore()) {
-      // Check for inconsistencies if the extension was supposedly installed
-      // from the webstore.
-      enum {
-        BAD_UPDATE_URL = 0,
-        // This value was a mistake. Turns out sideloaded extensions can
-        // have the from_webstore bit if they update from the webstore.
-        DEPRECATED_IS_EXTERNAL = 1,
-      };
-      if (!ManifestURL::UpdatesFromGallery(*ex)) {
-        UMA_HISTOGRAM_ENUMERATION("Extensions.FromWebstoreInconsistency",
-                                  BAD_UPDATE_URL, 2);
-      }
-    }
 
-    // Don't count component extensions, since they are only extensions as an
-    // implementation detail.
+    // From now on, don't count component extensions, since they are only
+    // extensions as an implementation detail. Continue to count unpacked
+    // extensions for a few metrics.
     if (location == Manifest::COMPONENT)
       continue;
+
     // Histogram for non-webstore extensions overriding new tab page should
     // include unpacked extensions.
-    if (!(*ex)->from_webstore()) {
-      const extensions::URLOverrides::URLOverrideMap& override_map =
-          extensions::URLOverrides::GetChromeURLOverrides(ex->get());
-      if (override_map.find("newtab") != override_map.end()) {
-        ++non_webstore_ntp_override_count;
-      }
+    if (!extension->from_webstore() &&
+        URLOverrides::GetChromeURLOverrides(extension).count("newtab")) {
+      ++non_webstore_ntp_override_count;
     }
 
-    // Don't count unpacked extensions, since they're a developer-specific
-    // feature.
+    // Don't count unpacked extensions anymore, either.
     if (Manifest::IsUnpackedLocation(location))
       continue;
 
     UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestVersion",
-                              (*ex)->manifest_version(), 10);
+                              extension->manifest_version(),
+                              10);  // TODO(kalman): Why 10 manifest versions?
 
+    // We might have wanted to count legacy packaged apps here, too, since they
+    // are effectively extensions. Unfortunately, it's too late, as we don't
+    // want to mess up the existing stats.
     if (type == Manifest::TYPE_EXTENSION) {
-      BackgroundPageType background_page_type =
-          GetBackgroundPageType(ex->get());
-      UMA_HISTOGRAM_ENUMERATION(
-          "Extensions.BackgroundPageType", background_page_type, 10);
+      UMA_HISTOGRAM_ENUMERATION("Extensions.BackgroundPageType",
+                                GetBackgroundPageType(extension),
+                                NUM_BACKGROUND_PAGE_TYPES);
     }
 
     // Using an enumeration shows us the total installed ratio across all users.
     // Using the totals per user at each startup tells us the distribution of
     // usage for each user (e.g. 40% of users have at least one app installed).
-    UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
+    UMA_HISTOGRAM_ENUMERATION(
+        "Extensions.LoadType", type, Manifest::NUM_LOAD_TYPES);
     switch (type) {
       case Manifest::TYPE_THEME:
         ++theme_count;
@@ -402,30 +451,51 @@ void InstalledLoader::LoadAllExtensions() {
         }
         break;
     }
-    if (!Manifest::IsExternalLocation((*ex)->location()))
-      ++item_user_count;
-    ExtensionActionManager* extension_action_manager =
-        ExtensionActionManager::Get(extension_service_->profile());
-    if (extension_action_manager->GetPageAction(*ex->get()))
+
+    if (extension_action_manager->GetPageAction(*extension))
       ++page_action_count;
-    if (extension_action_manager->GetBrowserAction(*ex->get()))
+
+    if (extension_action_manager->GetBrowserAction(*extension))
       ++browser_action_count;
 
-    if (extensions::ManagedModeInfo::IsContentPack(ex->get()))
+    if (SupervisedUserInfo::IsContentPack(extension))
       ++content_pack_count;
 
-    extension_service_->RecordPermissionMessagesHistogram(
-        ex->get(), "Extensions.Permissions_Load");
+    RecordCreationFlags(extension);
+
+    ExtensionService::RecordPermissionMessagesHistogram(
+        extension, "Extensions.Permissions_Load2");
+
+    // For incognito and file access, skip anything that doesn't appear in
+    // settings. Also, policy-installed (and unpacked of course, checked above)
+    // extensions are boring.
+    if (extension->ShouldDisplayInExtensionSettings() &&
+        !Manifest::IsPolicyLocation(extension->location())) {
+      if (extension->can_be_incognito_enabled()) {
+        if (util::IsIncognitoEnabled(extension->id(), profile))
+          ++incognito_allowed_count;
+        else
+          ++incognito_not_allowed_count;
+      }
+      if (extension->wants_file_access()) {
+        if (util::AllowFileAccess(extension->id(), profile))
+          ++file_access_allowed_count;
+        else
+          ++file_access_not_allowed_count;
+      }
+    }
   }
 
-  const ExtensionSet* disabled_extensions =
-      extension_service_->disabled_extensions();
-  for (ex = disabled_extensions->begin();
-       ex != disabled_extensions->end(); ++ex) {
-    if (extension_service_->extension_prefs()->
-        DidExtensionEscalatePermissions((*ex)->id())) {
+  const ExtensionSet& disabled_extensions =
+      extension_registry_->disabled_extensions();
+
+  for (ExtensionSet::const_iterator ex = disabled_extensions.begin();
+       ex != disabled_extensions.end();
+       ++ex) {
+    if (extension_prefs_->DidExtensionEscalatePermissions((*ex)->id())) {
       ++disabled_for_permissions_count;
     }
+    RecordDisableReasons(extension_prefs_->GetDisableReasons((*ex)->id()));
     if (Manifest::IsExternalLocation((*ex)->location())) {
       // See loop above for ENABLED.
       if (ManifestURL::UpdatesFromGallery(*ex)) {
@@ -459,7 +529,6 @@ void InstalledLoader::LoadAllExtensions() {
     }
   }
 
-  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAllUser", item_user_count);
   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
                            app_user_count + app_external_count);
   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
@@ -484,6 +553,20 @@ void InstalledLoader::LoadAllExtensions() {
                            disabled_for_permissions_count);
   UMA_HISTOGRAM_COUNTS_100("Extensions.NonWebStoreNewTabPageOverrides",
                            non_webstore_ntp_override_count);
+  if (incognito_allowed_count + incognito_not_allowed_count > 0) {
+    UMA_HISTOGRAM_COUNTS_100("Extensions.IncognitoAllowed",
+                             incognito_allowed_count);
+    UMA_HISTOGRAM_COUNTS_100("Extensions.IncognitoNotAllowed",
+                             incognito_not_allowed_count);
+  }
+  if (file_access_allowed_count + file_access_not_allowed_count > 0) {
+    UMA_HISTOGRAM_COUNTS_100("Extensions.FileAccessAllowed",
+                             file_access_allowed_count);
+    UMA_HISTOGRAM_COUNTS_100("Extensions.FileAccessNotAllowed",
+                             file_access_not_allowed_count);
+  }
+  UMA_HISTOGRAM_COUNTS_100("Extensions.CorruptExtensionTotalDisables",
+                           extension_prefs_->GetCorruptedDisableCount());
 }
 
 int InstalledLoader::GetCreationFlags(const ExtensionInfo* info) {