blob: 1cbd91930e21d6770bb4fceb0d78fb468ea124c2 [file] [log] [blame]
Mark De Ruyterd9c540a2018-05-04 11:21:55 -07001#!/usr/bin/env python3
tturney1bdf77d2015-12-28 17:46:13 -08002#
3# Copyright (C) 2016 The Android Open Source Project
Ang Li73697b32015-12-03 00:41:53 +00004#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16
Ang Li5bd83f32016-05-23 14:39:38 -070017import logging
Ang Li73697b32015-12-03 00:41:53 +000018import random
Ang Li73697b32015-12-03 00:41:53 +000019import string
tturney50f851d2016-07-07 11:07:37 -070020from queue import Empty
Ang Li73697b32015-12-03 00:41:53 +000021import threading
22import time
tturney03a45ae2016-05-24 15:36:05 -070023from acts import utils
tprotopopov2e18bbb2018-10-02 10:29:01 -070024import re
tturneye3170f02016-05-19 14:37:00 -070025from subprocess import call
Ang Li73697b32015-12-03 00:41:53 +000026
Aidan Holloway-bidwellf8f51512018-11-06 10:42:14 -080027from acts.test_utils.bt.bt_constants import bits_per_samples
28from acts.test_utils.bt.bt_constants import channel_modes
29from acts.test_utils.bt.bt_constants import codec_types
30from acts.test_utils.bt.bt_constants import codec_priorities
31from acts.test_utils.bt.bt_constants import sample_rates
tturneyec1b8f52017-07-26 07:35:06 -070032from acts.test_utils.bt.bt_constants import adv_fail
33from acts.test_utils.bt.bt_constants import adv_succ
tturneyec1b8f52017-07-26 07:35:06 -070034from acts.test_utils.bt.bt_constants import batch_scan_not_supported_list
tturneyec1b8f52017-07-26 07:35:06 -070035from acts.test_utils.bt.bt_constants import ble_advertise_settings_modes
36from acts.test_utils.bt.bt_constants import ble_advertise_settings_tx_powers
Aidan Holloway-bidwellf8f51512018-11-06 10:42:14 -080037from acts.test_utils.bt.bt_constants import bluetooth_a2dp_codec_config_changed
tturneyec1b8f52017-07-26 07:35:06 -070038from acts.test_utils.bt.bt_constants import bluetooth_off
39from acts.test_utils.bt.bt_constants import bluetooth_on
40from acts.test_utils.bt.bt_constants import \
41 bluetooth_profile_connection_state_changed
42from acts.test_utils.bt.bt_constants import bt_default_timeout
tturneyec1b8f52017-07-26 07:35:06 -070043from acts.test_utils.bt.bt_constants import bt_profile_states
tturneyb72742f2017-08-29 17:46:50 -070044from acts.test_utils.bt.bt_constants import bt_profile_constants
tturneyec1b8f52017-07-26 07:35:06 -070045from acts.test_utils.bt.bt_constants import bt_rfcomm_uuids
Timofey Protopopova47c8812018-03-28 11:37:31 -070046from acts.test_utils.bt.bt_constants import bluetooth_socket_conn_test_uuid
tturneyec1b8f52017-07-26 07:35:06 -070047from acts.test_utils.bt.bt_constants import bt_scan_mode_types
48from acts.test_utils.bt.bt_constants import btsnoop_last_log_path_on_device
49from acts.test_utils.bt.bt_constants import btsnoop_log_path_on_device
50from acts.test_utils.bt.bt_constants import default_rfcomm_timeout_ms
Stanley Tng180a8be2017-11-29 10:53:33 -080051from acts.test_utils.bt.bt_constants import default_bluetooth_socket_timeout_ms
tturneyec1b8f52017-07-26 07:35:06 -070052from acts.test_utils.bt.bt_constants import pairing_variant_passkey_confirmation
53from acts.test_utils.bt.bt_constants import pan_connect_timeout
54from acts.test_utils.bt.bt_constants import small_timeout
55from acts.test_utils.bt.bt_constants import scan_result
Tom Turney7b0baa52018-06-26 11:31:31 -070056from acts.test_utils.bt.bt_constants import sig_uuid_constants
Hansong Zhangd78b3b82017-10-03 10:36:12 -070057from acts.test_utils.bt.bt_constants import hid_id_keyboard
tturney83c28a02018-03-06 14:30:54 -080058
tturney1e174fd2017-06-01 14:42:20 -070059from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
tturneyb92368a2016-09-13 10:43:15 -070060from acts.test_utils.tel.tel_test_utils import verify_http_connection
Ang Li73697b32015-12-03 00:41:53 +000061from acts.utils import exe_cmd
62
Ang Li5bd83f32016-05-23 14:39:38 -070063log = logging
Ang Li73697b32015-12-03 00:41:53 +000064
tturney57eb93a2016-06-21 13:58:06 -070065advertisements_to_devices = {}
Ang Li73697b32015-12-03 00:41:53 +000066
Ang Li73697b32015-12-03 00:41:53 +000067
tturney951533f2016-06-23 11:24:25 -070068class BtTestUtilsError(Exception):
69 pass
70
tturneyb92368a2016-09-13 10:43:15 -070071
Bill Leung46b69352018-11-09 17:28:39 -080072def _add_android_device_to_dictionary(android_device, profile_list,
73 selector_dict):
74 """Adds the AndroidDevice and supported features to the selector dictionary
tturneyed249972016-09-13 11:07:49 -070075
76 Args:
Bill Leung46b69352018-11-09 17:28:39 -080077 android_device: The Android device.
78 profile_list: The list of profiles the Android device supports.
tturneyed249972016-09-13 11:07:49 -070079 """
Bill Leung46b69352018-11-09 17:28:39 -080080 for profile in profile_list:
81 if profile in selector_dict and android_device not in selector_dict[profile]:
82 selector_dict[profile].append(android_device)
83 else:
84 selector_dict[profile] = [android_device]
Ang Li73697b32015-12-03 00:41:53 +000085
86
tturney50f851d2016-07-07 11:07:37 -070087def bluetooth_enabled_check(ad):
tturneyed249972016-09-13 11:07:49 -070088 """Checks if the Bluetooth state is enabled, if not it will attempt to
89 enable it.
90
91 Args:
92 ad: The Android device list to enable Bluetooth on.
93
94 Returns:
95 True if successful, false if unsuccessful.
96 """
tturney50f851d2016-07-07 11:07:37 -070097 if not ad.droid.bluetoothCheckState():
98 ad.droid.bluetoothToggleState(True)
99 expected_bluetooth_on_event_name = bluetooth_on
100 try:
tturneyec1b8f52017-07-26 07:35:06 -0700101 ad.ed.pop_event(expected_bluetooth_on_event_name,
102 bt_default_timeout)
tturney50f851d2016-07-07 11:07:37 -0700103 except Empty:
tturney5da68262017-05-02 08:57:52 -0700104 ad.log.info(
105 "Failed to toggle Bluetooth on(no broadcast received).")
tturney50f851d2016-07-07 11:07:37 -0700106 # Try one more time to poke at the actual state.
107 if ad.droid.bluetoothCheckState():
tturney34ee54d2016-11-16 15:29:02 -0800108 ad.log.info(".. actual state is ON")
tturney50f851d2016-07-07 11:07:37 -0700109 return True
tturney34ee54d2016-11-16 15:29:02 -0800110 ad.log.error(".. actual state is OFF")
tturney50f851d2016-07-07 11:07:37 -0700111 return False
112 return True
113
Tom Turney9bce15d2018-06-21 13:00:42 -0700114
Bill Leung46b69352018-11-09 17:28:39 -0800115def check_device_supported_profiles(droid):
116 """Checks for Android device supported profiles.
tturneyed249972016-09-13 11:07:49 -0700117
118 Args:
Bill Leung46b69352018-11-09 17:28:39 -0800119 droid: The droid object to query.
tturneyed249972016-09-13 11:07:49 -0700120
121 Returns:
Bill Leung46b69352018-11-09 17:28:39 -0800122 A dictionary of supported profiles.
Ang Li73697b32015-12-03 00:41:53 +0000123 """
Bill Leung46b69352018-11-09 17:28:39 -0800124 profile_dict = {}
125 profile_dict['hid'] = droid.bluetoothHidIsReady()
126 profile_dict['hsp'] = droid.bluetoothHspIsReady()
127 profile_dict['a2dp'] = droid.bluetoothA2dpIsReady()
128 profile_dict['avrcp'] = droid.bluetoothAvrcpIsReady()
129 profile_dict['a2dp_sink'] = droid.bluetoothA2dpSinkIsReady()
130 profile_dict['hfp_client'] = droid.bluetoothHfpClientIsReady()
131 profile_dict['pbap_client'] = droid.bluetoothPbapClientIsReady()
132 return profile_dict
Ang Li73697b32015-12-03 00:41:53 +0000133
134
tturneyed249972016-09-13 11:07:49 -0700135def cleanup_scanners_and_advertisers(scn_android_device, scn_callback_list,
tturney1ce8dc62016-02-18 09:55:53 -0800136 adv_android_device, adv_callback_list):
tturneyed249972016-09-13 11:07:49 -0700137 """Try to gracefully stop all scanning and advertising instances.
138
139 Args:
140 scn_android_device: The Android device that is actively scanning.
141 scn_callback_list: The scan callback id list that needs to be stopped.
142 adv_android_device: The Android device that is actively advertising.
143 adv_callback_list: The advertise callback id list that needs to be
144 stopped.
Ang Li73697b32015-12-03 00:41:53 +0000145 """
tturney1ce8dc62016-02-18 09:55:53 -0800146 scan_droid, scan_ed = scn_android_device.droid, scn_android_device.ed
147 adv_droid = adv_android_device.droid
Ang Li73697b32015-12-03 00:41:53 +0000148 try:
tturneyed249972016-09-13 11:07:49 -0700149 for scan_callback in scn_callback_list:
Ang Li73697b32015-12-03 00:41:53 +0000150 scan_droid.bleStopBleScan(scan_callback)
tturneye3170f02016-05-19 14:37:00 -0700151 except Exception as err:
tturney34ee54d2016-11-16 15:29:02 -0800152 scn_android_device.log.debug(
153 "Failed to stop LE scan... reseting Bluetooth. Error {}".format(
154 err))
tturney1ce8dc62016-02-18 09:55:53 -0800155 reset_bluetooth([scn_android_device])
Ang Li73697b32015-12-03 00:41:53 +0000156 try:
157 for adv_callback in adv_callback_list:
158 adv_droid.bleStopBleAdvertising(adv_callback)
tturneye3170f02016-05-19 14:37:00 -0700159 except Exception as err:
tturney34ee54d2016-11-16 15:29:02 -0800160 adv_android_device.log.debug(
tturneyb92368a2016-09-13 10:43:15 -0700161 "Failed to stop LE advertisement... reseting Bluetooth. Error {}".
Timofey Protopopova47c8812018-03-28 11:37:31 -0700162 format(err))
tturney1ce8dc62016-02-18 09:55:53 -0800163 reset_bluetooth([adv_android_device])
Ang Li73697b32015-12-03 00:41:53 +0000164
165
Bill Leung46b69352018-11-09 17:28:39 -0800166def clear_bonded_devices(ad):
167 """Clear bonded devices from the input Android device.
tturneyed249972016-09-13 11:07:49 -0700168
169 Args:
Bill Leung46b69352018-11-09 17:28:39 -0800170 ad: the Android device performing the connection.
tturneyed249972016-09-13 11:07:49 -0700171 Returns:
Bill Leung46b69352018-11-09 17:28:39 -0800172 True if clearing bonded devices was successful, false if unsuccessful.
tturneyed249972016-09-13 11:07:49 -0700173 """
Bill Leung46b69352018-11-09 17:28:39 -0800174 bonded_device_list = ad.droid.bluetoothGetBondedDevices()
175 while bonded_device_list:
176 device_address = bonded_device_list[0]['address']
177 if not ad.droid.bluetoothUnbond(device_address):
178 log.error("Failed to unbond {} from {}".format(
179 device_address, ad.serial))
180 return False
181 log.info("Successfully unbonded {} from {}".format(
182 device_address, ad.serial))
183 #TODO: wait for BOND_STATE_CHANGED intent instead of waiting
184 time.sleep(1)
Ang Li73697b32015-12-03 00:41:53 +0000185
Bill Leung46b69352018-11-09 17:28:39 -0800186 # If device was first connected using LE transport, after bonding it is
187 # accessible through it's LE address, and through it classic address.
188 # Unbonding it will unbond two devices representing different
189 # "addresses". Attempt to unbond such already unbonded devices will
190 # result in bluetoothUnbond returning false.
191 bonded_device_list = ad.droid.bluetoothGetBondedDevices()
Sanket Agarwalc8fdc1a2016-07-06 16:39:34 -0700192 return True
193
Tom Turney9bce15d2018-06-21 13:00:42 -0700194
Aidan Holloway-bidwell9e44b9d2018-11-07 14:33:27 -0800195def connect_phone_to_headset(android, headset, timeout=bt_default_timeout,
196 connection_check_period=10):
197 """Connects android phone to bluetooth headset.
198 Headset object must have methods power_on and enter_pairing_mode,
199 and attribute mac_address.
200
201 Args:
202 android: AndroidDevice object with SL4A installed.
203 headset: Object with attribute mac_address and methods power_on and
204 enter_pairing_mode.
205 timeout: Seconds to wait for devices to connect.
206 connection_check_period: how often to check for connection once the
207 SL4A connect RPC has been sent.
208 Returns:
209 connected (bool): True if devices are paired and connected by end of
210 method. False otherwise.
211 """
212 connected = is_a2dp_src_device_connected(android, headset.mac_address)
213 log.info('Devices connected before pair attempt: %s' % connected)
214 start_time = time.time()
215 # If already connected, skip pair and connect attempt.
216 while not connected and (time.time() - start_time < timeout):
217 bonded_info = android.droid.bluetoothA2dpGetConnectedDevices()
218 if headset.mac_address not in [info["address"] for info in bonded_info]:
219 # Turn on headset and initiate pairing mode.
220 headset.enter_pairing_mode()
221 # Use SL4A to pair and connect with headset.
222 android.droid.bluetoothDiscoverAndBond(headset.mac_address)
223 else: # Device is bonded but not connected
224 android.droid.bluetoothConnectBonded(headset.mac_address)
225 log.info('Waiting for connection...')
226 time.sleep(connection_check_period)
227 # Check for connection.
228 connected = is_a2dp_src_device_connected(android, headset.mac_address)
229 log.info('Devices connected after pair attempt: %s' % connected)
230 return connected
231
232
Phillip Walker827112a2016-09-08 16:27:19 -0700233def connect_pri_to_sec(pri_ad, sec_ad, profiles_set, attempts=2):
Sanket Agarwalc96b9cc2016-08-18 12:01:04 -0700234 """Connects pri droid to secondary droid.
tturney57eb93a2016-06-21 13:58:06 -0700235
Sanket Agarwalc96b9cc2016-08-18 12:01:04 -0700236 Args:
Phillip Walker827112a2016-09-08 16:27:19 -0700237 pri_ad: AndroidDroid initiating connection
238 sec_ad: AndroidDroid accepting connection
Sanket Agarwalc96b9cc2016-08-18 12:01:04 -0700239 profiles_set: Set of profiles to be connected
240 attempts: Number of attempts to try until failure.
241
242 Returns:
243 Pass if True
244 Fail if False
245 """
Phillip Walker827112a2016-09-08 16:27:19 -0700246 device_addr = sec_ad.droid.bluetoothGetLocalAddress()
247 # Allows extra time for the SDP records to be updated.
248 time.sleep(2)
Sanket Agarwalc96b9cc2016-08-18 12:01:04 -0700249 curr_attempts = 0
250 while curr_attempts < attempts:
Phillip Walker827112a2016-09-08 16:27:19 -0700251 log.info("connect_pri_to_sec curr attempt {} total {}".format(
252 curr_attempts, attempts))
253 if _connect_pri_to_sec(pri_ad, sec_ad, profiles_set):
254 return True
255 curr_attempts += 1
256 log.error("connect_pri_to_sec failed to connect after {} attempts".format(
257 attempts))
Sanket Agarwalc96b9cc2016-08-18 12:01:04 -0700258 return False
259
Phillip Walker827112a2016-09-08 16:27:19 -0700260
261def _connect_pri_to_sec(pri_ad, sec_ad, profiles_set):
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700262 """Connects pri droid to secondary droid.
263
264 Args:
Phillip Walker827112a2016-09-08 16:27:19 -0700265 pri_ad: AndroidDroid initiating connection.
266 sec_ad: AndroidDroid accepting connection.
tturneyed249972016-09-13 11:07:49 -0700267 profiles_set: Set of profiles to be connected.
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700268
269 Returns:
tturneyed249972016-09-13 11:07:49 -0700270 True of connection is successful, false if unsuccessful.
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700271 """
272 # Check if we support all profiles.
tturneye1f6c722017-08-30 07:03:11 -0700273 supported_profiles = bt_profile_constants.values()
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700274 for profile in profiles_set:
275 if profile not in supported_profiles:
tturney34ee54d2016-11-16 15:29:02 -0800276 pri_ad.log.info("Profile {} is not supported list {}".format(
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700277 profile, supported_profiles))
278 return False
279
280 # First check that devices are bonded.
281 paired = False
Phillip Walker827112a2016-09-08 16:27:19 -0700282 for paired_device in pri_ad.droid.bluetoothGetBondedDevices():
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700283 if paired_device['address'] == \
Timofey Protopopova47c8812018-03-28 11:37:31 -0700284 sec_ad.droid.bluetoothGetLocalAddress():
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700285 paired = True
286 break
287
288 if not paired:
tturney34ee54d2016-11-16 15:29:02 -0800289 pri_ad.log.error("Not paired to {}".format(sec_ad.serial))
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700290 return False
291
292 # Now try to connect them, the following call will try to initiate all
293 # connections.
Stanley Tngc9a123d2017-12-05 17:37:49 -0800294 pri_ad.droid.bluetoothConnectBonded(
295 sec_ad.droid.bluetoothGetLocalAddress())
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700296
tturney46060782016-11-14 16:44:38 -0800297 end_time = time.time() + 10
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700298 profile_connected = set()
tturney46060782016-11-14 16:44:38 -0800299 sec_addr = sec_ad.droid.bluetoothGetLocalAddress()
tturney34ee54d2016-11-16 15:29:02 -0800300 pri_ad.log.info("Profiles to be connected {}".format(profiles_set))
tturney46060782016-11-14 16:44:38 -0800301 # First use APIs to check profile connection state
Stanley Tngc9a123d2017-12-05 17:37:49 -0800302 while (time.time() < end_time
303 and not profile_connected.issuperset(profiles_set)):
304 if (bt_profile_constants['headset_client'] not in profile_connected
305 and bt_profile_constants['headset_client'] in profiles_set):
tturney46060782016-11-14 16:44:38 -0800306 if is_hfp_client_device_connected(pri_ad, sec_addr):
tturneyec1b8f52017-07-26 07:35:06 -0700307 profile_connected.add(bt_profile_constants['headset_client'])
Stanley Tngc9a123d2017-12-05 17:37:49 -0800308 if (bt_profile_constants['a2dp'] not in profile_connected
309 and bt_profile_constants['a2dp'] in profiles_set):
tturney46060782016-11-14 16:44:38 -0800310 if is_a2dp_src_device_connected(pri_ad, sec_addr):
tturneyec1b8f52017-07-26 07:35:06 -0700311 profile_connected.add(bt_profile_constants['a2dp'])
Stanley Tngc9a123d2017-12-05 17:37:49 -0800312 if (bt_profile_constants['a2dp_sink'] not in profile_connected
313 and bt_profile_constants['a2dp_sink'] in profiles_set):
tturney46060782016-11-14 16:44:38 -0800314 if is_a2dp_snk_device_connected(pri_ad, sec_addr):
tturneyec1b8f52017-07-26 07:35:06 -0700315 profile_connected.add(bt_profile_constants['a2dp_sink'])
Stanley Tngc9a123d2017-12-05 17:37:49 -0800316 if (bt_profile_constants['map_mce'] not in profile_connected
317 and bt_profile_constants['map_mce'] in profiles_set):
tturney46060782016-11-14 16:44:38 -0800318 if is_map_mce_device_connected(pri_ad, sec_addr):
tturneyec1b8f52017-07-26 07:35:06 -0700319 profile_connected.add(bt_profile_constants['map_mce'])
Stanley Tngc9a123d2017-12-05 17:37:49 -0800320 if (bt_profile_constants['map'] not in profile_connected
321 and bt_profile_constants['map'] in profiles_set):
tturney46060782016-11-14 16:44:38 -0800322 if is_map_mse_device_connected(pri_ad, sec_addr):
tturneyec1b8f52017-07-26 07:35:06 -0700323 profile_connected.add(bt_profile_constants['map'])
tturney46060782016-11-14 16:44:38 -0800324 time.sleep(0.1)
325 # If APIs fail, try to find the connection broadcast receiver.
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700326 while not profile_connected.issuperset(profiles_set):
327 try:
Phillip Walker827112a2016-09-08 16:27:19 -0700328 profile_event = pri_ad.ed.pop_event(
tturney46060782016-11-14 16:44:38 -0800329 bluetooth_profile_connection_state_changed,
tturneyec1b8f52017-07-26 07:35:06 -0700330 bt_default_timeout + 10)
tturney34ee54d2016-11-16 15:29:02 -0800331 pri_ad.log.info("Got event {}".format(profile_event))
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700332 except Exception:
tturney34ee54d2016-11-16 15:29:02 -0800333 pri_ad.log.error("Did not get {} profiles left {}".format(
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700334 bluetooth_profile_connection_state_changed, profile_connected))
335 return False
336
337 profile = profile_event['data']['profile']
338 state = profile_event['data']['state']
339 device_addr = profile_event['data']['addr']
tturneyec1b8f52017-07-26 07:35:06 -0700340 if state == bt_profile_states['connected'] and \
Timofey Protopopova47c8812018-03-28 11:37:31 -0700341 device_addr == sec_ad.droid.bluetoothGetLocalAddress():
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700342 profile_connected.add(profile)
Stanley Tngc9a123d2017-12-05 17:37:49 -0800343 pri_ad.log.info(
344 "Profiles connected until now {}".format(profile_connected))
Sanket Agarwald09c7d82016-05-17 20:24:51 -0700345 # Failure happens inside the while loop. If we came here then we already
346 # connected.
347 return True
Ang Li73697b32015-12-03 00:41:53 +0000348
tturney57eb93a2016-06-21 13:58:06 -0700349
Bill Leung46b69352018-11-09 17:28:39 -0800350def determine_max_advertisements(android_device):
351 """Determines programatically how many advertisements the Android device
352 supports.
353
354 Args:
355 android_device: The Android device to determine max advertisements of.
356
357 Returns:
358 The maximum advertisement count.
359 """
360 android_device.log.info(
361 "Determining number of maximum concurrent advertisements...")
362 advertisement_count = 0
363 bt_enabled = False
364 expected_bluetooth_on_event_name = bluetooth_on
365 if not android_device.droid.bluetoothCheckState():
366 android_device.droid.bluetoothToggleState(True)
367 try:
368 android_device.ed.pop_event(expected_bluetooth_on_event_name,
369 bt_default_timeout)
370 except Exception:
371 android_device.log.info(
372 "Failed to toggle Bluetooth on(no broadcast received).")
373 # Try one more time to poke at the actual state.
374 if android_device.droid.bluetoothCheckState() is True:
375 android_device.log.info(".. actual state is ON")
376 else:
377 android_device.log.error(
378 "Failed to turn Bluetooth on. Setting default advertisements to 1"
379 )
380 advertisement_count = -1
381 return advertisement_count
382 advertise_callback_list = []
383 advertise_data = android_device.droid.bleBuildAdvertiseData()
384 advertise_settings = android_device.droid.bleBuildAdvertiseSettings()
385 while (True):
386 advertise_callback = android_device.droid.bleGenBleAdvertiseCallback()
387 advertise_callback_list.append(advertise_callback)
388
389 android_device.droid.bleStartBleAdvertising(
390 advertise_callback, advertise_data, advertise_settings)
391
392 regex = "(" + adv_succ.format(
393 advertise_callback) + "|" + adv_fail.format(
394 advertise_callback) + ")"
395 # wait for either success or failure event
396 evt = android_device.ed.pop_events(regex, bt_default_timeout,
397 small_timeout)
398 if evt[0]["name"] == adv_succ.format(advertise_callback):
399 advertisement_count += 1
400 android_device.log.info(
401 "Advertisement {} started.".format(advertisement_count))
402 else:
403 error = evt[0]["data"]["Error"]
404 if error == "ADVERTISE_FAILED_TOO_MANY_ADVERTISERS":
405 android_device.log.info(
406 "Advertisement failed to start. Reached max " +
407 "advertisements at {}".format(advertisement_count))
408 break
409 else:
410 raise BtTestUtilsError(
411 "Expected ADVERTISE_FAILED_TOO_MANY_ADVERTISERS," +
412 " but received bad error code {}".format(error))
413 try:
414 for adv in advertise_callback_list:
415 android_device.droid.bleStopBleAdvertising(adv)
416 except Exception:
417 android_device.log.error(
418 "Failed to stop advertisingment, resetting Bluetooth.")
419 reset_bluetooth([android_device])
420 return advertisement_count
421
422
423def disable_bluetooth(droid):
424 """Disable Bluetooth on input Droid object.
425
426 Args:
427 droid: The droid object to disable Bluetooth on.
428
429 Returns:
430 True if successful, false if unsuccessful.
431 """
432 if droid.bluetoothCheckState() is True:
433 droid.bluetoothToggleState(False)
434 if droid.bluetoothCheckState() is True:
435 log.error("Failed to toggle Bluetooth off.")
436 return False
437 return True
438
439
Phillip Walker827112a2016-09-08 16:27:19 -0700440def disconnect_pri_from_sec(pri_ad, sec_ad, profiles_list):
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700441 """
442 Disconnect primary from secondary on a specific set of profiles
443 Args:
Phillip Walker827112a2016-09-08 16:27:19 -0700444 pri_ad - Primary android_device initiating disconnection
445 sec_ad - Secondary android droid (sl4a interface to keep the
446 method signature the same connect_pri_to_sec above)
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700447 profiles_list - List of profiles we want to disconnect from
448
449 Returns:
450 True on Success
451 False on Failure
452 """
453 # Sanity check to see if all the profiles in the given set is supported
tturneyca42e2e2017-08-30 10:22:54 -0700454 supported_profiles = bt_profile_constants.values()
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700455 for profile in profiles_list:
456 if profile not in supported_profiles:
tturney34ee54d2016-11-16 15:29:02 -0800457 pri_ad.log.info("Profile {} is not in supported list {}".format(
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700458 profile, supported_profiles))
459 return False
460
tturney34ee54d2016-11-16 15:29:02 -0800461 pri_ad.log.info(pri_ad.droid.bluetoothGetBondedDevices())
Phillip Walker827112a2016-09-08 16:27:19 -0700462 # Disconnecting on a already disconnected profile is a nop,
463 # so not checking for the connection state
464 try:
465 pri_ad.droid.bluetoothDisconnectConnectedProfile(
466 sec_ad.droid.bluetoothGetLocalAddress(), profiles_list)
467 except Exception as err:
tturney34ee54d2016-11-16 15:29:02 -0800468 pri_ad.log.error(
469 "Exception while trying to disconnect profile(s) {}: {}".format(
470 profiles_list, err))
Phillip Walker827112a2016-09-08 16:27:19 -0700471 return False
472
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700473 profile_disconnected = set()
tturney34ee54d2016-11-16 15:29:02 -0800474 pri_ad.log.info("Disconnecting from profiles: {}".format(profiles_list))
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700475
476 while not profile_disconnected.issuperset(profiles_list):
477 try:
Phillip Walker827112a2016-09-08 16:27:19 -0700478 profile_event = pri_ad.ed.pop_event(
Timofey Protopopova47c8812018-03-28 11:37:31 -0700479 bluetooth_profile_connection_state_changed, bt_default_timeout)
tturney34ee54d2016-11-16 15:29:02 -0800480 pri_ad.log.info("Got event {}".format(profile_event))
Timofey Protopopova47c8812018-03-28 11:37:31 -0700481 except Exception as e:
Tom Turney9bce15d2018-06-21 13:00:42 -0700482 pri_ad.log.error(
483 "Did not disconnect from Profiles. Reason {}".format(e))
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700484 return False
485
486 profile = profile_event['data']['profile']
487 state = profile_event['data']['state']
488 device_addr = profile_event['data']['addr']
489
tturneyec1b8f52017-07-26 07:35:06 -0700490 if state == bt_profile_states['disconnected'] and \
Timofey Protopopova47c8812018-03-28 11:37:31 -0700491 device_addr == sec_ad.droid.bluetoothGetLocalAddress():
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700492 profile_disconnected.add(profile)
Stanley Tngc9a123d2017-12-05 17:37:49 -0800493 pri_ad.log.info(
494 "Profiles disconnected so far {}".format(profile_disconnected))
Ram Periathiruvadie3f9a702016-07-26 17:41:59 -0700495
496 return True
497
498
Bill Leung46b69352018-11-09 17:28:39 -0800499def enable_bluetooth(droid, ed):
500 if droid.bluetoothCheckState() is True:
501 return True
tturneyed249972016-09-13 11:07:49 -0700502
Bill Leung46b69352018-11-09 17:28:39 -0800503 droid.bluetoothToggleState(True)
504 expected_bluetooth_on_event_name = bluetooth_on
tturney5d7a1fc2017-06-01 15:12:12 -0700505 try:
Bill Leung46b69352018-11-09 17:28:39 -0800506 ed.pop_event(expected_bluetooth_on_event_name, bt_default_timeout)
507 except Exception:
508 log.info("Failed to toggle Bluetooth on (no broadcast received)")
509 if droid.bluetoothCheckState() is True:
510 log.info(".. actual state is ON")
Timofey Protopopov2651b742018-04-09 16:43:49 -0700511 return True
Bill Leung46b69352018-11-09 17:28:39 -0800512 log.info(".. actual state is OFF")
513 return False
514
515 return True
516
517
518def factory_reset_bluetooth(android_devices):
519 """Clears Bluetooth stack of input Android device list.
520
521 Args:
522 android_devices: The Android device list to reset Bluetooth
523
524 Returns:
525 True if successful, false if unsuccessful.
526 """
527 for a in android_devices:
528 droid, ed = a.droid, a.ed
529 a.log.info("Reset state of bluetooth on device.")
530 if not bluetooth_enabled_check(a):
531 return False
532 # TODO: remove device unbond b/79418045
533 # Temporary solution to ensure all devices are unbonded
534 bonded_devices = droid.bluetoothGetBondedDevices()
535 for b in bonded_devices:
536 a.log.info("Removing bond for device {}".format(b['address']))
537 droid.bluetoothUnbond(b['address'])
538
539 droid.bluetoothFactoryReset()
540 wait_for_bluetooth_manager_state(droid)
541 if not enable_bluetooth(droid, ed):
542 return False
543 return True
544
545
546def generate_ble_advertise_objects(droid):
547 """Generate generic LE advertise objects.
548
549 Args:
550 droid: The droid object to generate advertise LE objects from.
551
552 Returns:
553 advertise_callback: The generated advertise callback id.
554 advertise_data: The generated advertise data id.
555 advertise_settings: The generated advertise settings id.
556 """
557 advertise_callback = droid.bleGenBleAdvertiseCallback()
558 advertise_data = droid.bleBuildAdvertiseData()
559 advertise_settings = droid.bleBuildAdvertiseSettings()
560 return advertise_callback, advertise_data, advertise_settings
561
562
563def generate_ble_scan_objects(droid):
564 """Generate generic LE scan objects.
565
566 Args:
567 droid: The droid object to generate LE scan objects from.
568
569 Returns:
570 filter_list: The generated scan filter list id.
571 scan_settings: The generated scan settings id.
572 scan_callback: The generated scan callback id.
573 """
574 filter_list = droid.bleGenFilterList()
575 scan_settings = droid.bleBuildScanSetting()
576 scan_callback = droid.bleGenScanCallback()
577 return filter_list, scan_settings, scan_callback
578
579
580def generate_id_by_size(
581 size,
582 chars=(
583 string.ascii_lowercase + string.ascii_uppercase + string.digits)):
584 """Generate random ascii characters of input size and input char types
585
586 Args:
587 size: Input size of string.
588 chars: (Optional) Chars to use in generating a random string.
589
590 Returns:
591 String of random input chars at the input size.
592 """
593 return ''.join(random.choice(chars) for _ in range(size))
594
595
596def get_advanced_droid_list(android_devices):
597 """Add max_advertisement and batch_scan_supported attributes to input
598 Android devices
599
600 This will programatically determine maximum LE advertisements of each
601 input Android device.
602
603 Args:
604 android_devices: The Android devices to setup.
605
606 Returns:
607 List of Android devices with new attribtues.
608 """
609 droid_list = []
610 for a in android_devices:
611 d, e = a.droid, a.ed
612 model = d.getBuildModel()
613 max_advertisements = 1
614 batch_scan_supported = True
615 if model in advertisements_to_devices.keys():
616 max_advertisements = advertisements_to_devices[model]
617 else:
618 max_advertisements = determine_max_advertisements(a)
619 max_tries = 3
620 # Retry to calculate max advertisements
621 while max_advertisements == -1 and max_tries > 0:
622 a.log.info(
623 "Attempts left to determine max advertisements: {}".format(
624 max_tries))
625 max_advertisements = determine_max_advertisements(a)
626 max_tries -= 1
627 advertisements_to_devices[model] = max_advertisements
628 if model in batch_scan_not_supported_list:
629 batch_scan_supported = False
630 role = {
631 'droid': d,
632 'ed': e,
633 'max_advertisements': max_advertisements,
634 'batch_scan_supported': batch_scan_supported
635 }
636 droid_list.append(role)
637 return droid_list
638
639
640def get_bluetooth_crash_count(android_device):
641 out = android_device.adb.shell("dumpsys bluetooth_manager")
642 return int(re.search("crashed(.*\d)", out).group(1))
Tom Turneyf5b42142018-06-22 14:01:27 -0700643
644
Tom Turney9bce15d2018-06-21 13:00:42 -0700645def get_device_selector_dictionary(android_device_list):
646 """Create a dictionary of Bluetooth features vs Android devices.
647
648 Args:
649 android_device_list: The list of Android devices.
650 Returns:
651 A dictionary of profiles/features to Android devices.
652 """
653 selector_dict = {}
654 for ad in android_device_list:
655 uuids = ad.droid.bluetoothGetLocalUuids()
656
657 for profile, uuid_const in sig_uuid_constants.items():
658 uuid_check = sig_uuid_constants['BASE_UUID'].format(
659 uuid_const).lower()
Aidan Holloway-bidwell9e44b9d2018-11-07 14:33:27 -0800660 if uuids and uuid_check in uuids:
Tom Turney9bce15d2018-06-21 13:00:42 -0700661 if profile in selector_dict:
662 selector_dict[profile].append(ad)
663 else:
664 selector_dict[profile] = [ad]
665
666 # Various services may not be active during BT startup.
667 # If the device can be identified through adb shell pm list features
668 # then try to add them to the appropriate profiles / features.
669
670 # Android TV.
671 if "feature:com.google.android.tv.installed" in ad.features:
672 ad.log.info("Android TV device found.")
673 supported_profiles = ['AudioSink']
674 _add_android_device_to_dictionary(ad, supported_profiles,
675 selector_dict)
676
677 # Android Auto
678 elif "feature:android.hardware.type.automotive" in ad.features:
679 ad.log.info("Android Auto device found.")
680 # Add: AudioSink , A/V_RemoteControl,
681 supported_profiles = [
682 'AudioSink', 'A/V_RemoteControl', 'Message Notification Server'
683 ]
684 _add_android_device_to_dictionary(ad, supported_profiles,
685 selector_dict)
686 # Android Wear
687 elif "feature:android.hardware.type.watch" in ad.features:
688 ad.log.info("Android Wear device found.")
689 supported_profiles = []
690 _add_android_device_to_dictionary(ad, supported_profiles,
691 selector_dict)
692 # Android Phone
693 elif "feature:android.hardware.telephony" in ad.features:
694 ad.log.info("Android Phone device found.")
695 # Add: AudioSink
696 supported_profiles = [
697 'AudioSource', 'A/V_RemoteControlTarget',
698 'Message Access Server'
699 ]
700 _add_android_device_to_dictionary(ad, supported_profiles,
701 selector_dict)
702 return selector_dict
703
704
Bill Leung46b69352018-11-09 17:28:39 -0800705def get_mac_address_of_generic_advertisement(scan_ad, adv_ad):
706 """Start generic advertisement and get it's mac address by LE scanning.
Tom Turney9bce15d2018-06-21 13:00:42 -0700707
708 Args:
Bill Leung46b69352018-11-09 17:28:39 -0800709 scan_ad: The Android device to use as the scanner.
710 adv_ad: The Android device to use as the advertiser.
711
712 Returns:
713 mac_address: The mac address of the advertisement.
714 advertise_callback: The advertise callback id of the active
715 advertisement.
Tom Turney9bce15d2018-06-21 13:00:42 -0700716 """
Bill Leung46b69352018-11-09 17:28:39 -0800717 adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
718 adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode(
719 ble_advertise_settings_modes['low_latency'])
720 adv_ad.droid.bleSetAdvertiseSettingsIsConnectable(True)
721 adv_ad.droid.bleSetAdvertiseSettingsTxPowerLevel(
722 ble_advertise_settings_tx_powers['high'])
723 advertise_callback, advertise_data, advertise_settings = (
724 generate_ble_advertise_objects(adv_ad.droid))
725 adv_ad.droid.bleStartBleAdvertising(advertise_callback, advertise_data,
726 advertise_settings)
727 try:
728 adv_ad.ed.pop_event(
729 adv_succ.format(advertise_callback), bt_default_timeout)
730 except Empty as err:
731 raise BtTestUtilsError(
732 "Advertiser did not start successfully {}".format(err))
733 filter_list = scan_ad.droid.bleGenFilterList()
734 scan_settings = scan_ad.droid.bleBuildScanSetting()
735 scan_callback = scan_ad.droid.bleGenScanCallback()
736 scan_ad.droid.bleSetScanFilterDeviceName(
737 adv_ad.droid.bluetoothGetLocalName())
738 scan_ad.droid.bleBuildScanFilter(filter_list)
739 scan_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback)
740 try:
741 event = scan_ad.ed.pop_event(
742 "BleScan{}onScanResults".format(scan_callback), bt_default_timeout)
743 except Empty as err:
744 raise BtTestUtilsError(
745 "Scanner did not find advertisement {}".format(err))
746 mac_address = event['data']['Result']['deviceInfo']['address']
747 return mac_address, advertise_callback, scan_callback
748
749
750def hid_device_send_key_data_report(host_id, device_ad, key, interval=1):
751 """Send a HID report simulating a 1-second keyboard press from host_ad to
752 device_ad
753
754 Args:
755 host_id: the Bluetooth MAC address or name of the HID host
756 device_ad: HID device
757 key: the key we want to send
758 interval: the interval between key press and key release
759 """
760 device_ad.droid.bluetoothHidDeviceSendReport(host_id, hid_id_keyboard,
761 hid_keyboard_report(key))
762 time.sleep(interval)
763 device_ad.droid.bluetoothHidDeviceSendReport(host_id, hid_id_keyboard,
764 hid_keyboard_report("00"))
765
766
767def hid_keyboard_report(key, modifier="00"):
768 """Get the HID keyboard report for the given key
769
770 Args:
771 key: the key we want
772 modifier: HID keyboard modifier bytes
773 Returns:
774 The byte array for the HID report.
775 """
776 return str(
777 bytearray.fromhex(" ".join(
778 [modifier, "00", key, "00", "00", "00", "00", "00"])), "utf-8")
779
780
781def is_a2dp_connected(sink, source):
782 """
783 Convenience Function to see if the 2 devices are connected on
784 A2dp.
785 Args:
786 sink: Audio Sink
787 source: Audio Source
788 Returns:
789 True if Connected
790 False if Not connected
791 """
792
793 devices = sink.droid.bluetoothA2dpSinkGetConnectedDevices()
794 for device in devices:
795 sink.log.info("A2dp Connected device {}".format(device["name"]))
796 if (device["address"] == source.droid.bluetoothGetLocalAddress()):
797 return True
798 return False
799
800
801def is_a2dp_snk_device_connected(ad, addr):
802 """Determines if an AndroidDevice has A2DP snk connectivity to input address
803
804 Args:
805 ad: the Android device
806 addr: the address that's expected
807 Returns:
808 True if connection was successful, false if unsuccessful.
809 """
810 devices = ad.droid.bluetoothA2dpSinkGetConnectedDevices()
811 ad.log.info("Connected A2DP Sink devices: {}".format(devices))
812 if addr in {d['address'] for d in devices}:
813 return True
814 return False
815
816
817def is_a2dp_src_device_connected(ad, addr):
818 """Determines if an AndroidDevice has A2DP connectivity to input address
819
820 Args:
821 ad: the Android device
822 addr: the address that's expected
823 Returns:
824 True if connection was successful, false if unsuccessful.
825 """
826 devices = ad.droid.bluetoothA2dpGetConnectedDevices()
827 ad.log.info("Connected A2DP Source devices: {}".format(devices))
828 if addr in {d['address'] for d in devices}:
829 return True
830 return False
831
832
833def is_hfp_client_device_connected(ad, addr):
834 """Determines if an AndroidDevice has HFP connectivity to input address
835
836 Args:
837 ad: the Android device
838 addr: the address that's expected
839 Returns:
840 True if connection was successful, false if unsuccessful.
841 """
842 devices = ad.droid.bluetoothHfpClientGetConnectedDevices()
843 ad.log.info("Connected HFP Client devices: {}".format(devices))
844 if addr in {d['address'] for d in devices}:
845 return True
846 return False
847
848
849def is_map_mce_device_connected(ad, addr):
850 """Determines if an AndroidDevice has MAP MCE connectivity to input address
851
852 Args:
853 ad: the Android device
854 addr: the address that's expected
855 Returns:
856 True if connection was successful, false if unsuccessful.
857 """
858 devices = ad.droid.bluetoothMapClientGetConnectedDevices()
859 ad.log.info("Connected MAP MCE devices: {}".format(devices))
860 if addr in {d['address'] for d in devices}:
861 return True
862 return False
863
864
865def is_map_mse_device_connected(ad, addr):
866 """Determines if an AndroidDevice has MAP MSE connectivity to input address
867
868 Args:
869 ad: the Android device
870 addr: the address that's expected
871 Returns:
872 True if connection was successful, false if unsuccessful.
873 """
874 devices = ad.droid.bluetoothMapGetConnectedDevices()
875 ad.log.info("Connected MAP MSE devices: {}".format(devices))
876 if addr in {d['address'] for d in devices}:
877 return True
878 return False
879
880
881def kill_bluetooth_process(ad):
882 """Kill Bluetooth process on Android device.
883
884 Args:
885 ad: Android device to kill BT process on.
886 """
887 ad.log.info("Killing Bluetooth process.")
888 pid = ad.adb.shell(
889 "ps | grep com.android.bluetooth | awk '{print $2}'").decode('ascii')
890 call(["adb -s " + ad.serial + " shell kill " + pid], shell=True)
891
892
893def log_energy_info(android_devices, state):
894 """Logs energy info of input Android devices.
895
896 Args:
897 android_devices: input Android device list to log energy info from.
898 state: the input state to log. Usually 'Start' or 'Stop' for logging.
899
900 Returns:
901 A logging string of the Bluetooth energy info reported.
902 """
903 return_string = "{} Energy info collection:\n".format(state)
904 # Bug: b/31966929
905 return return_string
906
907
908def orchestrate_and_verify_pan_connection(pan_dut, panu_dut):
909 """Setups up a PAN conenction between two android devices.
910
911 Args:
912 pan_dut: the Android device providing tethering services
913 panu_dut: the Android device using the internet connection from the
914 pan_dut
915 Returns:
916 True if PAN connection and verification is successful,
917 false if unsuccessful.
918 """
919 if not toggle_airplane_mode_by_adb(log, panu_dut, True):
920 panu_dut.log.error("Failed to toggle airplane mode on")
921 return False
922 if not toggle_airplane_mode_by_adb(log, panu_dut, False):
923 pan_dut.log.error("Failed to toggle airplane mode off")
924 return False
925 pan_dut.droid.bluetoothStartConnectionStateChangeMonitor("")
926 panu_dut.droid.bluetoothStartConnectionStateChangeMonitor("")
927 if not bluetooth_enabled_check(panu_dut):
928 return False
929 if not bluetooth_enabled_check(pan_dut):
930 return False
931 pan_dut.droid.bluetoothPanSetBluetoothTethering(True)
932 if not (pair_pri_to_sec(pan_dut, panu_dut)):
933 return False
934 if not pan_dut.droid.bluetoothPanIsTetheringOn():
935 pan_dut.log.error("Failed to enable Bluetooth tethering.")
936 return False
937 # Magic sleep needed to give the stack time in between bonding and
938 # connecting the PAN profile.
939 time.sleep(pan_connect_timeout)
940 panu_dut.droid.bluetoothConnectBonded(
941 pan_dut.droid.bluetoothGetLocalAddress())
942 if not verify_http_connection(log, panu_dut):
943 panu_dut.log.error("Can't verify http connection on PANU device.")
944 if not verify_http_connection(log, pan_dut):
945 pan_dut.log.info(
946 "Can't verify http connection on PAN service device")
947 return False
948 return True
949
950
951def orchestrate_bluetooth_socket_connection(
952 client_ad,
953 server_ad,
954 accept_timeout_ms=default_bluetooth_socket_timeout_ms,
955 uuid=None):
956 """Sets up the Bluetooth Socket connection between two Android devices.
957
958 Args:
959 client_ad: the Android device performing the connection.
960 server_ad: the Android device accepting the connection.
961 Returns:
962 True if connection was successful, false if unsuccessful.
963 """
964 server_ad.droid.bluetoothStartPairingHelper()
965 client_ad.droid.bluetoothStartPairingHelper()
966
967 server_ad.droid.bluetoothSocketConnBeginAcceptThreadUuid(
968 (bluetooth_socket_conn_test_uuid
969 if uuid is None else uuid), accept_timeout_ms)
970 client_ad.droid.bluetoothSocketConnBeginConnectThreadUuid(
971 server_ad.droid.bluetoothGetLocalAddress(),
972 (bluetooth_socket_conn_test_uuid if uuid is None else uuid))
973
974 end_time = time.time() + bt_default_timeout
975 result = False
976 test_result = True
977 while time.time() < end_time:
978 if len(client_ad.droid.bluetoothSocketConnActiveConnections()) > 0:
979 test_result = True
980 client_ad.log.info("Bluetooth socket Client Connection Active")
981 break
Tom Turney9bce15d2018-06-21 13:00:42 -0700982 else:
Bill Leung46b69352018-11-09 17:28:39 -0800983 test_result = False
984 time.sleep(1)
985 if not test_result:
986 client_ad.log.error(
987 "Failed to establish a Bluetooth socket connection")
988 return False
989 return True
tprotopopov2e18bbb2018-10-02 10:29:01 -0700990
Aidan Holloway-bidwellf8f51512018-11-06 10:42:14 -0800991
Bill Leung46b69352018-11-09 17:28:39 -0800992def orchestrate_rfcomm_connection(client_ad,
993 server_ad,
994 accept_timeout_ms=default_rfcomm_timeout_ms,
995 uuid=None):
996 """Sets up the RFCOMM connection between two Android devices.
997
998 Args:
999 client_ad: the Android device performing the connection.
1000 server_ad: the Android device accepting the connection.
1001 Returns:
1002 True if connection was successful, false if unsuccessful.
1003 """
1004 result = orchestrate_bluetooth_socket_connection(
1005 client_ad, server_ad, accept_timeout_ms,
1006 (bt_rfcomm_uuids['default_uuid'] if uuid is None else uuid))
1007
1008 return result
1009
1010
1011def pair_pri_to_sec(pri_ad, sec_ad, attempts=2, auto_confirm=True):
1012 """Pairs pri droid to secondary droid.
1013
1014 Args:
1015 pri_ad: Android device initiating connection
1016 sec_ad: Android device accepting connection
1017 attempts: Number of attempts to try until failure.
1018 auto_confirm: Auto confirm passkey match for both devices
1019
1020 Returns:
1021 Pass if True
1022 Fail if False
1023 """
1024 pri_ad.droid.bluetoothStartConnectionStateChangeMonitor(
1025 sec_ad.droid.bluetoothGetLocalAddress())
1026 curr_attempts = 0
1027 while curr_attempts < attempts:
1028 if _pair_pri_to_sec(pri_ad, sec_ad, auto_confirm):
1029 return True
1030 # Wait 2 seconds before unbound
1031 time.sleep(2)
1032 if not clear_bonded_devices(pri_ad):
1033 log.error("Failed to clear bond for primary device at attempt {}"
1034 .format(str(curr_attempts)))
1035 return False
1036 if not clear_bonded_devices(sec_ad):
1037 log.error("Failed to clear bond for secondary device at attempt {}"
1038 .format(str(curr_attempts)))
1039 return False
1040 # Wait 2 seconds after unbound
1041 time.sleep(2)
1042 curr_attempts += 1
1043 log.error("pair_pri_to_sec failed to connect after {} attempts".format(
1044 str(attempts)))
1045 return False
1046
1047
1048def _pair_pri_to_sec(pri_ad, sec_ad, auto_confirm):
1049 # Enable discovery on sec_ad so that pri_ad can find it.
1050 # The timeout here is based on how much time it would take for two devices
1051 # to pair with each other once pri_ad starts seeing devices.
1052 pri_droid = pri_ad.droid
1053 sec_droid = sec_ad.droid
1054 pri_ad.ed.clear_all_events()
1055 sec_ad.ed.clear_all_events()
1056 log.info("Bonding device {} to {}".format(
1057 pri_droid.bluetoothGetLocalAddress(),
1058 sec_droid.bluetoothGetLocalAddress()))
1059 sec_droid.bluetoothMakeDiscoverable(bt_default_timeout)
1060 target_address = sec_droid.bluetoothGetLocalAddress()
1061 log.debug("Starting paring helper on each device")
1062 pri_droid.bluetoothStartPairingHelper(auto_confirm)
1063 sec_droid.bluetoothStartPairingHelper(auto_confirm)
1064 pri_ad.log.info("Primary device starting discovery and executing bond")
1065 result = pri_droid.bluetoothDiscoverAndBond(target_address)
1066 if not auto_confirm:
1067 if not _wait_for_passkey_match(pri_ad, sec_ad):
1068 return False
1069 # Loop until we have bonded successfully or timeout.
1070 end_time = time.time() + bt_default_timeout
1071 pri_ad.log.info("Verifying devices are bonded")
1072 while time.time() < end_time:
1073 bonded_devices = pri_droid.bluetoothGetBondedDevices()
1074 bonded = False
1075 for d in bonded_devices:
1076 if d['address'] == target_address:
1077 pri_ad.log.info("Successfully bonded to device")
1078 return True
1079 time.sleep(0.1)
1080 # Timed out trying to bond.
1081 pri_ad.log.info("Failed to bond devices.")
1082 return False
1083
1084
1085def reset_bluetooth(android_devices):
1086 """Resets Bluetooth state of input Android device list.
1087
1088 Args:
1089 android_devices: The Android device list to reset Bluetooth state on.
1090
1091 Returns:
1092 True if successful, false if unsuccessful.
1093 """
1094 for a in android_devices:
1095 droid, ed = a.droid, a.ed
1096 a.log.info("Reset state of bluetooth on device.")
1097 if droid.bluetoothCheckState() is True:
1098 droid.bluetoothToggleState(False)
1099 expected_bluetooth_off_event_name = bluetooth_off
1100 try:
1101 ed.pop_event(expected_bluetooth_off_event_name,
1102 bt_default_timeout)
1103 except Exception:
1104 a.log.error("Failed to toggle Bluetooth off.")
1105 return False
1106 # temp sleep for b/17723234
1107 time.sleep(3)
1108 if not bluetooth_enabled_check(a):
1109 return False
1110 return True
1111
1112
1113def scan_and_verify_n_advertisements(scn_ad, max_advertisements):
1114 """Verify that input number of advertisements can be found from the scanning
1115 Android device.
1116
1117 Args:
1118 scn_ad: The Android device to start LE scanning on.
1119 max_advertisements: The number of advertisements the scanner expects to
1120 find.
1121
1122 Returns:
1123 True if successful, false if unsuccessful.
1124 """
1125 test_result = False
1126 address_list = []
1127 filter_list = scn_ad.droid.bleGenFilterList()
1128 scn_ad.droid.bleBuildScanFilter(filter_list)
1129 scan_settings = scn_ad.droid.bleBuildScanSetting()
1130 scan_callback = scn_ad.droid.bleGenScanCallback()
1131 scn_ad.droid.bleStartBleScan(filter_list, scan_settings, scan_callback)
1132 start_time = time.time()
1133 while (start_time + bt_default_timeout) > time.time():
1134 event = None
1135 try:
1136 event = scn_ad.ed.pop_event(
1137 scan_result.format(scan_callback), bt_default_timeout)
1138 except Empty as error:
1139 raise BtTestUtilsError(
1140 "Failed to find scan event: {}".format(error))
1141 address = event['data']['Result']['deviceInfo']['address']
1142 if address not in address_list:
1143 address_list.append(address)
1144 if len(address_list) == max_advertisements:
1145 test_result = True
1146 break
1147 scn_ad.droid.bleStopBleScan(scan_callback)
1148 return test_result
Aidan Holloway-bidwellf8f51512018-11-06 10:42:14 -08001149
1150
1151def set_bluetooth_codec(
1152 android_device,
1153 codec_type,
1154 sample_rate,
1155 bits_per_sample,
1156 channel_mode,
1157 codec_specific_1=0):
1158 """Sets the A2DP codec configuration on the AndroidDevice.
1159
1160 Args:
1161 android_device (acts.controllers.android_device.AndroidDevice): the
1162 android device for which to switch the codec.
1163 codec_type (str): the desired codec type. Must be a key in
1164 bt_constants.codec_types.
1165 sample_rate (str): the desired sample rate. Must be a key in
1166 bt_constants.sample_rates.
1167 bits_per_sample (str): the desired bits per sample. Must be a key in
1168 bt_constants.bits_per_samples.
1169 channel_mode (str): the desired channel mode. Must be a key in
1170 bt_constants.channel_modes.
1171 codec_specific_1 (int): the desired bit rate (quality) for LDAC codec.
1172 Returns:
1173 bool: True if the codec config was successfully changed to the desired
1174 values. Else False.
1175 """
1176 message = (
1177 "Set Android Device A2DP Bluetooth codec configuration:\n"
1178 "\tCodec: {codec_type}\n"
1179 "\tSample Rate: {sample_rate}\n"
1180 "\tBits per Sample: {bits_per_sample}\n"
1181 "\tChannel Mode: {channel_mode}".format(
1182 codec_type=codec_type,
1183 sample_rate=sample_rate,
1184 bits_per_sample=bits_per_sample,
1185 channel_mode=channel_mode
1186 )
1187 )
1188 android_device.log.info(message)
1189
1190 # Send SL4A command
1191 droid, ed = android_device.droid, android_device.ed
1192 if not droid.bluetoothA2dpSetCodecConfigPreference(
1193 codec_types[codec_type],
1194 sample_rates[str(sample_rate)],
1195 bits_per_samples[str(bits_per_sample)],
1196 channel_modes[channel_mode],
1197 codec_specific_1
1198 ):
Aidan Holloway-bidwell477807a2019-02-01 15:29:00 -08001199 android_device.log.warning("SL4A command returned False. Codec was not "
1200 "changed.")
1201 else:
1202 try:
1203 ed.pop_event(bluetooth_a2dp_codec_config_changed,
1204 bt_default_timeout)
1205 except Exception:
1206 android_device.log.warning("SL4A event not registered. Codec "
1207 "may not have been changed.")
Aidan Holloway-bidwellf8f51512018-11-06 10:42:14 -08001208
1209 # Validate codec value through ADB
Aidan Holloway-bidwell477807a2019-02-01 15:29:00 -08001210 # TODO (aidanhb): validate codec more robustly using SL4A
Aidan Holloway-bidwellf8f51512018-11-06 10:42:14 -08001211 command = "dumpsys bluetooth_manager | grep -i 'current codec'"
1212 out = android_device.adb.shell(command)
1213 split_out = out.split(": ")
1214 if len(split_out) != 2:
1215 android_device.log.warning("Could not verify codec config change "
1216 "through ADB.")
Aidan Holloway-bidwell9e44b9d2018-11-07 14:33:27 -08001217 elif split_out[1].strip().upper() != codec_type:
Aidan Holloway-bidwellf8f51512018-11-06 10:42:14 -08001218 android_device.log.error(
1219 "Codec config was not changed.\n"
1220 "\tExpected codec: {exp}\n"
1221 "\tActual codec: {act}".format(
1222 exp=codec_type,
1223 act=split_out[1].strip()
1224 )
1225 )
1226 return False
1227 android_device.log.info("Bluetooth codec successfully changed.")
1228 return True
Bill Leung46b69352018-11-09 17:28:39 -08001229
1230
1231def set_bt_scan_mode(ad, scan_mode_value):
1232 """Set Android device's Bluetooth scan mode.
1233
1234 Args:
1235 ad: The Android device to set the scan mode on.
1236 scan_mode_value: The value to set the scan mode to.
1237
1238 Returns:
1239 True if successful, false if unsuccessful.
1240 """
1241 droid, ed = ad.droid, ad.ed
1242 if scan_mode_value == bt_scan_mode_types['state_off']:
1243 disable_bluetooth(droid)
1244 scan_mode = droid.bluetoothGetScanMode()
1245 reset_bluetooth([ad])
1246 if scan_mode != scan_mode_value:
1247 return False
1248 elif scan_mode_value == bt_scan_mode_types['none']:
1249 droid.bluetoothMakeUndiscoverable()
1250 scan_mode = droid.bluetoothGetScanMode()
1251 if scan_mode != scan_mode_value:
1252 return False
1253 elif scan_mode_value == bt_scan_mode_types['connectable']:
1254 droid.bluetoothMakeUndiscoverable()
1255 droid.bluetoothMakeConnectable()
1256 scan_mode = droid.bluetoothGetScanMode()
1257 if scan_mode != scan_mode_value:
1258 return False
1259 elif (scan_mode_value == bt_scan_mode_types['connectable_discoverable']):
1260 droid.bluetoothMakeDiscoverable()
1261 scan_mode = droid.bluetoothGetScanMode()
1262 if scan_mode != scan_mode_value:
1263 return False
1264 else:
1265 # invalid scan mode
1266 return False
1267 return True
1268
1269
1270def set_device_name(droid, name):
1271 """Set and check Bluetooth local name on input droid object.
1272
1273 Args:
1274 droid: Droid object to set local name on.
1275 name: the Bluetooth local name to set.
1276
1277 Returns:
1278 True if successful, false if unsuccessful.
1279 """
1280 droid.bluetoothSetLocalName(name)
1281 time.sleep(2)
1282 droid_name = droid.bluetoothGetLocalName()
1283 if droid_name != name:
1284 return False
1285 return True
1286
1287
1288def set_profile_priority(host_ad, client_ad, profiles, priority):
1289 """Sets the priority of said profile(s) on host_ad for client_ad"""
1290 for profile in profiles:
1291 host_ad.log.info("Profile {} on {} for {} set to priority {}".format(
1292 profile, host_ad.droid.bluetoothGetLocalName(),
1293 client_ad.droid.bluetoothGetLocalAddress(), priority.value))
1294 if bt_profile_constants['a2dp_sink'] == profile:
1295 host_ad.droid.bluetoothA2dpSinkSetPriority(
1296 client_ad.droid.bluetoothGetLocalAddress(), priority.value)
1297 elif bt_profile_constants['headset_client'] == profile:
1298 host_ad.droid.bluetoothHfpClientSetPriority(
1299 client_ad.droid.bluetoothGetLocalAddress(), priority.value)
1300 elif bt_profile_constants['pbap_client'] == profile:
1301 host_ad.droid.bluetoothPbapClientSetPriority(
1302 client_ad.droid.bluetoothGetLocalAddress(), priority.value)
1303 else:
1304 host_ad.log.error(
1305 "Profile {} not yet supported for priority settings".format(
1306 profile))
1307
1308
1309def setup_multiple_devices_for_bt_test(android_devices):
1310 """A common setup routine for Bluetooth on input Android device list.
1311
1312 Things this function sets up:
1313 1. Resets Bluetooth
1314 2. Set Bluetooth local name to random string of size 4
1315 3. Disable BLE background scanning.
1316 4. Enable Bluetooth snoop logging.
1317
1318 Args:
1319 android_devices: Android device list to setup Bluetooth on.
1320
1321 Returns:
1322 True if successful, false if unsuccessful.
1323 """
1324 log.info("Setting up Android Devices")
1325 # TODO: Temp fix for an selinux error.
1326 for ad in android_devices:
1327 ad.adb.shell("setenforce 0")
1328 threads = []
1329 try:
1330 for a in android_devices:
1331 thread = threading.Thread(
1332 target=factory_reset_bluetooth, args=([[a]]))
1333 threads.append(thread)
1334 thread.start()
1335 for t in threads:
1336 t.join()
1337
1338 for a in android_devices:
1339 d = a.droid
1340 # TODO: Create specific RPC command to instantiate
1341 # BluetoothConnectionFacade. This is just a workaround.
1342 d.bluetoothStartConnectionStateChangeMonitor("")
1343 setup_result = d.bluetoothSetLocalName(generate_id_by_size(4))
1344 if not setup_result:
1345 a.log.error("Failed to set device name.")
1346 return setup_result
1347 d.bluetoothDisableBLE()
Ted Wange4c70722019-02-21 16:06:53 +08001348 utils.set_location_service(a, True)
Bill Leung46b69352018-11-09 17:28:39 -08001349 bonded_devices = d.bluetoothGetBondedDevices()
1350 for b in bonded_devices:
1351 a.log.info("Removing bond for device {}".format(b['address']))
1352 d.bluetoothUnbond(b['address'])
1353 for a in android_devices:
1354 a.adb.shell("setprop persist.bluetooth.btsnoopenable true")
1355 getprop_result = bool(
1356 a.adb.shell("getprop persist.bluetooth.btsnoopenable"))
1357 if not getprop_result:
1358 a.log.warning("Failed to enable Bluetooth Hci Snoop Logging.")
1359 except Exception as err:
1360 log.error("Something went wrong in multi device setup: {}".format(err))
1361 return False
1362 return setup_result
1363
1364
1365def setup_n_advertisements(adv_ad, num_advertisements):
1366 """Setup input number of advertisements on input Android device.
1367
1368 Args:
1369 adv_ad: The Android device to start LE advertisements on.
1370 num_advertisements: The number of advertisements to start.
1371
1372 Returns:
1373 advertise_callback_list: List of advertisement callback ids.
1374 """
1375 adv_ad.droid.bleSetAdvertiseSettingsAdvertiseMode(
1376 ble_advertise_settings_modes['low_latency'])
1377 advertise_data = adv_ad.droid.bleBuildAdvertiseData()
1378 advertise_settings = adv_ad.droid.bleBuildAdvertiseSettings()
1379 advertise_callback_list = []
1380 for i in range(num_advertisements):
1381 advertise_callback = adv_ad.droid.bleGenBleAdvertiseCallback()
1382 advertise_callback_list.append(advertise_callback)
1383 adv_ad.droid.bleStartBleAdvertising(advertise_callback, advertise_data,
1384 advertise_settings)
1385 try:
1386 adv_ad.ed.pop_event(
1387 adv_succ.format(advertise_callback), bt_default_timeout)
1388 adv_ad.log.info("Advertisement {} started.".format(i + 1))
1389 except Empty as error:
1390 adv_ad.log.error("Advertisement {} failed to start.".format(i + 1))
1391 raise BtTestUtilsError(
1392 "Test failed with Empty error: {}".format(error))
1393 return advertise_callback_list
1394
1395
1396def take_btsnoop_log(ad, testcase, testname):
1397 """Grabs the btsnoop_hci log on a device and stores it in the log directory
1398 of the test class.
1399
1400 If you want grab the btsnoop_hci log, call this function with android_device
1401 objects in on_fail. Bug report takes a relative long time to take, so use
1402 this cautiously.
1403
1404 Args:
1405 ad: The android_device instance to take bugreport on.
1406 testcase: Name of the test calss that triggered this snoop log.
1407 testname: Name of the test case that triggered this bug report.
1408 """
1409 testname = "".join(x for x in testname if x.isalnum())
1410 serial = ad.serial
1411 device_model = ad.droid.getBuildModel()
1412 device_model = device_model.replace(" ", "")
1413 out_name = ','.join((testname, device_model, serial))
1414 snoop_path = ad.log_path + "/BluetoothSnoopLogs"
1415 utils.create_dir(snoop_path)
1416 cmd = ''.join(("adb -s ", serial, " pull ", btsnoop_log_path_on_device,
1417 " ", snoop_path + '/' + out_name, ".btsnoop_hci.log"))
1418 exe_cmd(cmd)
1419 try:
1420 cmd = ''.join(
1421 ("adb -s ", serial, " pull ", btsnoop_last_log_path_on_device, " ",
1422 snoop_path + '/' + out_name, ".btsnoop_hci.log.last"))
1423 exe_cmd(cmd)
1424 except Exception as err:
1425 testcase.log.info(
1426 "File does not exist {}".format(btsnoop_last_log_path_on_device))
1427
1428
1429def take_btsnoop_logs(android_devices, testcase, testname):
1430 """Pull btsnoop logs from an input list of android devices.
1431
1432 Args:
1433 android_devices: the list of Android devices to pull btsnoop logs from.
1434 testcase: Name of the test calss that triggered this snoop log.
1435 testname: Name of the test case that triggered this bug report.
1436 """
1437 for a in android_devices:
1438 take_btsnoop_log(a, testcase, testname)
1439
1440
1441def teardown_n_advertisements(adv_ad, num_advertisements,
1442 advertise_callback_list):
1443 """Stop input number of advertisements on input Android device.
1444
1445 Args:
1446 adv_ad: The Android device to stop LE advertisements on.
1447 num_advertisements: The number of advertisements to stop.
1448 advertise_callback_list: The list of advertisement callbacks to stop.
1449
1450 Returns:
1451 True if successful, false if unsuccessful.
1452 """
1453 for n in range(num_advertisements):
1454 adv_ad.droid.bleStopBleAdvertising(advertise_callback_list[n])
1455 return True
1456
1457
1458def verify_server_and_client_connected(client_ad, server_ad, log=True):
1459 """Verify that input server and client Android devices are connected.
1460
1461 This code is under the assumption that there will only be
1462 a single connection.
1463
1464 Args:
1465 client_ad: the Android device to check number of active connections.
1466 server_ad: the Android device to check number of active connections.
1467
1468 Returns:
1469 True both server and client have at least 1 active connection,
1470 false if unsuccessful.
1471 """
1472 test_result = True
1473 if len(server_ad.droid.bluetoothSocketConnActiveConnections()) == 0:
1474 if log:
1475 server_ad.log.error("No socket connections found on server.")
1476 test_result = False
1477 if len(client_ad.droid.bluetoothSocketConnActiveConnections()) == 0:
1478 if log:
1479 client_ad.log.error("No socket connections found on client.")
1480 test_result = False
1481 return test_result
1482
1483
1484def wait_for_bluetooth_manager_state(droid,
1485 state=None,
1486 timeout=10,
1487 threshold=5):
1488 """ Waits for BlueTooth normalized state or normalized explicit state
1489 args:
1490 droid: droid device object
1491 state: expected BlueTooth state
1492 timeout: max timeout threshold
1493 threshold: list len of bt state
1494 Returns:
1495 True if successful, false if unsuccessful.
1496 """
1497 all_states = []
1498 get_state = lambda: droid.bluetoothGetLeState()
1499 start_time = time.time()
1500 while time.time() < start_time + timeout:
1501 all_states.append(get_state())
1502 if len(all_states) >= threshold:
1503 # for any normalized state
1504 if state is None:
1505 if len(set(all_states[-threshold:])) == 1:
1506 log.info("State normalized {}".format(
1507 set(all_states[-threshold:])))
1508 return True
1509 else:
1510 # explicit check against normalized state
1511 if set([state]).issubset(all_states[-threshold:]):
1512 return True
1513 time.sleep(0.5)
1514 log.error(
1515 "Bluetooth state fails to normalize" if state is None else
1516 "Failed to match bluetooth state, current state {} expected state {}".
1517 format(get_state(), state))
1518 return False
1519
1520
1521def _wait_for_passkey_match(pri_ad, sec_ad):
1522 pri_pin, sec_pin = -1, 1
1523 pri_variant, sec_variant = -1, 1
1524 pri_pairing_req, sec_pairing_req = None, None
1525 try:
1526 pri_pairing_req = pri_ad.ed.pop_event(
1527 event_name="BluetoothActionPairingRequest",
1528 timeout=bt_default_timeout)
1529 pri_variant = pri_pairing_req["data"]["PairingVariant"]
1530 pri_pin = pri_pairing_req["data"]["Pin"]
1531 pri_ad.log.info("Primary device received Pin: {}, Variant: {}".format(
1532 pri_pin, pri_variant))
1533 sec_pairing_req = sec_ad.ed.pop_event(
1534 event_name="BluetoothActionPairingRequest",
1535 timeout=bt_default_timeout)
1536 sec_variant = sec_pairing_req["data"]["PairingVariant"]
1537 sec_pin = sec_pairing_req["data"]["Pin"]
1538 sec_ad.log.info("Secondary device received Pin: {}, Variant: {}"
1539 .format(sec_pin, sec_variant))
1540 except Empty as err:
1541 log.error("Wait for pin error: {}".format(err))
1542 log.error("Pairing request state, Primary: {}, Secondary: {}".format(
1543 pri_pairing_req, sec_pairing_req))
1544 return False
1545 if pri_variant == sec_variant == pairing_variant_passkey_confirmation:
1546 confirmation = pri_pin == sec_pin
1547 if confirmation:
1548 log.info("Pairing code matched, accepting connection")
1549 else:
1550 log.info("Pairing code mismatched, rejecting connection")
1551 pri_ad.droid.eventPost("BluetoothActionPairingRequestUserConfirm",
1552 str(confirmation))
1553 sec_ad.droid.eventPost("BluetoothActionPairingRequestUserConfirm",
1554 str(confirmation))
1555 if not confirmation:
1556 return False
1557 elif pri_variant != sec_variant:
1558 log.error("Pairing variant mismatched, abort connection")
1559 return False
1560 return True
1561
1562
1563def write_read_verify_data(client_ad, server_ad, msg, binary=False):
1564 """Verify that the client wrote data to the server Android device correctly.
1565
1566 Args:
1567 client_ad: the Android device to perform the write.
1568 server_ad: the Android device to read the data written.
1569 msg: the message to write.
1570 binary: if the msg arg is binary or not.
1571
1572 Returns:
1573 True if the data written matches the data read, false if not.
1574 """
1575 client_ad.log.info("Write message.")
1576 try:
1577 if binary:
1578 client_ad.droid.bluetoothSocketConnWriteBinary(msg)
1579 else:
1580 client_ad.droid.bluetoothSocketConnWrite(msg)
1581 except Exception as err:
1582 client_ad.log.error("Failed to write data: {}".format(err))
1583 return False
1584 server_ad.log.info("Read message.")
1585 try:
1586 if binary:
1587 read_msg = server_ad.droid.bluetoothSocketConnReadBinary().rstrip(
1588 "\r\n")
1589 else:
1590 read_msg = server_ad.droid.bluetoothSocketConnRead()
1591 except Exception as err:
1592 server_ad.log.error("Failed to read data: {}".format(err))
1593 return False
1594 log.info("Verify message.")
1595 if msg != read_msg:
1596 log.error("Mismatch! Read: {}, Expected: {}".format(read_msg, msg))
1597 return False
1598 return True
1599