[CrOS Bluetooth] Add bluetooth pairing metrics
Bug: b:207588508
Change-Id: I23cbc59aa0af4d3898572698b3c50a6cccc53865
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3331228
Reviewed-by: Gordon Seto <gordonseto@google.com>
Reviewed-by: Kyle Horimoto <khorimoto@chromium.org>
Commit-Queue: Theo Johnson-kanu <tjohnsonkanu@google.com>
Cr-Commit-Position: refs/heads/main@{#952564}
diff --git a/chromeos/services/bluetooth_config/device_pairing_handler.cc b/chromeos/services/bluetooth_config/device_pairing_handler.cc
index 39002a0..878c39d 100644
--- a/chromeos/services/bluetooth_config/device_pairing_handler.cc
+++ b/chromeos/services/bluetooth_config/device_pairing_handler.cc
@@ -6,7 +6,10 @@
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
+#include "base/time/default_clock.h"
#include "components/device_event_log/device_event_log.h"
+#include "device/bluetooth/bluetooth_common.h"
+#include "device/bluetooth/chromeos/bluetooth_utils.h"
namespace chromeos {
namespace bluetooth_config {
@@ -29,6 +32,47 @@
passkey_string});
}
+device::BluetoothTransport GetBluetoothTransport(
+ device::BluetoothTransport type) {
+ switch (type) {
+ case device::BLUETOOTH_TRANSPORT_CLASSIC:
+ return device::BLUETOOTH_TRANSPORT_CLASSIC;
+ case device::BLUETOOTH_TRANSPORT_LE:
+ return device::BLUETOOTH_TRANSPORT_LE;
+ case device::BLUETOOTH_TRANSPORT_DUAL:
+ return device::BLUETOOTH_TRANSPORT_DUAL;
+ default:
+ return device::BLUETOOTH_TRANSPORT_INVALID;
+ }
+}
+
+mojom::PairingResult GetPairingResult(
+ absl::optional<device::ConnectionFailureReason> failure_reason) {
+ if (!failure_reason) {
+ return mojom::PairingResult::kSuccess;
+ }
+
+ switch (failure_reason.value()) {
+ case device::ConnectionFailureReason::kAuthTimeout:
+ FALLTHROUGH;
+ case device::ConnectionFailureReason::kAuthFailed:
+ return mojom::PairingResult::kAuthFailed;
+
+ case device::ConnectionFailureReason::kUnknownError:
+ FALLTHROUGH;
+ case device::ConnectionFailureReason::kSystemError:
+ FALLTHROUGH;
+ case device::ConnectionFailureReason::kFailed:
+ FALLTHROUGH;
+ case device::ConnectionFailureReason::kUnknownConnectionError:
+ FALLTHROUGH;
+ case device::ConnectionFailureReason::kUnsupportedDevice:
+ FALLTHROUGH;
+ case device::ConnectionFailureReason::kNotConnectable:
+ return mojom::PairingResult::kNonAuthFailure;
+ }
+}
+
} // namespace
DevicePairingHandler::DevicePairingHandler(
@@ -50,7 +94,7 @@
<< "Could not cancel pairing for device to due device no longer being "
"found, identifier: "
<< current_pairing_device_id_;
- FinishCurrentPairingRequest(mojom::PairingResult::kAuthFailed);
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kAuthFailed);
return;
}
device->CancelPairing();
@@ -72,6 +116,7 @@
// There should only be one PairDevice request at a time.
CHECK(current_pairing_device_id_.empty());
+ pairing_start_timestamp_ = base::Time();
pair_device_callback_ = std::move(callback);
delegate_.reset();
@@ -84,7 +129,7 @@
BLUETOOTH_LOG(ERROR) << "Pairing failed due to Bluetooth not being "
"enabled, device identifier: "
<< device_id;
- FinishCurrentPairingRequest(mojom::PairingResult::kNonAuthFailure);
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kFailed);
return;
}
@@ -95,7 +140,7 @@
BLUETOOTH_LOG(ERROR) << "Pairing failed due to device not being "
"found, identifier: "
<< device_id;
- FinishCurrentPairingRequest(mojom::PairingResult::kNonAuthFailure);
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kFailed);
return;
}
@@ -168,7 +213,7 @@
void DevicePairingHandler::OnDeviceConnect(
absl::optional<device::BluetoothDevice::ConnectErrorCode> error_code) {
if (!error_code.has_value()) {
- FinishCurrentPairingRequest(mojom::PairingResult::kSuccess);
+ FinishCurrentPairingRequest(absl::nullopt);
NotifyFinished();
return;
}
@@ -182,21 +227,26 @@
case ErrorCode::ERROR_AUTH_FAILED:
FALLTHROUGH;
case ErrorCode::ERROR_AUTH_REJECTED:
- FALLTHROUGH;
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kAuthFailed);
+ return;
case ErrorCode::ERROR_AUTH_TIMEOUT:
- FinishCurrentPairingRequest(mojom::PairingResult::kAuthFailed);
+ FinishCurrentPairingRequest(
+ device::ConnectionFailureReason::kAuthTimeout);
return;
case ErrorCode::ERROR_FAILED:
FALLTHROUGH;
case ErrorCode::ERROR_INPROGRESS:
- FALLTHROUGH;
- case ErrorCode::ERROR_UNKNOWN:
- FALLTHROUGH;
- case ErrorCode::ERROR_UNSUPPORTED_DEVICE:
- FinishCurrentPairingRequest(mojom::PairingResult::kNonAuthFailure);
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kFailed);
return;
-
+ case ErrorCode::ERROR_UNKNOWN:
+ FinishCurrentPairingRequest(
+ device::ConnectionFailureReason::kUnknownError);
+ return;
+ case ErrorCode::ERROR_UNSUPPORTED_DEVICE:
+ FinishCurrentPairingRequest(
+ device::ConnectionFailureReason::kUnsupportedDevice);
+ return;
default:
BLUETOOTH_LOG(ERROR) << "Error code is invalid.";
break;
@@ -210,7 +260,7 @@
<< "OnRequestPinCode failed due to device no longer being "
"found, identifier: "
<< current_pairing_device_id_;
- FinishCurrentPairingRequest(mojom::PairingResult::kNonAuthFailure);
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kFailed);
return;
}
@@ -224,7 +274,7 @@
<< "OnRequestPasskey failed due to device no longer being "
"found, identifier: "
<< current_pairing_device_id_;
- FinishCurrentPairingRequest(mojom::PairingResult::kNonAuthFailure);
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kFailed);
return;
}
@@ -245,7 +295,7 @@
<< "OnConfirmPairing failed due to device no longer being "
"found, identifier: "
<< current_pairing_device_id_;
- FinishCurrentPairingRequest(mojom::PairingResult::kNonAuthFailure);
+ FinishCurrentPairingRequest(device::ConnectionFailureReason::kFailed);
return;
}
@@ -256,9 +306,19 @@
}
void DevicePairingHandler::FinishCurrentPairingRequest(
- mojom::PairingResult result) {
+ absl::optional<device::ConnectionFailureReason> failure_reason) {
+ device::BluetoothDevice* device = FindDevice(current_pairing_device_id_);
current_pairing_device_id_.clear();
- std::move(pair_device_callback_).Run(result);
+
+ device::BluetoothTransport transport =
+ device ? device->GetType()
+ : device::BluetoothTransport::BLUETOOTH_TRANSPORT_INVALID;
+
+ device::RecordPairingResult(
+ failure_reason, GetBluetoothTransport(transport),
+ base::DefaultClock::GetInstance()->Now() - pairing_start_timestamp_);
+
+ std::move(pair_device_callback_).Run(GetPairingResult(failure_reason));
}
void DevicePairingHandler::OnDelegateDisconnect() {
diff --git a/chromeos/services/bluetooth_config/device_pairing_handler.h b/chromeos/services/bluetooth_config/device_pairing_handler.h
index 61e5572..c9d0e42 100644
--- a/chromeos/services/bluetooth_config/device_pairing_handler.h
+++ b/chromeos/services/bluetooth_config/device_pairing_handler.h
@@ -11,6 +11,7 @@
#include "chromeos/services/bluetooth_config/adapter_state_controller.h"
#include "chromeos/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom.h"
#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/chromeos/bluetooth_utils.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace chromeos {
@@ -86,9 +87,10 @@
void OnRequestPasskey(const std::string& passkey);
void OnConfirmPairing(bool confirmed);
- // Invokes |pair_device_callback_| with |result| and resets
- // this class' state to be ready for another pairing request.
- void FinishCurrentPairingRequest(mojom::PairingResult result);
+ // Invokes |pair_device_callback_| and resets this class' state to be ready
+ // for another pairing request.
+ void FinishCurrentPairingRequest(
+ absl::optional<device::ConnectionFailureReason> failure_reason);
void OnDelegateDisconnect();
@@ -97,6 +99,8 @@
// Flushes queued Mojo messages in unit tests.
void FlushForTesting();
+ base::Time pairing_start_timestamp_;
+
// The identifier of the device currently being paired with. This is null if
// there is no in-progress pairing attempt.
std::string current_pairing_device_id_;
diff --git a/chromeos/services/bluetooth_config/device_pairing_handler_impl_unittest.cc b/chromeos/services/bluetooth_config/device_pairing_handler_impl_unittest.cc
index 2cd20d4..171f039 100644
--- a/chromeos/services/bluetooth_config/device_pairing_handler_impl_unittest.cc
+++ b/chromeos/services/bluetooth_config/device_pairing_handler_impl_unittest.cc
@@ -6,10 +6,12 @@
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "chromeos/services/bluetooth_config/fake_adapter_state_controller.h"
#include "chromeos/services/bluetooth_config/fake_device_pairing_delegate.h"
#include "chromeos/services/bluetooth_config/fake_key_entered_handler.h"
+#include "device/bluetooth/chromeos/bluetooth_utils.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/bluetooth/test/mock_bluetooth_device.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -70,6 +72,18 @@
void DestroyHandler() { device_pairing_handler_.reset(); }
+ void CheckPairingHistograms(device::BluetoothTransportType type,
+ int type_count,
+ int failure_count,
+ int success_count) {
+ histogram_tester.ExpectBucketCount(
+ "Bluetooth.ChromeOS.Pairing.TransportType", type, type_count);
+ histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.Pairing.Result",
+ false, failure_count);
+ histogram_tester.ExpectBucketCount("Bluetooth.ChromeOS.Pairing.Result",
+ true, success_count);
+ }
+
void AddDevice(std::string* id_out,
AuthType auth_type,
uint32_t passkey = kDefaultPinCodeNum) {
@@ -141,6 +155,10 @@
.WillByDefault(testing::Invoke(
[this](const uint32_t passkey) { received_passkey_ = passkey; }));
+ ON_CALL(*mock_device, GetType()).WillByDefault(testing::Invoke([]() {
+ return device::BluetoothTransport::BLUETOOTH_TRANSPORT_CLASSIC;
+ }));
+
mock_devices_.push_back(std::move(mock_device));
}
@@ -200,6 +218,7 @@
}
std::string received_pin_code() const { return received_pin_code_; }
uint32_t received_passkey() const { return received_passkey_; }
+ base::HistogramTester histogram_tester;
private:
std::vector<const device::BluetoothDevice*> GetMockDevices() {
@@ -256,6 +275,10 @@
EXPECT_EQ(pairing_result(), mojom::PairingResult::kNonAuthFailure);
EXPECT_EQ(num_pairing_attempt_finished_calls(), 0u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
+
std::unique_ptr<FakeDevicePairingDelegate> delegate2 = PairDevice(device_id2);
EXPECT_TRUE(delegate2->IsMojoPipeConnected());
@@ -263,6 +286,10 @@
InvokePendingConnectCallback(/*success=*/true);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kSuccess);
EXPECT_EQ(num_pairing_attempt_finished_calls(), 1u);
+
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/2, /*failure_count=*/1,
+ /*success_count=*/1);
}
TEST_F(DevicePairingHandlerImplTest, DisableBluetoothBeforePairing) {
@@ -278,6 +305,11 @@
EXPECT_FALSE(HasPendingConnectCallback());
EXPECT_EQ(pairing_result(), mojom::PairingResult::kNonAuthFailure);
EXPECT_EQ(num_pairing_attempt_finished_calls(), 0u);
+
+ // Pairing result metric is only recorded for valid transport types.
+ CheckPairingHistograms(device::BluetoothTransportType::kInvalid,
+ /*type_count=*/1, /*failure_count=*/0,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, DisableBluetoothDuringPairing) {
@@ -295,6 +327,9 @@
EXPECT_EQ(num_cancel_pairing_calls(), 1u);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
EXPECT_EQ(num_pairing_attempt_finished_calls(), 0u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, DestroyHandlerBeforeConnectFinishes) {
@@ -311,6 +346,9 @@
// Destroying the handler should call OnPairingAttemptFinished();
EXPECT_EQ(num_pairing_attempt_finished_calls(), 1u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, DestroyHandlerAfterConnectFinishes) {
@@ -332,6 +370,9 @@
// Destroying the handler shouldn't call OnPairingAttemptFinished();
EXPECT_EQ(num_pairing_attempt_finished_calls(), 1u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/0,
+ /*success_count=*/1);
}
TEST_F(DevicePairingHandlerImplTest, DisconnectDelegateBeforeConnectFinishes) {
@@ -349,6 +390,9 @@
// Disconnecting the pipe should not call OnPairingAttemptFinished().
EXPECT_EQ(num_pairing_attempt_finished_calls(), 0u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest,
@@ -369,6 +413,9 @@
// Disconnecting the pipe should not call OnPairingAttemptFinished().
EXPECT_EQ(num_pairing_attempt_finished_calls(), 0u);
+ CheckPairingHistograms(device::BluetoothTransportType::kInvalid,
+ /*type_count=*/1, /*failure_count=*/0,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest,
@@ -389,6 +436,9 @@
// Disconnecting the pipe should not call OnPairingAttemptFinished().
EXPECT_EQ(num_pairing_attempt_finished_calls(), 0u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairDeviceNotFound) {
@@ -396,6 +446,9 @@
EXPECT_FALSE(HasPendingConnectCallback());
EXPECT_EQ(pairing_result(), mojom::PairingResult::kNonAuthFailure);
+ CheckPairingHistograms(device::BluetoothTransportType::kInvalid,
+ /*type_count=*/1, /*failure_count=*/0,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthRequestPinCode) {
@@ -410,6 +463,9 @@
InvokePendingConnectCallback(/*success=*/false);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthRequestPinCodeRemoveDevice) {
@@ -427,6 +483,9 @@
// Failure result should be returned.
EXPECT_TRUE(received_pin_code().empty());
EXPECT_EQ(pairing_result(), mojom::PairingResult::kNonAuthFailure);
+ CheckPairingHistograms(device::BluetoothTransportType::kInvalid,
+ /*type_count=*/1, /*failure_count=*/0,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthRequestPasskey) {
@@ -441,6 +500,9 @@
InvokePendingConnectCallback(/*success=*/false);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthRequestPasskeyRemoveDevice) {
@@ -458,6 +520,9 @@
// Failure result should be returned.
EXPECT_EQ(received_passkey(), kUninitializedPasskey);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kNonAuthFailure);
+ CheckPairingHistograms(device::BluetoothTransportType::kInvalid,
+ /*type_count=*/1, /*failure_count=*/0,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthRequestPasskeyInvalidKey) {
@@ -479,6 +544,9 @@
// CancelPairing() should not be called again since we already cancelled the
// pairing.
EXPECT_EQ(num_cancel_pairing_calls(), 1u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthDisplayPinCode) {
@@ -497,6 +565,9 @@
InvokePendingConnectCallback(/*success=*/false);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthDisplayPinCodeDisconnectHandler) {
@@ -515,6 +586,11 @@
EnterKeys(device_id, /*num_keys_entered=*/6u);
// Number of keys entered should still be zero since pipe is disconnected.
EXPECT_EQ(delegate->key_entered_handler()->num_keys_entered(), 0);
+
+ // Metrics is not recorded because pairing did not finish.
+ CheckPairingHistograms(device::BluetoothTransportType::kInvalid,
+ /*type_count=*/0, /*failure_count=*/0,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthDisplayPasskey) {
@@ -533,6 +609,9 @@
InvokePendingConnectCallback(/*success=*/false);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthDisplayPasskeyPadZeroes) {
@@ -547,6 +626,9 @@
InvokePendingConnectCallback(/*success=*/false);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
// Pair a new device.
std::string device_id2;
@@ -557,6 +639,10 @@
// Passkey displayed should be a 6-digit number, padded with zeroes if needed.
EXPECT_EQ(delegate2->displayed_passkey(), "000000");
EXPECT_TRUE(delegate2->key_entered_handler()->IsMojoPipeConnected());
+ // Expect value to be 1 since pairing was not finished.
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthConfirmPasskey) {
@@ -574,6 +660,9 @@
InvokePendingConnectCallback(/*success=*/false);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
// Pair a new device.
std::string device_id2;
@@ -592,6 +681,9 @@
// ConfirmPairing() should not be called again, CancelPairing() should.
EXPECT_EQ(num_confirm_pairing_calls(), 1u);
EXPECT_EQ(num_cancel_pairing_calls(), 1u);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/2, /*failure_count=*/2,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthConfirmPasskeyRemoveDevice) {
@@ -611,6 +703,9 @@
// Failure result should be returned.
EXPECT_EQ(num_confirm_pairing_calls(), 0u);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kNonAuthFailure);
+ CheckPairingHistograms(device::BluetoothTransportType::kInvalid,
+ /*type_count=*/1, /*failure_count=*/0,
+ /*success_count=*/0);
}
TEST_F(DevicePairingHandlerImplTest, PairAuthAuthorizePairing) {
@@ -626,6 +721,9 @@
InvokePendingConnectCallback(/*success=*/false);
EXPECT_EQ(pairing_result(), mojom::PairingResult::kAuthFailed);
+ CheckPairingHistograms(device::BluetoothTransportType::kClassic,
+ /*type_count=*/1, /*failure_count=*/1,
+ /*success_count=*/0);
}
} // namespace bluetooth_config
diff --git a/device/bluetooth/chromeos/bluetooth_utils.cc b/device/bluetooth/chromeos/bluetooth_utils.cc
index b0ab4d9a..02c5939c 100644
--- a/device/bluetooth/chromeos/bluetooth_utils.cc
+++ b/device/bluetooth/chromeos/bluetooth_utils.cc
@@ -39,18 +39,6 @@
constexpr base::TimeDelta kMaxDeviceSelectionDuration = base::Seconds(30);
-// This enum is tied directly to a UMA enum defined in
-// //tools/metrics/histograms/enums.xml, and should always reflect it (do not
-// change one without changing the other).
-enum class BluetoothTransportType {
- kUnknown = 0,
- kClassic = 1,
- kLE = 2,
- kDual = 3,
- kInvalid = 4,
- kMaxValue = kInvalid
-};
-
// Get limited number of devices from |devices| and
// prioritize paired/connecting devices over other devices.
BluetoothAdapter::DeviceList GetLimitedNumDevices(
diff --git a/device/bluetooth/chromeos/bluetooth_utils.h b/device/bluetooth/chromeos/bluetooth_utils.h
index b78a3e4..d1ec8ae 100644
--- a/device/bluetooth/chromeos/bluetooth_utils.h
+++ b/device/bluetooth/chromeos/bluetooth_utils.h
@@ -98,6 +98,18 @@
kMaxValue = kSuccess,
};
+// This enum is tied directly to a UMA enum defined in
+// //tools/metrics/histograms/enums.xml, and should always reflect it (do not
+// change one without changing the other).
+enum class BluetoothTransportType {
+ kUnknown = 0,
+ kClassic = 1,
+ kLE = 2,
+ kDual = 3,
+ kInvalid = 4,
+ kMaxValue = kInvalid
+};
+
// Return filtered devices based on the filter type and max number of devices.
DEVICE_BLUETOOTH_EXPORT device::BluetoothAdapter::DeviceList
FilterBluetoothDeviceList(const BluetoothAdapter::DeviceList& devices,