Add UMA to record whether the extension is from CWS

We want to investigate why the force installed extensions fail to
install with error CRX_HEADER_INVALID. This CL adds UMA statistics
to record whether the extension is from Chrome Web Store or not when
extension fails with CRX_HEADER_INVALID error to
get more details about it.

New histogram added:
"Extensions.ForceInstalledFailureWithCrxHeaderInvalidIsCWS"

(cherry picked from commit 3f4a6b7209515758dce0e350673c32dc7395062f)

Bug: b/170080693
Change-Id: I5cbaef996151fa75aa5716c985c5ce2035a04ac1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2449334
Commit-Queue: Swapnil Gupta <[email protected]>
Reviewed-by: Oleg Davydov <[email protected]>
Reviewed-by: Ilya Sherman <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#815097}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2469652
Reviewed-by: Swapnil Gupta <[email protected]>
Cr-Commit-Position: refs/branch-heads/4280@{#359}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
index 35f623a..00ed95e 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics.cc
@@ -187,7 +187,8 @@
 // Reports detailed failure reason for the extensions which failed to install
 // after 5 minutes.
 void ReportDetailedFailureReasons(
-    const InstallStageTracker::InstallationData& installation) {
+    const InstallStageTracker::InstallationData& installation,
+    const bool is_from_store) {
   FailureReason failure_reason =
       installation.failure_reason.value_or(FailureReason::UNKNOWN);
 
@@ -233,6 +234,13 @@
           installation.app_status_error.value());
     }
   }
+  if (installation.unpacker_failure_reason &&
+      installation.unpacker_failure_reason.value() ==
+          SandboxedUnpackerFailureReason::CRX_HEADER_INVALID) {
+    base::UmaHistogramBoolean(
+        "Extensions.ForceInstalledFailureWithCrxHeaderInvalidIsCWS",
+        is_from_store);
+  }
 }
 
 }  // namespace
@@ -359,7 +367,8 @@
         installation.failure_reason.value_or(FailureReason::UNKNOWN);
     base::UmaHistogramEnumeration("Extensions.ForceInstalledFailureReason3",
                                   failure_reason);
-    if (tracker_->extensions().at(extension_id).is_from_store) {
+    bool is_from_store = tracker_->extensions().at(extension_id).is_from_store;
+    if (is_from_store) {
       base::UmaHistogramEnumeration(
           "Extensions.WebStore_ForceInstalledFailureReason3", failure_reason);
     } else {
@@ -383,7 +392,7 @@
     VLOG(2) << "Forced extension " << extension_id
             << " failed to install with data="
             << InstallStageTracker::GetFormattedInstallationData(installation);
-    ReportDetailedFailureReasons(installation);
+    ReportDetailedFailureReasons(installation, is_from_store);
   }
   bool non_misconfigured_failure_occurred =
       misconfigured_extensions != missing_forced_extensions.size();
diff --git a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
index 21d8c03..60b57ef 100644
--- a/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
+++ b/chrome/browser/extensions/forced_extensions/force_installed_metrics_unittest.cc
@@ -111,6 +111,8 @@
     "Extensions.ForceInstalledTime.CheckingExpectationsStartTo.FinalizingStart";
 constexpr char kFinalizingTimeStats[] =
     "Extensions.ForceInstalledTime.FinalizingStartTo.CRXInstallComplete";
+constexpr char kCrxHeaderInvalidFailureIsCWS[] =
+    "Extensions.ForceInstalledFailureWithCrxHeaderInvalidIsCWS";
 
 }  // namespace
 
@@ -531,6 +533,25 @@
       1);
 }
 
+// Reporting whether the extension is from CWS or not when the force installed
+// extension fails to install with error CRX_HEADER_INVALID.
+TEST_F(ForceInstalledMetricsTest, ExtensionsCrxHeaderInvalid) {
+  SetupForceList();
+  install_stage_tracker()->ReportSandboxedUnpackerFailureReason(
+      kExtensionId1, SandboxedUnpackerFailureReason::CRX_HEADER_INVALID);
+  auto ext2 = ExtensionBuilder(kExtensionName2).SetID(kExtensionId2).Build();
+  registry()->AddEnabled(ext2.get());
+  force_installed_tracker()->OnExtensionLoaded(profile(), ext2.get());
+  // ForceInstalledMetrics shuts down timer because all extension are either
+  // loaded or failed.
+  EXPECT_FALSE(fake_timer_->IsRunning());
+  histogram_tester_.ExpectTotalCount(kSandboxUnpackFailureReason, 1);
+  histogram_tester_.ExpectBucketCount(
+      kSandboxUnpackFailureReason,
+      SandboxedUnpackerFailureReason::CRX_HEADER_INVALID, 1);
+  histogram_tester_.ExpectBucketCount(kCrxHeaderInvalidFailureIsCWS, true, 1);
+}
+
 // Reporting info when the force installed extension fails to install with error
 // CRX_FETCH_URL_EMPTY due to no updates from the server.
 TEST_F(ForceInstalledMetricsTest, ExtensionsNoUpdatesInfoReporting) {
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 22a1ffc2..59657b44 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -38522,6 +38522,15 @@
   <int value="5" label="IPV6_INTERFACE_ARRAY_TOO_SHORT"/>
 </enum>
 
+<enum name="IsForceInstalledExtensionFailedWithCrxHeaderInvalidFromCWSBoolean">
+  <summary>
+    A boolean for whether a force installed extension which failed with error
+    CRX_HEADER_INVALID is from Chrome Web Store or not.
+  </summary>
+  <int value="0" label="Offstore"/>
+  <int value="1" label="Chrome Web Store"/>
+</enum>
+
 <enum name="IsFullyManagedBoolean">
   <summary>
     A boolean for whether a device is &quot;fully managed&quot;.
diff --git a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
index 87985e4c..8da06b6 100644
--- a/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/extensions/histograms.xml
@@ -1469,6 +1469,20 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.ForceInstalledFailureWithCrxHeaderInvalidIsCWS"
+    enum="IsForceInstalledExtensionFailedWithCrxHeaderInvalidFromCWSBoolean"
+    expires_after="2021-01-24">
+  <owner>[email protected]</owner>
+  <owner>[email protected]</owner>
+  <owner>[email protected]</owner>
+  <summary>
+    Records whether the extension is from the Chrome Web Store or not. Recorded
+    for each forced extension that failed to install after 5 minutes with
+    Extensions.ForceInstalledFailureSandboxUnpackFailureReason equal to
+    CRX_HEADER_INVALID.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.ForceInstalledFetchTries" units="retries"
     expires_after="2021-03-28">
   <owner>[email protected]</owner>