1# Copyright 2020 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""Bluetooth tests to check controller role support 6 7In preparation for Nearby features, we need to verify that our device 8controllers support the LE connection roles that we will require 9""" 10 11from __future__ import absolute_import 12 13import logging 14import threading 15import time 16 17import common 18from autotest_lib.server.cros.bluetooth import advertisements_data 19from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests 20 21DEFAULT_MIN_ADV_INTERVAL = 200 22DEFAULT_MAX_ADV_INTERVAL = 500 23 24 25class bluetooth_AdapterControllerRoleTests( 26 bluetooth_adapter_tests.BluetoothAdapterTests): 27 """Bluetooth controller role tests. 28 29 This class comprises a number of test cases to verify our controllers 30 support the minimum requirements for LE connection states. 31 """ 32 33 def pair_adapter_to_device(self, device): 34 """Pairs to device, then disconnects 35 36 For our Nearby tests, we use a peer emulating a HID device to act as 37 the Nearby device. Since HID profile requires bonding for connection to 38 occur, this function exchanges the bonding information as a test 39 prerequisite so the Nearby device can later connected 40 41 @param device: handle to peripheral object 42 """ 43 44 self.test_discover_device(device.address) 45 time.sleep(self.TEST_SLEEP_SECS) 46 self.test_pairing(device.address, device.pin, trusted=True) 47 self.test_disconnection_by_adapter(device.address) 48 49 50 def connect_and_test_secondary_device(self, device, secondary_test_func): 51 """Creates connection to a secondary device and tests it 52 53 @param device: handle to peripheral object 54 @param secondary_test_func: function handle to test connection 55 """ 56 logging.info('Setting up secondary device') 57 self.test_discover_device(device.address) 58 self.test_pairing(device.address, device.pin, trusted=True) 59 time.sleep(self.TEST_SLEEP_SECS) 60 self.test_connection_by_adapter(device.address) 61 time.sleep(self.TEST_SLEEP_SECS) 62 secondary_test_func(device) 63 64 65 def _receiver_discovery_async(self, device): 66 """Asynchronously discovers and begins advertising from peer 67 68 We want to verify that the DUT is scanning and advertising at the same 69 time. This function returns a thread that waits, discovers the desired 70 device, and then starts advertising back to emulate a Nearby Receiver 71 device. 72 73 @param device: handle to peripheral object 74 75 @returns threading.Thread object with receiver discovery task 76 """ 77 78 def _action_receiver_discovery(): 79 time.sleep(3) 80 self.test_discover_by_device(device) 81 self.test_device_set_discoverable(device, True) 82 83 thread = threading.Thread(target=_action_receiver_discovery) 84 return thread 85 86 # --------------------------------------------------------------- 87 # Definitions of controller readiness tests 88 # --------------------------------------------------------------- 89 90 ### General test for controller in secondary role 91 def controller_secondary_role_test(self, primary_device, primary_test_func, 92 secondary_info=None): 93 """Advertise from DUT and verify we can handle connection as secondary 94 95 Optional secondary device arguments allows us to try test with existing 96 connection, or to establish new secondary connection during test 97 98 @param primary_device: primary device of connection test 99 @param primary_test_func: function to test connection to primary 100 @param secondary_info: Optional tuple with structure 101 (secondary_device_handle, secondary_test_func, use): 102 secondary_device_handle: peer device to test with 103 secondary_test_func: function handle to run connection test 104 device_use: 'pre' - device should be connected before test runs - or 105 'mid' - device should be connected during test 106 """ 107 108 # 109 # Due to crbug/946835, some messages does not reach btmon 110 # causing our tests to fails. This is seen on kernel 3.18 and lower. 111 # Remove this check when the issue is fixed 112 # TODO(crbug/946835) 113 # 114 self.is_supported_kernel_version(self.host.get_kernel_version(), 115 '3.19', 116 'Test cannnot proceed on this' 117 'kernel due to crbug/946835 ') 118 119 self.bluetooth_le_facade = self.bluetooth_facade 120 121 if secondary_info is not None: 122 (secondary_device_handle, secondary_test_func, 123 device_use) = secondary_info 124 125 # Start fresh, remove DUT from peer's known devices 126 primary_device.RemoveDevice(self.bluetooth_facade.address) 127 128 # Pair the primary device first - necessary for later connection to 129 # secondary device 130 self.pair_adapter_to_device(primary_device) 131 self.test_device_set_discoverable(primary_device, False) 132 133 # If test requires it, connect and test secondary device 134 if secondary_info is not None and device_use == 'pre': 135 self.connect_and_test_secondary_device( 136 secondary_device_handle, secondary_test_func) 137 138 # Register and start advertising instance 139 # We ignore failure because the test isn't able to verify the min/max 140 # advertising intervals, but this is ok. 141 self.test_reset_advertising() 142 self.test_set_advertising_intervals(DEFAULT_MIN_ADV_INTERVAL, 143 DEFAULT_MAX_ADV_INTERVAL) 144 self.test_register_advertisement(advertisements_data.ADVERTISEMENTS[0], 145 1, DEFAULT_MIN_ADV_INTERVAL, 146 DEFAULT_MAX_ADV_INTERVAL) 147 148 # Discover DUT from peer 149 self.test_discover_by_device(primary_device) 150 time.sleep(self.TEST_SLEEP_SECS) 151 152 # Connect to DUT from peer, putting DUT in secondary role 153 self.test_connection_by_device(primary_device) 154 155 # If test requires it, connect and test secondary device 156 if secondary_info is not None and device_use == 'mid': 157 self.connect_and_test_secondary_device( 158 secondary_device_handle, secondary_test_func) 159 160 # Try transferring data over connection 161 primary_test_func(primary_device) 162 163 # Handle cleanup of connected devices 164 if secondary_info is not None: 165 self.test_disconnection_by_adapter(secondary_device_handle.address) 166 167 self.test_disconnection_by_device(primary_device) 168 self.test_reset_advertising() 169 170 ### Nearby sender role test 171 172 def nearby_sender_role_test(self, nearby_device, nearby_device_test_func, 173 secondary_info=None): 174 """Test Nearby Sender role 175 176 Optional secondary device arguments allows us to try test with existing 177 connection, or to establish new secondary connection during test 178 179 @param nearby_device: Device acting as Nearby Receiver in test 180 @param nearby_device_test_func: function to test connection to device 181 @param secondary_info: Optional tuple with structure 182 (secondary_device_handle, secondary_test_func, use): 183 secondary_device_handle: peer device to test with 184 secondary_test_func: function handle to run connection test 185 device_use: 'pre' - device should be connected before test runs - or 186 'mid' - device should be connected during test 187 """ 188 189 # 190 # Due to crbug/946835, some messages does not reach btmon 191 # causing our tests to fails. This is seen on kernel 3.18 and lower. 192 # Remove this check when the issue is fixed 193 # TODO(crbug/946835) 194 # 195 self.is_supported_kernel_version(self.host.get_kernel_version(), 196 '3.19', 197 'Test cannnot proceed on this' 198 'kernel due to crbug/946835 ') 199 200 self.bluetooth_le_facade = self.bluetooth_facade 201 202 if secondary_info is not None: 203 (secondary_device_handle, secondary_test_func, 204 device_use) = secondary_info 205 206 # Start fresh, remove DUT from nearby device 207 nearby_device.RemoveDevice(self.bluetooth_facade.address) 208 209 # Pair the nearby device first - necessary for later connection to 210 # secondary device 211 self.pair_adapter_to_device(nearby_device) 212 213 # We don't want peer advertising until it hears our broadcast 214 self.test_device_set_discoverable(nearby_device, False) 215 216 # If test requires it, connect and test secondary device 217 if secondary_info is not None and device_use == 'pre': 218 self.connect_and_test_secondary_device( 219 secondary_device_handle, secondary_test_func) 220 221 # Register and start non-connectable advertising instance 222 # We ignore failure because the test isn't able to verify the min/max 223 # advertising intervals, but this is ok. 224 self.test_reset_advertising() 225 self.test_set_advertising_intervals(DEFAULT_MIN_ADV_INTERVAL, 226 DEFAULT_MAX_ADV_INTERVAL) 227 228 # For now, advertise connectable advertisement. If we use a broadcast 229 # advertisement, the Pi can't resolve the address and 230 # test_discover_by_device will fail 231 self.test_register_advertisement( 232 advertisements_data.ADVERTISEMENTS[0], 1, 233 DEFAULT_MIN_ADV_INTERVAL, DEFAULT_MAX_ADV_INTERVAL) 234 235 # Second thread runs on peer, delays, discovers DUT, and then advertises 236 # itself back 237 peer_discover = self._receiver_discovery_async(nearby_device) 238 peer_discover.start() 239 240 # Verify that we correctly receive advertisement from nearby device 241 self.test_receive_advertisement(address=nearby_device.address, 242 timeout=30) 243 244 # Make sure peer thread completes 245 peer_discover.join() 246 247 # Connect to peer from DUT 248 self.test_connection_by_adapter(nearby_device.address) 249 250 # TODO(b/164131633) On 4.4 kernel, sometimes the input device is not 251 # created if we connect a second device too quickly 252 time.sleep(self.TEST_SLEEP_SECS) 253 254 # If test requires it, connect and test secondary device 255 if secondary_info is not None and device_use == 'mid': 256 self.connect_and_test_secondary_device( 257 secondary_device_handle, secondary_test_func) 258 259 time.sleep(self.TEST_SLEEP_SECS) 260 261 # Try data test with nearby device 262 nearby_device_test_func(nearby_device) 263 264 # Handle cleanup of connected devices 265 if secondary_info is not None: 266 self.test_disconnection_by_adapter(secondary_device_handle.address) 267 268 self.test_disconnection_by_adapter(nearby_device.address) 269 self.test_reset_advertising() 270 271 # Nearby receiver role test 272 273 def nearby_receiver_role_test(self, nearby_device, nearby_device_test_func, 274 secondary_info=None): 275 """Test Nearby Receiver role 276 277 Optional secondary device arguments allows us to try test with existing 278 connection, or to establish new secondary connection during test 279 280 @param nearby_device: Device acting as Nearby Sender in test 281 @param nearby_device_test_func: function to test connection to device 282 @param secondary_info: Optional tuple with structure 283 (secondary_device_handle, secondary_test_func, use): 284 secondary_device_handle: peer device to test with 285 secondary_test_func: function handle to run connection test 286 device_use: 'pre' - device should be connected before test runs - or 287 'mid' - device should be connected in middle of test, 288 during advertisement 289 'end' - device should be connected at end of test, when 290 already connected to Nearby device 291 """ 292 293 # 294 # Due to crbug/946835, some messages does not reach btmon 295 # causing our tests to fails. This is seen on kernel 3.18 and lower. 296 # Remove this check when the issue is fixed 297 # TODO(crbug/946835) 298 # 299 self.is_supported_kernel_version(self.host.get_kernel_version(), 300 '3.19', 301 'Test cannnot proceed on this' 302 'kernel due to crbug/946835 ') 303 304 self.bluetooth_le_facade = self.bluetooth_facade 305 306 if secondary_info is not None: 307 (secondary_device_handle, secondary_test_func, 308 device_use) = secondary_info 309 310 # Start fresh, remove device peer 311 nearby_device.RemoveDevice(self.bluetooth_facade.address) 312 313 # If test requires it, connect and test secondary device 314 if secondary_info is not None and device_use == 'pre': 315 self.connect_and_test_secondary_device( 316 secondary_device_handle, secondary_test_func) 317 318 # Verify that we correctly receive advertisement from peer 319 # TODO ideally, peer would be broadcasting non-connectable adv with 320 # 0xFE2C data, but this is not implemented yet on peer 321 self.test_receive_advertisement(address=nearby_device.address, 322 timeout=30) 323 324 # Pair the nearby device first - necessary for later connection to 325 # secondary device 326 self.pair_adapter_to_device(nearby_device) 327 328 # Register and start non-connectable advertising instance 329 # We ignore failure because the test isn't able to verify the min/max 330 # advertising intervals, but this is ok. 331 self.test_reset_advertising() 332 self.test_set_advertising_intervals(DEFAULT_MIN_ADV_INTERVAL, 333 DEFAULT_MAX_ADV_INTERVAL) 334 self.test_register_advertisement(advertisements_data.ADVERTISEMENTS[0], 335 1, DEFAULT_MIN_ADV_INTERVAL, 336 DEFAULT_MAX_ADV_INTERVAL) 337 338 # If test requires it, connect and test secondary device 339 if secondary_info is not None and device_use == 'mid': 340 self.connect_and_test_secondary_device( 341 secondary_device_handle, secondary_test_func) 342 343 # Discover DUT from peer 344 self.test_discover_by_device(nearby_device) 345 346 # Connect to DUT from peer 347 self.test_connection_by_device(nearby_device) 348 349 # TODO(b/164131633) On 4.4 kernel, sometimes the input device is not 350 # created if we connect a second device too quickly 351 time.sleep(self.TEST_SLEEP_SECS) 352 353 # If test requires it, connect and test secondary device 354 if secondary_info is not None and device_use == 'end': 355 self.connect_and_test_secondary_device( 356 secondary_device_handle, secondary_test_func) 357 358 time.sleep(self.TEST_SLEEP_SECS) 359 360 # Try data test with nearby device 361 nearby_device_test_func(nearby_device) 362 363 self.test_disconnection_by_device(nearby_device) 364 self.test_reset_advertising() 365