Avi Drissman | 0db8484 | 2022-09-13 19:47:04 | [diff] [blame] | 1 | // Copyright 2018 The Chromium Authors |
Sarah Hu | ad95e80 | 2018-04-12 06:24:29 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "device/bluetooth/chromeos/bluetooth_utils.h" |
| 6 | |
Lei Zhang | 589fe0a | 2021-05-12 03:17:43 | [diff] [blame] | 7 | #include "base/containers/contains.h" |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 8 | #include "base/containers/fixed_flat_set.h" |
Sonny Sasaka | 7fecfeda | 2018-07-11 23:47:55 | [diff] [blame] | 9 | #include "base/feature_list.h" |
Ryan Hansberry | 27c9c58 | 2019-03-22 04:38:52 | [diff] [blame] | 10 | #include "base/metrics/field_trial_params.h" |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 11 | #include "base/metrics/histogram_functions.h" |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 12 | #include "base/strings/strcat.h" |
Ryan Hansberry | 27c9c58 | 2019-03-22 04:38:52 | [diff] [blame] | 13 | #include "base/strings/string_number_conversions.h" |
| 14 | #include "base/strings/string_split.h" |
| 15 | #include "base/strings/string_util.h" |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 16 | #include "base/time/time.h" |
Eric Willigers | 4f1da11 | 2022-03-28 22:55:28 | [diff] [blame] | 17 | #include "build/chromeos_buildflags.h" |
Samuel Huang | 81b7b32 | 2021-11-19 06:19:55 | [diff] [blame] | 18 | #include "chromeos/constants/chromeos_features.h" |
Eric Willigers | 4f1da11 | 2022-03-28 22:55:28 | [diff] [blame] | 19 | #include "device/base/features.h" |
Anton Bikineev | 15c0700 | 2021-05-15 17:55:02 | [diff] [blame] | 20 | #include "third_party/abseil-cpp/absl/types/optional.h" |
Alain Michaud | da9d491 | 2020-03-09 20:55:30 | [diff] [blame] | 21 | |
Samuel Huang | 1f2e5dc | 2021-11-12 02:05:33 | [diff] [blame] | 22 | #if BUILDFLAG(IS_CHROMEOS_ASH) |
Julie Jeongeun Kim | db566246 | 2023-11-22 07:32:07 | [diff] [blame] | 23 | #include <string_view> |
| 24 | |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 25 | #include "ash/constants/ash_features.h" |
Samuel Huang | 1f2e5dc | 2021-11-12 02:05:33 | [diff] [blame] | 26 | #include "ash/constants/ash_switches.h" |
Chad Duffin | f716657 | 2023-07-17 17:37:15 | [diff] [blame] | 27 | #include "chromeos/ash/services/nearby/public/cpp/nearby_client_uuids.h" |
| 28 | #include "chromeos/ash/services/secure_channel/public/cpp/shared/ble_constants.h" |
Samuel Huang | 1f2e5dc | 2021-11-12 02:05:33 | [diff] [blame] | 29 | #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| 30 | |
| 31 | #if BUILDFLAG(IS_CHROMEOS_LACROS) |
Andrea Orru | 66066fcd | 2022-07-21 03:45:54 | [diff] [blame] | 32 | #include "chromeos/startup/browser_params_proxy.h" |
Samuel Huang | 1f2e5dc | 2021-11-12 02:05:33 | [diff] [blame] | 33 | #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| 34 | |
Sarah Hu | ad95e80 | 2018-04-12 06:24:29 | [diff] [blame] | 35 | namespace device { |
| 36 | |
| 37 | namespace { |
| 38 | |
Sarah Hu | 81c120a | 2018-05-10 00:33:52 | [diff] [blame] | 39 | // https://www.bluetooth.com/specifications/gatt/services. |
| 40 | const char kHIDServiceUUID[] = "1812"; |
| 41 | |
| 42 | // https://www.bluetooth.com/specifications/assigned-numbers/16-bit-uuids-for-sdos. |
| 43 | const char kSecurityKeyServiceUUID[] = "FFFD"; |
| 44 | |
Peter Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame] | 45 | constexpr base::TimeDelta kMaxDeviceSelectionDuration = base::Seconds(30); |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 46 | |
Michael Sun | d59d5bd | 2023-09-06 04:14:28 | [diff] [blame] | 47 | constexpr uint8_t kLimitedDiscoveryFlag = 0x01; |
| 48 | constexpr uint8_t kGeneralDiscoveryFlag = 0x02; |
| 49 | |
Sarah Hu | ad95e80 | 2018-04-12 06:24:29 | [diff] [blame] | 50 | // Get limited number of devices from |devices| and |
| 51 | // prioritize paired/connecting devices over other devices. |
| 52 | BluetoothAdapter::DeviceList GetLimitedNumDevices( |
| 53 | size_t max_device_num, |
| 54 | const BluetoothAdapter::DeviceList& devices) { |
| 55 | // If |max_device_num| is 0, it means there's no limit. |
| 56 | if (max_device_num == 0) |
| 57 | return devices; |
| 58 | |
| 59 | BluetoothAdapter::DeviceList result; |
| 60 | for (BluetoothDevice* device : devices) { |
| 61 | if (result.size() == max_device_num) |
| 62 | break; |
| 63 | |
| 64 | if (device->IsPaired() || device->IsConnecting()) |
| 65 | result.push_back(device); |
| 66 | } |
| 67 | |
| 68 | for (BluetoothDevice* device : devices) { |
| 69 | if (result.size() == max_device_num) |
| 70 | break; |
| 71 | |
| 72 | if (!device->IsPaired() && !device->IsConnecting()) |
| 73 | result.push_back(device); |
| 74 | } |
| 75 | |
| 76 | return result; |
| 77 | } |
| 78 | |
| 79 | // Filter out unknown devices from the list. |
| 80 | BluetoothAdapter::DeviceList FilterUnknownDevices( |
| 81 | const BluetoothAdapter::DeviceList& devices) { |
Samuel Huang | 1f2e5dc | 2021-11-12 02:05:33 | [diff] [blame] | 82 | #if BUILDFLAG(IS_CHROMEOS_ASH) |
Henrique Ferreiro | 93dd33b | 2022-01-18 16:06:45 | [diff] [blame] | 83 | if (ash::switches::IsUnfilteredBluetoothDevicesEnabled()) |
Sonny Sasaka | 7fecfeda | 2018-07-11 23:47:55 | [diff] [blame] | 84 | return devices; |
Samuel Huang | 1f2e5dc | 2021-11-12 02:05:33 | [diff] [blame] | 85 | #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| 86 | |
| 87 | #if BUILDFLAG(IS_CHROMEOS_LACROS) |
Andrea Orru | 66066fcd | 2022-07-21 03:45:54 | [diff] [blame] | 88 | if (chromeos::BrowserParamsProxy::Get() |
| 89 | ->IsUnfilteredBluetoothDeviceEnabled()) { |
Samuel Huang | 1f2e5dc | 2021-11-12 02:05:33 | [diff] [blame] | 90 | return devices; |
| 91 | } |
| 92 | #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
Sonny Sasaka | 7fecfeda | 2018-07-11 23:47:55 | [diff] [blame] | 93 | |
Sarah Hu | ad95e80 | 2018-04-12 06:24:29 | [diff] [blame] | 94 | BluetoothAdapter::DeviceList result; |
| 95 | for (BluetoothDevice* device : devices) { |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 96 | if (device::IsUnsupportedDevice(device)) |
Ryan Hansberry | 2e46246 | 2019-06-19 18:03:11 | [diff] [blame] | 97 | continue; |
Ryan Hansberry | 2e46246 | 2019-06-19 18:03:11 | [diff] [blame] | 98 | |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 99 | result.push_back(device); |
Sarah Hu | ad95e80 | 2018-04-12 06:24:29 | [diff] [blame] | 100 | } |
| 101 | return result; |
| 102 | } |
| 103 | |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 104 | void RecordPairingDuration(const std::string& histogram_name, |
| 105 | base::TimeDelta pairing_duration) { |
| 106 | base::UmaHistogramCustomTimes(histogram_name, pairing_duration, |
Peter Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame] | 107 | base::Milliseconds(1) /* min */, |
| 108 | base::Seconds(30) /* max */, 50 /* buckets */); |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | void RecordPairingTransport(BluetoothTransport transport) { |
| 112 | BluetoothTransportType type; |
| 113 | switch (transport) { |
| 114 | case BLUETOOTH_TRANSPORT_CLASSIC: |
| 115 | type = BluetoothTransportType::kClassic; |
| 116 | break; |
| 117 | case BLUETOOTH_TRANSPORT_LE: |
| 118 | type = BluetoothTransportType::kLE; |
| 119 | break; |
| 120 | case BLUETOOTH_TRANSPORT_DUAL: |
| 121 | type = BluetoothTransportType::kDual; |
| 122 | break; |
| 123 | case BLUETOOTH_TRANSPORT_INVALID: |
| 124 | type = BluetoothTransportType::kInvalid; |
| 125 | break; |
| 126 | default: |
| 127 | type = BluetoothTransportType::kUnknown; |
| 128 | break; |
| 129 | } |
| 130 | |
| 131 | base::UmaHistogramEnumeration("Bluetooth.ChromeOS.Pairing.TransportType", |
| 132 | type); |
| 133 | } |
| 134 | |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 135 | void RecordDeviceSelectionDuration(const std::string& histogram_name, |
| 136 | base::TimeDelta duration) { |
| 137 | base::UmaHistogramCustomTimes( |
Peter Kasting | e5a38ed | 2021-10-02 03:06:35 | [diff] [blame] | 138 | histogram_name, duration, base::Milliseconds(1) /* min */, |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 139 | kMaxDeviceSelectionDuration /* max */, 50 /* buckets */); |
| 140 | } |
| 141 | |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 142 | std::string GetTransportName(BluetoothTransport transport) { |
| 143 | switch (transport) { |
| 144 | case BluetoothTransport::BLUETOOTH_TRANSPORT_CLASSIC: |
| 145 | return "Classic"; |
| 146 | case BluetoothTransport::BLUETOOTH_TRANSPORT_LE: |
| 147 | return "BLE"; |
| 148 | case BluetoothTransport::BLUETOOTH_TRANSPORT_DUAL: |
| 149 | return "Dual"; |
Theo Johnson-Kanu | 37fd36a | 2022-02-02 22:03:35 | [diff] [blame] | 150 | case BLUETOOTH_TRANSPORT_INVALID: |
| 151 | return "Invalid"; |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 152 | default: |
Theo Johnson-Kanu | 37fd36a | 2022-02-02 22:03:35 | [diff] [blame] | 153 | // A transport type of other is unexpected, and no success |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 154 | // metric for it exists. |
| 155 | return ""; |
| 156 | } |
| 157 | } |
| 158 | |
Theo Johnson-Kanu | 0a34d73 | 2023-03-23 20:16:09 | [diff] [blame] | 159 | void EmitFilteredFailureReason(ConnectionFailureReason failure_reason, |
| 160 | const std::string& transport_name) { |
| 161 | switch (failure_reason) { |
| 162 | case ConnectionFailureReason::kAuthCanceled: |
| 163 | [[fallthrough]]; |
| 164 | case ConnectionFailureReason::kAuthRejected: |
| 165 | return; |
| 166 | case ConnectionFailureReason::kUnknownError: |
| 167 | [[fallthrough]]; |
| 168 | case ConnectionFailureReason::kAuthFailed: |
| 169 | [[fallthrough]]; |
| 170 | case ConnectionFailureReason::kAuthTimeout: |
| 171 | [[fallthrough]]; |
| 172 | case ConnectionFailureReason::kUnknownConnectionError: |
| 173 | [[fallthrough]]; |
| 174 | case ConnectionFailureReason::kUnsupportedDevice: |
| 175 | [[fallthrough]]; |
| 176 | case ConnectionFailureReason::kNotConnectable: |
| 177 | [[fallthrough]]; |
| 178 | case ConnectionFailureReason::kSystemError: |
| 179 | [[fallthrough]]; |
| 180 | case ConnectionFailureReason::kFailed: |
| 181 | [[fallthrough]]; |
| 182 | case ConnectionFailureReason::kInprogress: |
| 183 | const std::string result_histogram_name_prefix = |
| 184 | "Bluetooth.ChromeOS.Pairing.Result"; |
| 185 | base::UmaHistogramEnumeration( |
| 186 | result_histogram_name_prefix + ".FilteredFailureReason", |
| 187 | failure_reason); |
| 188 | base::UmaHistogramEnumeration(result_histogram_name_prefix + |
| 189 | ".FilteredFailureReason." + |
| 190 | transport_name, |
| 191 | failure_reason); |
| 192 | return; |
| 193 | } |
| 194 | NOTREACHED(); |
| 195 | } |
| 196 | |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 197 | #if BUILDFLAG(IS_CHROMEOS_ASH) |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 198 | bool IsPolyDevice(const device::BluetoothDevice* device) { |
| 199 | // OUI portions of Bluetooth addresses for devices manufactured by Poly. See |
| 200 | // https://standards-oui.ieee.org/. |
Julie Jeongeun Kim | db566246 | 2023-11-22 07:32:07 | [diff] [blame] | 201 | constexpr auto kPolyOuis = base::MakeFixedFlatSet<std::string_view>( |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 202 | {"64:16:7F", "48:25:67", "00:04:F2"}); |
| 203 | |
| 204 | return base::Contains(kPolyOuis, device->GetOuiPortionOfBluetoothAddress()); |
| 205 | } |
Andrew Dear | 283c6e7 | 2022-12-01 17:49:54 | [diff] [blame] | 206 | #endif |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 207 | |
Archie | ef62df35 | 2024-01-24 09:23:54 | [diff] [blame^] | 208 | // Provide heuristics for which transport to use for a dual device |
| 209 | BluetoothTransport InferDeviceTransport(const device::BluetoothDevice* device) { |
| 210 | if (device->GetType() != BLUETOOTH_TRANSPORT_DUAL) { |
| 211 | return device->GetType(); |
| 212 | } |
| 213 | |
| 214 | #if BUILDFLAG(IS_CHROMEOS) |
| 215 | // Random address type indicates LE device. |
| 216 | if (device->GetAddressType() == |
| 217 | BluetoothDevice::AddressType::ADDR_TYPE_RANDOM) { |
| 218 | return BLUETOOTH_TRANSPORT_LE; |
| 219 | } |
| 220 | #endif |
| 221 | |
| 222 | // Devices without type/appearance most likely signals that it is truly only |
| 223 | // a LE advertisement for a peripheral which is active, but not pairable. Many |
| 224 | // popular headphones behave in this exact way. Mark as invalid until they |
| 225 | // provide a type/appearance; this means they've become pairable. See |
| 226 | // https://crrev.com/c/1656971 for more. |
| 227 | if (device->GetDeviceType() == BluetoothDeviceType::UNKNOWN) { |
| 228 | return BLUETOOTH_TRANSPORT_INVALID; |
| 229 | } |
| 230 | |
| 231 | return BLUETOOTH_TRANSPORT_CLASSIC; |
| 232 | } |
| 233 | |
Sarah Hu | ad95e80 | 2018-04-12 06:24:29 | [diff] [blame] | 234 | } // namespace |
| 235 | |
| 236 | device::BluetoothAdapter::DeviceList FilterBluetoothDeviceList( |
| 237 | const BluetoothAdapter::DeviceList& devices, |
| 238 | BluetoothFilterType filter_type, |
| 239 | int max_devices) { |
| 240 | BluetoothAdapter::DeviceList filtered_devices = |
| 241 | filter_type == BluetoothFilterType::KNOWN ? FilterUnknownDevices(devices) |
| 242 | : devices; |
| 243 | return GetLimitedNumDevices(max_devices, filtered_devices); |
| 244 | } |
| 245 | |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 246 | bool IsUnsupportedDevice(const device::BluetoothDevice* device) { |
| 247 | #if BUILDFLAG(IS_CHROMEOS_ASH) |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 248 | if (ash::switches::IsUnfilteredBluetoothDevicesEnabled()) { |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 249 | return false; |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 250 | } |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 251 | #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| 252 | |
| 253 | #if BUILDFLAG(IS_CHROMEOS_LACROS) |
Andrea Orru | 66066fcd | 2022-07-21 03:45:54 | [diff] [blame] | 254 | if (chromeos::BrowserParamsProxy::Get() |
| 255 | ->IsUnfilteredBluetoothDeviceEnabled()) { |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 256 | return false; |
| 257 | } |
| 258 | #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| 259 | |
Andrew Dear | 283c6e7 | 2022-12-01 17:49:54 | [diff] [blame] | 260 | #if BUILDFLAG(IS_CHROMEOS_ASH) |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 261 | // Never filter out Poly devices; this requires a special case since these |
| 262 | // devices often identify themselves as phones, which are disallowed below. |
| 263 | // See b/228118615. |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 264 | if (IsPolyDevice(device)) { |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 265 | return false; |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 266 | } |
| 267 | #endif |
| 268 | |
| 269 | #if BUILDFLAG(IS_CHROMEOS) |
| 270 | // Always allow bonded devices to appear in the UI. |
| 271 | if (device->IsBonded()) { |
| 272 | return false; |
| 273 | } |
Andrew Dear | 283c6e7 | 2022-12-01 17:49:54 | [diff] [blame] | 274 | #endif |
Kyle Horimoto | 419ea9a | 2022-05-13 02:10:08 | [diff] [blame] | 275 | |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 276 | // Always filter out laptops, etc. There is no intended use case or |
| 277 | // Bluetooth profile in this context. |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 278 | if (device->GetDeviceType() == BluetoothDeviceType::COMPUTER) { |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 279 | return true; |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 280 | } |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 281 | |
| 282 | // Always filter out phones. There is no intended use case or Bluetooth |
| 283 | // profile in this context. |
| 284 | if (base::FeatureList::IsEnabled(chromeos::features::kBluetoothPhoneFilter) && |
| 285 | device->GetDeviceType() == BluetoothDeviceType::PHONE) { |
| 286 | return true; |
| 287 | } |
| 288 | |
Chad Duffin | f716657 | 2023-07-17 17:37:15 | [diff] [blame] | 289 | #if BUILDFLAG(IS_CHROMEOS_ASH) |
| 290 | const BluetoothDevice::UUIDSet& uuids = device->GetUUIDs(); |
| 291 | |
| 292 | // These UUIDs are specific to Nearby Share and Phone Hub and are used to |
| 293 | // identify devices that should be filtered from the UI that otherwise would |
| 294 | // not have been correctly identified. These devices should always be filtered |
| 295 | // from the UI. For more information see b/219627324. |
| 296 | for (const auto& uuid : ash::nearby::GetNearbyClientUuids()) { |
| 297 | if (uuids.contains(uuid)) { |
| 298 | return true; |
| 299 | } |
| 300 | } |
| 301 | if (uuids.contains(BluetoothUUID(ash::secure_channel::kGattServerUuid))) { |
| 302 | return true; |
| 303 | } |
| 304 | #endif |
| 305 | |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 306 | #if !BUILDFLAG(IS_CHROMEOS) |
Chad Duffin | db4d352 | 2023-03-20 19:27:44 | [diff] [blame] | 307 | // Allow paired devices which are not filtered above to appear in the UI. |
| 308 | if (device->IsPaired()) { |
| 309 | return false; |
| 310 | } |
| 311 | #endif |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 312 | |
Archie | ef62df35 | 2024-01-24 09:23:54 | [diff] [blame^] | 313 | switch (InferDeviceTransport(device)) { |
Michael Sun | d59d5bd | 2023-09-06 04:14:28 | [diff] [blame] | 314 | // For LE devices, check the discoverable flag and UUIDs. |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 315 | case BLUETOOTH_TRANSPORT_LE: |
Michael Sun | d59d5bd | 2023-09-06 04:14:28 | [diff] [blame] | 316 | // Hide the LE device that mark itself as non-discoverble. |
| 317 | if (device->GetAdvertisingDataFlags().has_value()) { |
| 318 | if (!((kLimitedDiscoveryFlag | kGeneralDiscoveryFlag) & |
| 319 | device->GetAdvertisingDataFlags().value())) { |
| 320 | return true; |
| 321 | } |
| 322 | } |
| 323 | // Check the service UUID to determine if it supports HID or second factor |
| 324 | // authenticator (security key). |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 325 | if (base::Contains(device->GetUUIDs(), |
| 326 | device::BluetoothUUID(kHIDServiceUUID)) || |
| 327 | base::Contains(device->GetUUIDs(), |
| 328 | device::BluetoothUUID(kSecurityKeyServiceUUID))) { |
| 329 | return false; |
| 330 | } |
| 331 | break; |
| 332 | // For classic mode devices, only filter out if the name is empty because |
| 333 | // the device could have an unknown or even known type and still also |
| 334 | // provide audio/HID functionality. |
| 335 | case BLUETOOTH_TRANSPORT_CLASSIC: |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 336 | if (device->GetName()) { |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 337 | return false; |
Chad Duffin | 77a8537 | 2023-08-17 10:05:16 | [diff] [blame] | 338 | } |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 339 | break; |
Archie | ef62df35 | 2024-01-24 09:23:54 | [diff] [blame^] | 340 | // Otherwise, they are invalid, so filter them out. |
| 341 | default: |
Gordon Seto | c130899 | 2021-12-14 19:27:20 | [diff] [blame] | 342 | break; |
| 343 | } |
| 344 | |
| 345 | return true; |
| 346 | } |
| 347 | |
Anton Bikineev | 15c0700 | 2021-05-15 17:55:02 | [diff] [blame] | 348 | void RecordPairingResult(absl::optional<ConnectionFailureReason> failure_reason, |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 349 | BluetoothTransport transport, |
| 350 | base::TimeDelta duration) { |
| 351 | RecordPairingTransport(transport); |
| 352 | |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 353 | std::string transport_name = GetTransportName(transport); |
| 354 | if (transport_name.empty()) { |
| 355 | return; |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 356 | } |
| 357 | |
Ryan Hansberry | b9e645f | 2020-04-07 21:10:13 | [diff] [blame] | 358 | bool success = !failure_reason.has_value(); |
| 359 | std::string result_histogram_name_prefix = |
| 360 | "Bluetooth.ChromeOS.Pairing.Result"; |
| 361 | |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 362 | base::UmaHistogramBoolean(result_histogram_name_prefix, success); |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 363 | base::UmaHistogramBoolean(result_histogram_name_prefix + "." + transport_name, |
| 364 | success); |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 365 | |
| 366 | std::string duration_histogram_name_prefix = |
| 367 | "Bluetooth.ChromeOS.Pairing.Duration"; |
| 368 | std::string success_histogram_name = success ? "Success" : "Failure"; |
| 369 | |
| 370 | std::string base_histogram_name = |
| 371 | duration_histogram_name_prefix + "." + success_histogram_name; |
| 372 | RecordPairingDuration(base_histogram_name, duration); |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 373 | RecordPairingDuration(base_histogram_name + "." + transport_name, duration); |
Ryan Hansberry | b9e645f | 2020-04-07 21:10:13 | [diff] [blame] | 374 | |
| 375 | if (!success) { |
| 376 | base::UmaHistogramEnumeration( |
| 377 | result_histogram_name_prefix + ".FailureReason", *failure_reason); |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 378 | base::UmaHistogramEnumeration( |
| 379 | result_histogram_name_prefix + ".FailureReason." + transport_name, |
| 380 | *failure_reason); |
Theo Johnson-Kanu | 0a34d73 | 2023-03-23 20:16:09 | [diff] [blame] | 381 | EmitFilteredFailureReason(*failure_reason, transport_name); |
Ryan Hansberry | b9e645f | 2020-04-07 21:10:13 | [diff] [blame] | 382 | } |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 383 | } |
| 384 | |
Ryan Hansberry | b9e645f | 2020-04-07 21:10:13 | [diff] [blame] | 385 | void RecordUserInitiatedReconnectionAttemptResult( |
Anton Bikineev | 15c0700 | 2021-05-15 17:55:02 | [diff] [blame] | 386 | absl::optional<ConnectionFailureReason> failure_reason, |
Theo Johnson-Kanu | d95038f | 2021-07-20 17:45:12 | [diff] [blame] | 387 | UserInitiatedReconnectionUISurfaces surface) { |
Ryan Hansberry | b9e645f | 2020-04-07 21:10:13 | [diff] [blame] | 388 | bool success = !failure_reason.has_value(); |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 389 | std::string base_histogram_name = |
| 390 | "Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Result"; |
Ryan Hansberry | b9e645f | 2020-04-07 21:10:13 | [diff] [blame] | 391 | |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 392 | base::UmaHistogramBoolean(base_histogram_name, success); |
| 393 | |
| 394 | std::string surface_name = |
Theo Johnson-Kanu | d95038f | 2021-07-20 17:45:12 | [diff] [blame] | 395 | (surface == UserInitiatedReconnectionUISurfaces::kSettings |
| 396 | ? "Settings" |
| 397 | : "SystemTray"); |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 398 | base::UmaHistogramBoolean(base_histogram_name + "." + surface_name, success); |
Ryan Hansberry | b9e645f | 2020-04-07 21:10:13 | [diff] [blame] | 399 | |
| 400 | if (!success) { |
| 401 | base::UmaHistogramEnumeration(base_histogram_name + ".FailureReason", |
| 402 | *failure_reason); |
| 403 | base::UmaHistogramEnumeration( |
| 404 | base_histogram_name + ".FailureReason." + surface_name, |
| 405 | *failure_reason); |
| 406 | } |
Ryan Hansberry | 5ed351e | 2020-03-10 00:39:13 | [diff] [blame] | 407 | } |
| 408 | |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 409 | void RecordDeviceSelectionDuration(base::TimeDelta duration, |
Theo Johnson-Kanu | d95038f | 2021-07-20 17:45:12 | [diff] [blame] | 410 | DeviceSelectionUISurfaces surface, |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 411 | bool was_paired, |
| 412 | BluetoothTransport transport) { |
| 413 | // Throw out longtail results of the user taking longer than |
| 414 | // |kMaxDeviceSelectionDuration|. Assume that these thrown out results reflect |
| 415 | // the user not being actively engaged with device connection: leaving the |
| 416 | // page open for a long time, walking away from computer, etc. |
| 417 | if (duration > kMaxDeviceSelectionDuration) |
| 418 | return; |
| 419 | |
| 420 | std::string base_histogram_name = |
| 421 | "Bluetooth.ChromeOS.DeviceSelectionDuration"; |
| 422 | RecordDeviceSelectionDuration(base_histogram_name, duration); |
| 423 | |
| 424 | std::string surface_name = |
Theo Johnson-Kanu | d95038f | 2021-07-20 17:45:12 | [diff] [blame] | 425 | (surface == DeviceSelectionUISurfaces::kSettings ? "Settings" |
| 426 | : "SystemTray"); |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 427 | std::string surface_histogram_name = base_histogram_name + "." + surface_name; |
| 428 | RecordDeviceSelectionDuration(surface_histogram_name, duration); |
| 429 | |
| 430 | std::string paired_name = (was_paired ? "Paired" : "NotPaired"); |
| 431 | std::string paired_histogram_name = |
| 432 | surface_histogram_name + "." + paired_name; |
| 433 | RecordDeviceSelectionDuration(paired_histogram_name, duration); |
| 434 | |
| 435 | if (!was_paired) { |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 436 | std::string transport_name = GetTransportName(transport); |
| 437 | if (transport_name.empty()) { |
| 438 | return; |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 439 | } |
Ryan Hansberry | af7c94e9 | 2019-06-14 19:39:38 | [diff] [blame] | 440 | std::string transport_histogram_name = |
| 441 | paired_histogram_name + "." + transport_name; |
| 442 | RecordDeviceSelectionDuration(transport_histogram_name, duration); |
| 443 | } |
| 444 | } |
Theo Johnson-Kanu | 9138c20 | 2021-07-15 21:51:44 | [diff] [blame] | 445 | |
Theo Johnson-Kanu | a4a9eac | 2021-07-24 02:48:33 | [diff] [blame] | 446 | void RecordPoweredStateOperationResult(PoweredStateOperation operation, |
| 447 | bool success) { |
| 448 | std::string operation_name = |
| 449 | operation == PoweredStateOperation::kEnable ? "Enable" : "Disable"; |
| 450 | |
| 451 | base::UmaHistogramBoolean(base::StrCat({"Bluetooth.ChromeOS.PoweredState.", |
| 452 | operation_name, ".Result"}), |
| 453 | success); |
| 454 | } |
| 455 | |
Theo Johnson-Kanu | 9138c20 | 2021-07-15 21:51:44 | [diff] [blame] | 456 | void RecordPoweredState(bool is_powered) { |
| 457 | base::UmaHistogramBoolean("Bluetooth.ChromeOS.PoweredState", is_powered); |
| 458 | } |
| 459 | |
Theo Johnson-Kanu | 9d51452f | 2021-07-24 01:05:08 | [diff] [blame] | 460 | void RecordForgetResult(ForgetResult forget_result) { |
| 461 | base::UmaHistogramEnumeration("Bluetooth.ChromeOS.Forget.Result", |
| 462 | forget_result); |
| 463 | } |
| 464 | |
Theo Johnson-Kanu | d87c2590 | 2022-01-26 19:18:18 | [diff] [blame] | 465 | void RecordDeviceDisconnect(BluetoothDeviceType device_type) { |
| 466 | base::UmaHistogramEnumeration("Bluetooth.ChromeOS.DeviceDisconnect", |
| 467 | device_type); |
| 468 | } |
| 469 | |
| 470 | void RecordUserInitiatedDisconnectResult(DisconnectResult disconnect_result, |
| 471 | BluetoothTransport transport) { |
Theo Johnson-Kanu | e7b494f | 2021-07-24 03:09:47 | [diff] [blame] | 472 | std::string transport_name = GetTransportName(transport); |
| 473 | |
| 474 | if (transport_name.empty()) { |
| 475 | return; |
| 476 | } |
| 477 | |
Theo Johnson-Kanu | e7b494f | 2021-07-24 03:09:47 | [diff] [blame] | 478 | base::UmaHistogramEnumeration( |
Theo Johnson-Kanu | d87c2590 | 2022-01-26 19:18:18 | [diff] [blame] | 479 | "Bluetooth.ChromeOS.UserInitiatedDisconnect.Result", disconnect_result); |
| 480 | base::UmaHistogramEnumeration( |
| 481 | base::StrCat({"Bluetooth.ChromeOS.UserInitiatedDisconnect.Result.", |
| 482 | transport_name}), |
Theo Johnson-Kanu | e7b494f | 2021-07-24 03:09:47 | [diff] [blame] | 483 | disconnect_result); |
| 484 | } |
| 485 | |
Theo Johnson-Kanu | e7abbf7d | 2021-07-21 02:38:27 | [diff] [blame] | 486 | void RecordUiSurfaceDisplayed(BluetoothUiSurface ui_surface) { |
| 487 | base::UmaHistogramEnumeration("Bluetooth.ChromeOS.UiSurfaceDisplayed", |
| 488 | ui_surface); |
| 489 | } |
| 490 | |
Theo Johnson-Kanu | 3c389db | 2021-07-22 21:49:02 | [diff] [blame] | 491 | void RecordUserInitiatedReconnectionAttemptDuration( |
| 492 | absl::optional<ConnectionFailureReason> failure_reason, |
| 493 | BluetoothTransport transport, |
| 494 | base::TimeDelta duration) { |
| 495 | bool success = !failure_reason.has_value(); |
| 496 | std::string transport_name = GetTransportName(transport); |
| 497 | |
| 498 | if (transport_name.empty()) { |
| 499 | return; |
| 500 | } |
| 501 | std::string success_histogram_name = success ? "Success" : "Failure"; |
| 502 | |
| 503 | std::string base_histogram_name = base::StrCat( |
| 504 | {"Bluetooth.ChromeOS.UserInitiatedReconnectionAttempt.Duration.", |
| 505 | success_histogram_name}); |
| 506 | base::UmaHistogramTimes(base_histogram_name, duration); |
| 507 | base::UmaHistogramTimes( |
| 508 | base::StrCat({base_histogram_name, ".", transport_name}), duration); |
| 509 | } |
| 510 | |
Theo Johnson-Kanu | 7956e7d1 | 2021-12-14 22:13:40 | [diff] [blame] | 511 | void RecordSetDeviceNickName(SetNicknameResult set_nickname_result) { |
| 512 | base::UmaHistogramEnumeration("Bluetooth.ChromeOS.SetNickname.Result", |
| 513 | set_nickname_result); |
| 514 | } |
| 515 | |
Sarah Hu | ad95e80 | 2018-04-12 06:24:29 | [diff] [blame] | 516 | } // namespace device |