Commit 8af94ef3 authored by Swapnil's avatar Swapnil Committed by Commit Bot

Add fetch error codes event for force installed extensions

We store error codes and number of fetch tries if the extension
installation fails due to MANIFEST_FETCH_FAILED or CRX_FETCH_FAILED.
We want to add these fields to the existing events for
the event based reporting for force installed extensions so that
detailed reason can be reported.

Bug: 1048640
Change-Id: I124615d0a8ffa4b7f9991149054947a5cf391e5a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2505983
Commit-Queue: Swapnil Gupta <swapnilgupta@google.com>
Reviewed-by: default avatarOleg Davydov <burunduk@chromium.org>
Reviewed-by: default avatarSergey Poromov <poromov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825821}
parent 962f3a29
...@@ -485,8 +485,24 @@ ConvertManifestInvalidErrorToProto(extensions::ManifestInvalidError error) { ...@@ -485,8 +485,24 @@ ConvertManifestInvalidErrorToProto(extensions::ManifestInvalidError error) {
} }
} }
void AddErrorCodesToFailureEvent(
const extensions::InstallStageTracker::InstallationData& data,
em::ExtensionInstallReportLogEvent* event) {
if (data.response_code) {
event->set_fetch_error_code(data.response_code.value());
} else {
DCHECK(data.network_error_code);
event->set_fetch_error_code(data.network_error_code.value());
}
DCHECK(data.fetch_tries);
event->set_fetch_tries(data.fetch_tries.value_or(0));
}
} // namespace } // namespace
using FailureReason = extensions::InstallStageTracker::FailureReason;
ExtensionInstallEventLogCollector::ExtensionInstallEventLogCollector( ExtensionInstallEventLogCollector::ExtensionInstallEventLogCollector(
extensions::ExtensionRegistry* registry, extensions::ExtensionRegistry* registry,
Delegate* delegate, Delegate* delegate,
...@@ -564,7 +580,7 @@ void ExtensionInstallEventLogCollector::OnConnectionChanged( ...@@ -564,7 +580,7 @@ void ExtensionInstallEventLogCollector::OnConnectionChanged(
void ExtensionInstallEventLogCollector::OnExtensionInstallationFailed( void ExtensionInstallEventLogCollector::OnExtensionInstallationFailed(
const extensions::ExtensionId& extension_id, const extensions::ExtensionId& extension_id,
extensions::InstallStageTracker::FailureReason reason) { FailureReason reason) {
if (!delegate_->IsExtensionPending(extension_id)) if (!delegate_->IsExtensionPending(extension_id))
return; return;
auto event = std::make_unique<em::ExtensionInstallReportLogEvent>(); auto event = std::make_unique<em::ExtensionInstallReportLogEvent>();
...@@ -598,6 +614,12 @@ void ExtensionInstallEventLogCollector::OnExtensionInstallationFailed( ...@@ -598,6 +614,12 @@ void ExtensionInstallEventLogCollector::OnExtensionInstallationFailed(
event->set_crx_install_error_detail( event->set_crx_install_error_detail(
ConvertCrxInstallErrorDetailToProto(data.install_error_detail.value())); ConvertCrxInstallErrorDetailToProto(data.install_error_detail.value()));
} }
if (reason == FailureReason::CRX_FETCH_FAILED ||
reason == FailureReason::MANIFEST_FETCH_FAILED) {
AddErrorCodesToFailureEvent(data, event.get());
}
extensions::ForceInstalledTracker* force_installed_tracker = extensions::ForceInstalledTracker* force_installed_tracker =
extensions::ExtensionSystem::Get(profile_) extensions::ExtensionSystem::Get(profile_)
->extension_service() ->extension_service()
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "content/public/test/browser_task_environment.h" #include "content/public/test/browser_task_environment.h"
#include "extensions/browser/extension_system.h" #include "extensions/browser/extension_system.h"
#include "extensions/common/extension_builder.h" #include "extensions/common/extension_builder.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h" #include "third_party/cros_system_api/dbus/service_constants.h"
...@@ -47,6 +48,10 @@ constexpr char kExtensionName1[] = "name1"; ...@@ -47,6 +48,10 @@ constexpr char kExtensionName1[] = "name1";
constexpr char kEmailId[] = "test@example.com"; constexpr char kEmailId[] = "test@example.com";
constexpr char kGaiaId[] = "12345"; constexpr char kGaiaId[] = "12345";
const int kFetchTries = 5;
// HTTP_UNAUTHORIZED
const int kResponseCode = 401;
class FakeExtensionInstallEventLogCollectorDelegate class FakeExtensionInstallEventLogCollectorDelegate
: public ExtensionInstallEventLogCollector::Delegate { : public ExtensionInstallEventLogCollector::Delegate {
public: public:
...@@ -555,6 +560,59 @@ TEST_F(ExtensionInstallEventLogCollectorTest, ...@@ -555,6 +560,59 @@ TEST_F(ExtensionInstallEventLogCollectorTest,
delegate()->last_request().event.manifest_invalid_error()); delegate()->last_request().event.manifest_invalid_error());
} }
// Verifies that a new event with error codes and number of fetch tries is
// created when the extension failed with error MANFIEST_FETCH_FAILED.
TEST_F(ExtensionInstallEventLogCollectorTest,
ExtensionInstallFailedWithManifestFetchFailed) {
auto collector = std::make_unique<ExtensionInstallEventLogCollector>(
registry(), delegate(), profile());
extensions::InstallStageTracker* tracker =
extensions::InstallStageTracker::Get(profile());
// One extension failed.
extensions::ExtensionDownloaderDelegate::FailureData data(
net::Error::OK, kResponseCode, kFetchTries);
tracker->ReportFetchError(
kExtensionId1,
extensions::InstallStageTracker::FailureReason::MANIFEST_FETCH_FAILED,
data);
ASSERT_TRUE(VerifyEventAddedSuccessfully(1 /*expected_add_count*/,
0 /*expected_add_all_count*/));
EXPECT_EQ(em::ExtensionInstallReportLogEvent::INSTALLATION_FAILED,
delegate()->last_request().event.event_type());
EXPECT_EQ(em::ExtensionInstallReportLogEvent::MANIFEST_FETCH_FAILED,
delegate()->last_request().event.failure_reason());
EXPECT_EQ(kResponseCode, delegate()->last_request().event.fetch_error_code());
EXPECT_EQ(kFetchTries, delegate()->last_request().event.fetch_tries());
}
// Verifies that a new event with fetch error code and number of fetch tries is
// created when the extension failed with error CRX_FETCH_FAILED.
TEST_F(ExtensionInstallEventLogCollectorTest,
ExtensionInstallFailedWithCrxFetchFailed) {
auto collector = std::make_unique<ExtensionInstallEventLogCollector>(
registry(), delegate(), profile());
extensions::InstallStageTracker* tracker =
extensions::InstallStageTracker::Get(profile());
// One extension failed.
extensions::ExtensionDownloaderDelegate::FailureData data(
net::Error::OK, kResponseCode, kFetchTries);
tracker->ReportFetchError(
kExtensionId1,
extensions::InstallStageTracker::FailureReason::CRX_FETCH_FAILED, data);
ASSERT_TRUE(VerifyEventAddedSuccessfully(1 /*expected_add_count*/,
0 /*expected_add_all_count*/));
EXPECT_EQ(em::ExtensionInstallReportLogEvent::INSTALLATION_FAILED,
delegate()->last_request().event.event_type());
EXPECT_EQ(em::ExtensionInstallReportLogEvent::CRX_FETCH_FAILED,
delegate()->last_request().event.failure_reason());
EXPECT_EQ(kResponseCode, delegate()->last_request().event.fetch_error_code());
EXPECT_EQ(kFetchTries, delegate()->last_request().event.fetch_tries());
}
// Verifies that a new event is created when an extension is successfully // Verifies that a new event is created when an extension is successfully
// installed. // installed.
TEST_F(ExtensionInstallEventLogCollectorTest, InstallExtension) { TEST_F(ExtensionInstallEventLogCollectorTest, InstallExtension) {
......
...@@ -53,6 +53,8 @@ constexpr char kDownloadCacheStatus[] = "downloadCacheStatus"; ...@@ -53,6 +53,8 @@ constexpr char kDownloadCacheStatus[] = "downloadCacheStatus";
constexpr char kUnpackerFailureReason[] = "unpackerFailureReason"; constexpr char kUnpackerFailureReason[] = "unpackerFailureReason";
constexpr char kManifestInvalidError[] = "manifestInvalidError"; constexpr char kManifestInvalidError[] = "manifestInvalidError";
constexpr char kCrxInstallErrorDetail[] = "crxInstallErrorDetail"; constexpr char kCrxInstallErrorDetail[] = "crxInstallErrorDetail";
constexpr char kFetchErrorCode[] = "fetchErrorCode";
constexpr char kFetchTries[] = "fetchTries";
// Calculates hash for the given |event| and |context|, and stores the hash in // Calculates hash for the given |event| and |context|, and stores the hash in
// |hash|. Returns true if |event| and |context| are json serializable and // |hash|. Returns true if |event| and |context| are json serializable and
...@@ -229,6 +231,16 @@ base::Value ConvertExtensionEventToValue( ...@@ -229,6 +231,16 @@ base::Value ConvertExtensionEventToValue(
extension_install_report_log_event.manifest_invalid_error()); extension_install_report_log_event.manifest_invalid_error());
} }
if (extension_install_report_log_event.has_fetch_error_code()) {
event.SetIntKey(kFetchErrorCode,
extension_install_report_log_event.fetch_error_code());
}
if (extension_install_report_log_event.has_fetch_tries()) {
event.SetIntKey(kFetchTries,
extension_install_report_log_event.fetch_tries());
}
if (extension_install_report_log_event.has_crx_install_error_detail()) { if (extension_install_report_log_event.has_crx_install_error_detail()) {
event.SetIntKey( event.SetIntKey(
kCrxInstallErrorDetail, kCrxInstallErrorDetail,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chrome/browser/profiles/reporting_util.h" #include "chrome/browser/profiles/reporting_util.h"
#include "chromeos/system/fake_statistics_provider.h" #include "chromeos/system/fake_statistics_provider.h"
#include "components/policy/proto/device_management_backend.pb.h" #include "components/policy/proto/device_management_backend.pb.h"
#include "net/base/net_errors.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -25,6 +26,10 @@ constexpr char kTestExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; ...@@ -25,6 +26,10 @@ constexpr char kTestExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
constexpr int64_t kDiskSpaceTotalBytes = 5 * 1024 * 1024; constexpr int64_t kDiskSpaceTotalBytes = 5 * 1024 * 1024;
const int64_t kDiskSpaceFreeBytes = 2 * 1024 * 1024; const int64_t kDiskSpaceFreeBytes = 2 * 1024 * 1024;
const int kExampleFetchTries = 5;
// HTTP_UNAUTHORIZED
const int kExampleResponseCode = 401;
// Common key names used when building the dictionary to pass to the Chrome // Common key names used when building the dictionary to pass to the Chrome
// Reporting API. These must be same as ones mentioned in // Reporting API. These must be same as ones mentioned in
// install_event_log_util.cc. // install_event_log_util.cc.
...@@ -52,6 +57,8 @@ constexpr char kDownloadCacheStatus[] = "downloadCacheStatus"; ...@@ -52,6 +57,8 @@ constexpr char kDownloadCacheStatus[] = "downloadCacheStatus";
constexpr char kUnpackerFailureReason[] = "unpackerFailureReason"; constexpr char kUnpackerFailureReason[] = "unpackerFailureReason";
constexpr char kManifestInvalidError[] = "manifestInvalidError"; constexpr char kManifestInvalidError[] = "manifestInvalidError";
constexpr char kCrxInstallErrorDetail[] = "crxInstallErrorDetail"; constexpr char kCrxInstallErrorDetail[] = "crxInstallErrorDetail";
constexpr char kFetchErrorCode[] = "fetchErrorCode";
constexpr char kFetchTries[] = "fetchTries";
void ConvertToValueAndVerify(const em::ExtensionInstallReportLogEvent& event, void ConvertToValueAndVerify(const em::ExtensionInstallReportLogEvent& event,
const std::vector<std::string>& keys) { const std::vector<std::string>& keys) {
...@@ -152,6 +159,22 @@ TEST_F(ExtensionInstallEventLogUtilTest, ManifestInvalidFailureReasonEvent) { ...@@ -152,6 +159,22 @@ TEST_F(ExtensionInstallEventLogUtilTest, ManifestInvalidFailureReasonEvent) {
kStatefulTotal, kStatefulFree}); kStatefulTotal, kStatefulFree});
} }
// Verifies that an event reporting error codes and number of fetch tries when
// extension failed to install with error MANIFEST_FETCH_FAILED is successfully
// parsed.
TEST_F(ExtensionInstallEventLogUtilTest, ManifestFetchFailedEvent) {
event_.set_event_type(
em::ExtensionInstallReportLogEvent::INSTALLATION_FAILED);
event_.set_failure_reason(
em::ExtensionInstallReportLogEvent::MANIFEST_FETCH_FAILED);
event_.set_fetch_error_code(kExampleResponseCode);
event_.set_fetch_tries(kExampleFetchTries);
event_.set_stateful_total(kDiskSpaceTotalBytes);
event_.set_stateful_free(kDiskSpaceFreeBytes);
ConvertToValueAndVerify(event_, {kEventType, kFailureReason, kFetchErrorCode,
kFetchTries, kStatefulTotal, kStatefulFree});
}
// Verifies that an event reporting extension installation stage is successfully // Verifies that an event reporting extension installation stage is successfully
// parsed. // parsed.
TEST_F(ExtensionInstallEventLogUtilTest, InstallationStageEvent) { TEST_F(ExtensionInstallEventLogUtilTest, InstallationStageEvent) {
......
...@@ -3177,6 +3177,14 @@ message ExtensionInstallReportLogEvent { ...@@ -3177,6 +3177,14 @@ message ExtensionInstallReportLogEvent {
// Extended error code if the extension installation failed due to CRX install // Extended error code if the extension installation failed due to CRX install
// error. // error.
optional CrxInstallErrorDetail crx_install_error_detail = 18; optional CrxInstallErrorDetail crx_install_error_detail = 18;
// Fetch error code when failure_reason is CRX_FETCH_FAILED or
// MANIFEST_FETCH_FAILED.
optional int32 fetch_error_code = 19;
// Number of fetch tries made when failure reason is CRX_FETCH_FAILED or
// MANIFEST_FETCH_FAILED.
optional int32 fetch_tries = 20;
} }
// A single entry in the push-install log for an app. // A single entry in the push-install log for an app.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment