Add UpdateEngine.Attempt.ConnectionType metric.
This adds a new metric so we can track the how the device is connected
to the Internet when an attempt starts.
BUG=chromium:358339
TEST=New unit test + unit tests pass.
Change-Id: Ic5c2f50e2396e6baa288aca70906f7112ef7bca9
Reviewed-on: https://chromium-review.googlesource.com/192864
Reviewed-by: Chris Sosa <sosa@chromium.org>
Reviewed-by: Alex Deymo <deymo@chromium.org>
Tested-by: David Zeuthen <zeuthen@chromium.org>
Commit-Queue: David Zeuthen <zeuthen@chromium.org>
diff --git a/metrics.cc b/metrics.cc
index b784b61..1584120 100644
--- a/metrics.cc
+++ b/metrics.cc
@@ -39,6 +39,8 @@
"UpdateEngine.Attempt.PayloadType";
const char kMetricAttemptPayloadSizeMiB[] =
"UpdateEngine.Attempt.PayloadSizeMiB";
+const char kMetricAttemptConnectionType[] =
+ "UpdateEngine.Attempt.ConnectionType";
const char kMetricAttemptDurationMinutes[] =
"UpdateEngine.Attempt.DurationMinutes";
const char kMetricAttemptDurationUptimeMinutes[] =
@@ -180,7 +182,8 @@
DownloadSource download_source,
AttemptResult attempt_result,
ErrorCode internal_error_code,
- DownloadErrorCode payload_download_error_code) {
+ DownloadErrorCode payload_download_error_code,
+ ConnectionType connection_type) {
string metric;
metric = metrics::kMetricAttemptNumber;
@@ -311,6 +314,14 @@
30*24*60, // max: 30 days
50); // num_buckets
}
+
+ metric = metrics::kMetricAttemptConnectionType;
+ LOG(INFO) << "Uploading " << static_cast<int>(connection_type)
+ << " for metric " << metric;
+ system_state->metrics_lib()->SendEnumToUMA(
+ metric,
+ static_cast<int>(connection_type),
+ static_cast<int>(ConnectionType::kNumConstants));
}
diff --git a/metrics.h b/metrics.h
index 4e6ed04..b5dd5f1 100644
--- a/metrics.h
+++ b/metrics.h
@@ -30,6 +30,7 @@
extern const char kMetricAttemptNumber[];
extern const char kMetricAttemptPayloadType[];
extern const char kMetricAttemptPayloadSizeMiB[];
+extern const char kMetricAttemptConnectionType[];
extern const char kMetricAttemptDurationMinutes[];
extern const char kMetricAttemptDurationUptimeMinutes[];
extern const char kMetricAttemptTimeSinceLastAttemptSeconds[];
@@ -140,6 +141,23 @@
kUnset = -1
};
+// Possible ways the device is connected to the Internet.
+//
+// This is used in the UpdateEngine.Attempt.ConnectionType histogram.
+enum class ConnectionType {
+ kUnknown, // Unknown.
+ kEthernet, // Ethernet.
+ kWifi, // Wireless.
+ kWimax, // WiMax.
+ kBluetooth, // Bluetooth.
+ kCellular, // Cellular.
+ kTetheredEthernet, // Tethered (Ethernet).
+ kTetheredWifi, // Tethered (Wifi).
+
+ kNumConstants,
+ kUnset = -1
+};
+
// Helper function to report metrics reported once a day. The
// following metrics are reported:
//
@@ -215,7 +233,8 @@
DownloadSource download_source,
AttemptResult attempt_result,
ErrorCode internal_error_code,
- DownloadErrorCode payload_download_error_code);
+ DownloadErrorCode payload_download_error_code,
+ ConnectionType connection_type);
// Helper function to report the after the completion of a successful
// update attempt. The following metrics are reported:
diff --git a/payload_state.cc b/payload_state.cc
index 779f708..2685130 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -16,6 +16,7 @@
#include "update_engine/hardware_interface.h"
#include "update_engine/install_plan.h"
#include "update_engine/prefs.h"
+#include "update_engine/real_dbus_wrapper.h"
#include "update_engine/system_state.h"
#include "update_engine/utils.h"
@@ -158,8 +159,22 @@
ClockInterface *clock = system_state_->clock();
attempt_start_time_boot_ = clock->GetBootTime();
attempt_start_time_monotonic_ = clock->GetMonotonicTime();
-
attempt_num_bytes_downloaded_ = 0;
+
+ metrics::ConnectionType type;
+ NetworkConnectionType network_connection_type;
+ NetworkTethering tethering;
+ RealDBusWrapper dbus_iface;
+ ConnectionManager* connection_manager = system_state_->connection_manager();
+ if (!connection_manager->GetConnectionProperties(&dbus_iface,
+ &network_connection_type,
+ &tethering)) {
+ LOG(ERROR) << "Failed to determine connection type.";
+ type = metrics::ConnectionType::kUnknown;
+ } else {
+ type = utils::GetConnectionType(network_connection_type, tethering);
+ }
+ attempt_connection_type_ = type;
}
void PayloadState::UpdateResumed() {
@@ -583,7 +598,8 @@
download_source,
attempt_result,
internal_error_code,
- payload_download_error_code);
+ payload_download_error_code,
+ attempt_connection_type_);
}
void PayloadState::CollectAndReportSuccessfulUpdateMetrics() {
diff --git a/payload_state.h b/payload_state.h
index 1035404..d0211c5 100644
--- a/payload_state.h
+++ b/payload_state.h
@@ -8,6 +8,7 @@
#include <base/time/time.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include "update_engine/metrics.h"
#include "update_engine/payload_state_interface.h"
#include "update_engine/prefs_interface.h"
@@ -502,6 +503,9 @@
// The monotonic time when the attempt was started.
base::Time attempt_start_time_monotonic_;
+ // The connection type when the attempt started.
+ metrics::ConnectionType attempt_connection_type_;
+
DISALLOW_COPY_AND_ASSIGN(PayloadState);
};
diff --git a/utils.cc b/utils.cc
index 0cde048..6d2abac 100644
--- a/utils.cc
+++ b/utils.cc
@@ -1125,6 +1125,41 @@
return metrics::DownloadErrorCode::kInputMalformed;
}
+metrics::ConnectionType GetConnectionType(
+ NetworkConnectionType type,
+ NetworkTethering tethering) {
+ switch (type) {
+ case kNetUnknown:
+ return metrics::ConnectionType::kUnknown;
+
+ case kNetEthernet:
+ if (tethering == NetworkTethering::kConfirmed)
+ return metrics::ConnectionType::kTetheredEthernet;
+ else
+ return metrics::ConnectionType::kEthernet;
+
+ case kNetWifi:
+ if (tethering == NetworkTethering::kConfirmed)
+ return metrics::ConnectionType::kTetheredWifi;
+ else
+ return metrics::ConnectionType::kWifi;
+
+ case kNetWimax:
+ return metrics::ConnectionType::kWimax;
+
+ case kNetBluetooth:
+ return metrics::ConnectionType::kBluetooth;
+
+ case kNetCellular:
+ return metrics::ConnectionType::kCellular;
+ }
+
+ LOG(ERROR) << "Unexpected network connection type: type=" << type
+ << ", tethering=" << static_cast<int>(tethering);
+
+ return metrics::ConnectionType::kUnknown;
+}
+
// Returns a printable version of the various flags denoted in the higher order
// bits of the given code. Returns an empty string if none of those bits are
// set.
diff --git a/utils.h b/utils.h
index 482f81a..77ed9d9 100644
--- a/utils.h
+++ b/utils.h
@@ -20,9 +20,10 @@
#include "metrics/metrics_library.h"
#include "update_engine/action.h"
+#include "update_engine/action_processor.h"
+#include "update_engine/connection_manager.h"
#include "update_engine/constants.h"
#include "update_engine/metrics.h"
-#include "update_engine/action_processor.h"
namespace chromeos_update_engine {
@@ -350,6 +351,10 @@
// can use utils::GetDownloadError() to get more detail.
metrics::AttemptResult GetAttemptResult(ErrorCode code);
+// Calculates the internet connection type given |type| and |tethering|.
+metrics::ConnectionType GetConnectionType(NetworkConnectionType type,
+ NetworkTethering tethering);
+
// Sends the error code to UMA using the metrics interface object in the given
// system state. It also uses the system state to determine the right UMA
// bucket for the error code.
diff --git a/utils_unittest.cc b/utils_unittest.cc
index 5e9d098..84c20cc 100644
--- a/utils_unittest.cc
+++ b/utils_unittest.cc
@@ -682,4 +682,54 @@
EXPECT_EQ(duration.InSeconds(), 0);
}
+TEST(UtilsTest, GetConnectionType) {
+ // Check that expected combinations map to the right value.
+ EXPECT_EQ(metrics::ConnectionType::kUnknown,
+ utils::GetConnectionType(kNetUnknown,
+ NetworkTethering::kUnknown));
+ EXPECT_EQ(metrics::ConnectionType::kEthernet,
+ utils::GetConnectionType(kNetEthernet,
+ NetworkTethering::kUnknown));
+ EXPECT_EQ(metrics::ConnectionType::kWifi,
+ utils::GetConnectionType(kNetWifi,
+ NetworkTethering::kUnknown));
+ EXPECT_EQ(metrics::ConnectionType::kWimax,
+ utils::GetConnectionType(kNetWimax,
+ NetworkTethering::kUnknown));
+ EXPECT_EQ(metrics::ConnectionType::kBluetooth,
+ utils::GetConnectionType(kNetBluetooth,
+ NetworkTethering::kUnknown));
+ EXPECT_EQ(metrics::ConnectionType::kCellular,
+ utils::GetConnectionType(kNetCellular,
+ NetworkTethering::kUnknown));
+ EXPECT_EQ(metrics::ConnectionType::kTetheredEthernet,
+ utils::GetConnectionType(kNetEthernet,
+ NetworkTethering::kConfirmed));
+ EXPECT_EQ(metrics::ConnectionType::kTetheredWifi,
+ utils::GetConnectionType(kNetWifi,
+ NetworkTethering::kConfirmed));
+
+ // Ensure that we don't report tethered ethernet unless it's confirmed.
+ EXPECT_EQ(metrics::ConnectionType::kEthernet,
+ utils::GetConnectionType(kNetEthernet,
+ NetworkTethering::kNotDetected));
+ EXPECT_EQ(metrics::ConnectionType::kEthernet,
+ utils::GetConnectionType(kNetEthernet,
+ NetworkTethering::kSuspected));
+ EXPECT_EQ(metrics::ConnectionType::kEthernet,
+ utils::GetConnectionType(kNetEthernet,
+ NetworkTethering::kUnknown));
+
+ // Ditto for tethered wifi.
+ EXPECT_EQ(metrics::ConnectionType::kWifi,
+ utils::GetConnectionType(kNetWifi,
+ NetworkTethering::kNotDetected));
+ EXPECT_EQ(metrics::ConnectionType::kWifi,
+ utils::GetConnectionType(kNetWifi,
+ NetworkTethering::kSuspected));
+ EXPECT_EQ(metrics::ConnectionType::kWifi,
+ utils::GetConnectionType(kNetWifi,
+ NetworkTethering::kUnknown));
+}
+
} // namespace chromeos_update_engine