diff options
author | Yimin Li <ymli@google.com> | 2022-04-26 11:30:54 -0700 |
---|---|---|
committer | Yimin Li <ymli@google.com> | 2022-04-26 11:30:54 -0700 |
commit | 17ae718d78b0baa63d6f7bfe769b417f15568b73 (patch) | |
tree | 09313c256b3a38c8aa253e6322d6ec463a4df364 | |
parent | 13435b1c9678462d2ff9f3bb2189f67eb23c2e92 (diff) | |
parent | 6cab953d1b6df0a93630d3c8aa1c351932a6df44 (diff) | |
download | bt-17ae718d78b0baa63d6f7bfe769b417f15568b73.tar.gz |
Merge commit '6cab953d1b6df0a93630d3c8aa1c351932a6df44' of sso://googleplex-android/platform/system/bt into HEAD
Change-Id: I73a6088889d7656b3529a8d4f29abc4b3a077d62
-rw-r--r-- | bta/hearing_aid/hearing_aid.cc | 118 | ||||
-rw-r--r-- | bta/include/bta_hearing_aid_api.h | 12 | ||||
-rw-r--r-- | btif/avrcp/avrcp_service.cc | 10 | ||||
-rw-r--r-- | btif/avrcp/avrcp_service.h | 1 | ||||
-rw-r--r-- | gd/cert/ble_lib.py | 261 | ||||
-rw-r--r-- | gd/cert/bt_constants.py | 740 | ||||
-rw-r--r-- | gd/cert/gd_base_test.py | 2 | ||||
-rw-r--r-- | gd/cert/gd_base_test_lib.py | 3 | ||||
-rw-r--r-- | gd/cert/gd_device.py | 32 | ||||
-rw-r--r-- | gd/cert/gd_sl4a_base_test.py | 129 | ||||
-rw-r--r-- | gd/cert/gd_sl4a_device_config.json | 46 | ||||
-rwxr-xr-x | gd/cert/run | 55 | ||||
-rw-r--r-- | gd/hci/cert/le_advanced_scanning_test.py | 250 | ||||
-rw-r--r-- | gd/hci/facade/le_advertising_manager_facade.cc | 60 | ||||
-rw-r--r-- | osi/src/config.cc | 6 | ||||
-rw-r--r-- | profile/avrcp/avrcp_config.h | 7 | ||||
-rw-r--r-- | stack/acl/btm_acl.cc | 9 | ||||
-rw-r--r-- | stack/gatt/gatt_sr.cc | 3 | ||||
-rw-r--r-- | stack/include/l2c_api.h | 12 | ||||
-rw-r--r-- | stack/l2cap/l2c_api.cc | 28 |
20 files changed, 1716 insertions, 68 deletions
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc index bf3f39fa6..f008a88a2 100644 --- a/bta/hearing_aid/hearing_aid.cc +++ b/bta/hearing_aid/hearing_aid.cc @@ -1152,10 +1152,54 @@ class HearingAidImpl : public HearingAid { hearingDevice->playback_started = true; } + /* Compare the two sides LE CoC credit and return true to drop two sides + * packet on these situations. + * 1) The credit is close + * 2) Other side is disconnected + * 3) Get one side current credit value failure. + * + * Otherwise, just flush audio packet one side. + */ + bool NeedToDropPacket(HearingDevice* target_side, HearingDevice* other_side) { + // Just drop packet if the other side does not exist. + if (!other_side) { + VLOG(2) << __func__ << ": other side not connected to profile"; + return true; + } + + uint16_t diff_credit = 0; + + uint16_t target_current_credit = L2CA_GetPeerLECocCredit( + target_side->address, GAP_ConnGetL2CAPCid(target_side->gap_handle)); + if (target_current_credit == L2CAP_LE_CREDIT_MAX) { + LOG(ERROR) << __func__ << ": Get target side credit value fail."; + return true; + } + + uint16_t other_current_credit = L2CA_GetPeerLECocCredit( + other_side->address, GAP_ConnGetL2CAPCid(other_side->gap_handle)); + if (other_current_credit == L2CAP_LE_CREDIT_MAX) { + LOG(ERROR) << __func__ << ": Get other side credit value fail."; + return true; + } + + if (target_current_credit > other_current_credit) { + diff_credit = target_current_credit - other_current_credit; + } else { + diff_credit = other_current_credit - target_current_credit; + } + VLOG(2) << __func__ << ": Target(" << target_side->address + << ") Credit: " << target_current_credit << ", Other(" + << other_side->address << ") Credit: " << other_current_credit + << ", Init Credit: " << init_credit; + return diff_credit < (init_credit / 2 - 1); + } + void OnAudioDataReady(const std::vector<uint8_t>& data) { /* For now we assume data comes in as 16bit per sample 16kHz PCM stereo */ DVLOG(2) << __func__; + bool need_drop = false; int num_samples = data.size() / (2 /*bytes_per_sample*/ * 2 /*number of channels*/); @@ -1229,16 +1273,24 @@ class HearingAidImpl : public HearingAid { encoded_data_left.resize(encoded_size); uint16_t cid = GAP_ConnGetL2CAPCid(left->gap_handle); - uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); - if (packets_to_flush) { - VLOG(2) << left->address << " skipping " << packets_to_flush - << " packets"; - left->audio_stats.packet_flush_count += packets_to_flush; - left->audio_stats.frame_flush_count++; + uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); + if (packets_in_chans) { + // Compare the two sides LE CoC credit value to confirm need to drop or + // skip audio packet. + if (NeedToDropPacket(left, right)) { + LOG(INFO) << left->address << " triggers dropping, " + << packets_in_chans << " packets in channel"; + need_drop = true; + left->audio_stats.trigger_drop_count++; + } else { + LOG(INFO) << left->address << " skipping " << packets_in_chans + << " packets"; + left->audio_stats.packet_flush_count += packets_in_chans; + left->audio_stats.frame_flush_count++; + L2CA_FlushChannel(cid, 0xffff); + } hearingDevices.StartRssiLog(); } - // flush all packets stuck in queue - L2CA_FlushChannel(cid, 0xffff); check_and_do_rssi_read(left); } @@ -1253,16 +1305,24 @@ class HearingAidImpl : public HearingAid { encoded_data_right.resize(encoded_size); uint16_t cid = GAP_ConnGetL2CAPCid(right->gap_handle); - uint16_t packets_to_flush = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); - if (packets_to_flush) { - VLOG(2) << right->address << " skipping " << packets_to_flush - << " packets"; - right->audio_stats.packet_flush_count += packets_to_flush; - right->audio_stats.frame_flush_count++; + uint16_t packets_in_chans = L2CA_FlushChannel(cid, L2CAP_FLUSH_CHANS_GET); + if (packets_in_chans) { + // Compare the two sides LE CoC credit value to confirm need to drop or + // skip audio packet. + if (NeedToDropPacket(right, left)) { + LOG(INFO) << right->address << " triggers dropping, " + << packets_in_chans << " packets in channel"; + need_drop = true; + right->audio_stats.trigger_drop_count++; + } else { + LOG(INFO) << right->address << " skipping " << packets_in_chans + << " packets"; + right->audio_stats.packet_flush_count += packets_in_chans; + right->audio_stats.frame_flush_count++; + L2CA_FlushChannel(cid, 0xffff); + } hearingDevices.StartRssiLog(); } - // flush all packets stuck in queue - L2CA_FlushChannel(cid, 0xffff); check_and_do_rssi_read(right); } @@ -1272,6 +1332,16 @@ class HearingAidImpl : public HearingAid { uint16_t packet_size = CalcCompressedAudioPacketSize(codec_in_use, default_data_interval_ms); + if (need_drop) { + if (left) { + left->audio_stats.packet_drop_count++; + } + if (right) { + right->audio_stats.packet_drop_count++; + } + return; + } + for (size_t i = 0; i < encoded_data_size; i += packet_size) { if (left) { left->audio_stats.packet_send_count++; @@ -1324,7 +1394,11 @@ class HearingAidImpl : public HearingAid { RawAddress address = *GAP_ConnGetRemoteAddr(gap_handle); uint16_t tx_mtu = GAP_ConnGetRemMtuSize(gap_handle); - LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu; + init_credit = + L2CA_GetPeerLECocCredit(address, GAP_ConnGetL2CAPCid(gap_handle)); + + LOG(INFO) << "GAP_EVT_CONN_OPENED " << address << ", tx_mtu=" << tx_mtu + << ", init_credit=" << init_credit; OnGapConnection(address); break; } @@ -1439,10 +1513,14 @@ class HearingAidImpl : public HearingAid { << (side ? "right" : "left") << " " << loghex(device.hi_sync_id) << std::endl; stream - << " Packet counts (enqueued/flushed) : " + << " Trigger dropped counts : " + << device.audio_stats.trigger_drop_count + << "\n Packet dropped counts : " + << device.audio_stats.packet_drop_count + << "\n Packet counts (send/flush) : " << device.audio_stats.packet_send_count << " / " << device.audio_stats.packet_flush_count - << "\n Frame counts (enqueued/flushed) : " + << "\n Frame counts (sent/flush) : " << device.audio_stats.frame_send_count << " / " << device.audio_stats.frame_flush_count << std::endl; @@ -1602,6 +1680,8 @@ class HearingAidImpl : public HearingAid { uint16_t default_data_interval_ms; + uint16_t init_credit; + HearingDevices hearingDevices; void find_server_changed_ccc_handle(uint16_t conn_id, diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h index 613802a21..6fdd101a0 100644 --- a/bta/include/bta_hearing_aid_api.h +++ b/bta/include/bta_hearing_aid_api.h @@ -70,19 +70,23 @@ struct rssi_log { }; struct AudioStats { - size_t packet_flush_count; + size_t trigger_drop_count; + size_t packet_drop_count; size_t packet_send_count; - size_t frame_flush_count; + size_t packet_flush_count; size_t frame_send_count; + size_t frame_flush_count; std::deque<rssi_log> rssi_history; AudioStats() { Reset(); } void Reset() { - packet_flush_count = 0; + trigger_drop_count = 0; + packet_drop_count = 0; packet_send_count = 0; - frame_flush_count = 0; + packet_flush_count = 0; frame_send_count = 0; + frame_flush_count = 0; } }; diff --git a/btif/avrcp/avrcp_service.cc b/btif/avrcp/avrcp_service.cc index 51d66feac..9a4af3651 100644 --- a/btif/avrcp/avrcp_service.cc +++ b/btif/avrcp/avrcp_service.cc @@ -297,6 +297,13 @@ void AvrcpService::Init(MediaInterface* media_interface, profile_version, 0); btif_dm_add_uuid_to_eir(UUID_SERVCLASS_AV_REM_CTRL_TARGET); + ct_sdp_record_handle = SDP_CreateRecord(); + + avrcp_interface_.AddRecord(UUID_SERVCLASS_AV_REMOTE_CONTROL, + "AV Remote Control", NULL, AVRCP_SUPF_TG_CT, + ct_sdp_record_handle, false, AVRC_REV_1_3, 0); + btif_dm_add_uuid_to_eir(UUID_SERVCLASS_AV_REMOTE_CONTROL); + media_interface_ = new MediaInterfaceWrapper(media_interface); media_interface->RegisterUpdateCallback(instance_); @@ -333,6 +340,9 @@ void AvrcpService::Cleanup() { avrcp_interface_.RemoveRecord(sdp_record_handle); btif_dm_remove_uuid_from_eir(UUID_SERVCLASS_AV_REM_CTRL_TARGET); sdp_record_handle = -1; + avrcp_interface_.RemoveRecord(ct_sdp_record_handle); + btif_dm_remove_uuid_from_eir(UUID_SERVCLASS_AV_REMOTE_CONTROL); + ct_sdp_record_handle = -1; connection_handler_->CleanUp(); connection_handler_ = nullptr; diff --git a/btif/avrcp/avrcp_service.h b/btif/avrcp/avrcp_service.h index 067631ecd..4898bbf54 100644 --- a/btif/avrcp/avrcp_service.h +++ b/btif/avrcp/avrcp_service.h @@ -98,6 +98,7 @@ class AvrcpService : public MediaCallbacks { static ServiceInterfaceImpl* service_interface_; uint32_t sdp_record_handle = -1; + uint32_t ct_sdp_record_handle = -1; uint16_t profile_version = -1; MediaInterface* media_interface_ = nullptr; diff --git a/gd/cert/ble_lib.py b/gd/cert/ble_lib.py new file mode 100644 index 000000000..20eeb81cd --- /dev/null +++ b/gd/cert/ble_lib.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +""" +Ble libraries +""" + +import time +import queue +import logging + +from cert.bt_constants import ble_advertise_settings_modes +from cert.bt_constants import small_timeout +from cert.bt_constants import adv_fail +from cert.bt_constants import adv_succ +from cert.bt_constants import advertising_set_on_own_address_read +from cert.bt_constants import advertising_set_started +from cert.bt_constants import bluetooth_on +from cert.bt_constants import bluetooth_off +from cert.bt_constants import bt_default_timeout + + +def enable_bluetooth(droid, ed): + if droid.bluetoothCheckState(): + return True + + droid.bluetoothToggleState(True) + expected_bluetooth_on_event_name = bluetooth_on + try: + ed.pop_event(expected_bluetooth_on_event_name, bt_default_timeout) + except Exception: + logging.info("Failed to toggle Bluetooth on (no broadcast received)") + if droid.bluetoothCheckState(): + logging.info(".. actual state is ON") + return True + logging.info(".. actual state is OFF") + return False + + return True + + +def disable_bluetooth(droid, ed): + if not droid.bluetoothCheckState(): + return True + droid.bluetoothToggleState(False) + expected_bluetooth_off_event_name = bluetooth_off + try: + ed.pop_event(expected_bluetooth_off_event_name, bt_default_timeout) + except Exception: + logging.info("Failed to toggle Bluetooth off (no broadcast received)") + if droid.bluetoothCheckState(): + logging.info(".. actual state is ON") + return False + logging.info(".. actual state is OFF") + return True + return True + + +def generate_ble_scan_objects(droid): + """Generate generic LE scan objects. + + Args: + droid: The droid object to generate LE scan objects from. + + Returns: + filter_list: The generated scan filter list id. + scan_settings: The generated scan settings id. + scan_callback: The generated scan callback id. + """ + filter_list = droid.bleGenFilterList() + scan_settings = droid.bleBuildScanSetting() + scan_callback = droid.bleGenScanCallback() + return filter_list, scan_settings, scan_callback + + +def generate_ble_advertise_objects(droid): + """Generate generic LE advertise objects. + + Args: + droid: The droid object to generate advertise LE objects from. + + Returns: + advertise_callback: The generated advertise callback id. + advertise_data: The generated advertise data id. + advertise_settings: The generated advertise settings id. + """ + advertise_callback = droid.bleGenBleAdvertiseCallback() + advertise_data = droid.bleBuildAdvertiseData() + advertise_settings = droid.bleBuildAdvertiseSettings() + return advertise_callback, advertise_data, advertise_settings + + +class BleLib(): + + def __init__(self, log, dut): + self.advertisement_list = [] + self.dut = dut + self.log = log + self.default_timeout = 5 + self.set_advertisement_list = [] + self.generic_uuid = "0000{}-0000-1000-8000-00805f9b34fb" + + def _verify_ble_adv_started(self, advertise_callback): + """Helper for verifying if an advertisment started or not""" + regex = "({}|{})".format(adv_succ.format(advertise_callback), adv_fail.format(advertise_callback)) + try: + event = self.dut.ed.pop_events(regex, 5, small_timeout) + except queue.Empty: + self.dut.log.error("Failed to get success or failed event.") + return + if event[0]["name"] == adv_succ.format(advertise_callback): + self.dut.log.info("Advertisement started successfully.") + return True + else: + self.dut.log.info("Advertisement failed to start.") + return False + + def start_generic_connectable_advertisement(self, line): + """Start a connectable LE advertisement""" + scan_response = None + if line: + scan_response = bool(line) + self.dut.droid.bleSetAdvertiseSettingsAdvertiseMode(ble_advertise_settings_modes['low_latency']) + self.dut.droid.bleSetAdvertiseSettingsIsConnectable(True) + advertise_callback, advertise_data, advertise_settings = (generate_ble_advertise_objects(self.dut.droid)) + if scan_response: + self.dut.droid.bleStartBleAdvertisingWithScanResponse(advertise_callback, advertise_data, + advertise_settings, advertise_data) + else: + self.dut.droid.bleStartBleAdvertising(advertise_callback, advertise_data, advertise_settings) + if self._verify_ble_adv_started(advertise_callback): + self.log.info("Tracking Callback ID: {}".format(advertise_callback)) + self.advertisement_list.append(advertise_callback) + self.log.info(self.advertisement_list) + + def start_connectable_advertisement_set(self, line): + """Start Connectable Advertisement Set""" + adv_callback = self.dut.droid.bleAdvSetGenCallback() + adv_data = { + "includeDeviceName": True, + } + self.dut.droid.bleAdvSetStartAdvertisingSet({ + "connectable": True, + "legacyMode": False, + "primaryPhy": "PHY_LE_1M", + "secondaryPhy": "PHY_LE_1M", + "interval": 320 + }, adv_data, None, None, None, 0, 0, adv_callback) + evt = self.dut.ed.pop_event(advertising_set_started.format(adv_callback), self.default_timeout) + set_id = evt['data']['setId'] + self.log.error("did not receive the set started event!") + evt = self.dut.ed.pop_event(advertising_set_on_own_address_read.format(set_id), self.default_timeout) + address = evt['data']['address'] + self.log.info("Advertiser address is: {}".format(str(address))) + self.set_advertisement_list.append(adv_callback) + + def stop_all_advertisement_set(self, line): + """Stop all Advertisement Sets""" + for adv in self.set_advertisement_list: + try: + self.dut.droid.bleAdvSetStopAdvertisingSet(adv) + except Exception as err: + self.log.error("Failed to stop advertisement: {}".format(err)) + + def adv_add_service_uuid_list(self, line): + """Add service UUID to the LE advertisement inputs: + [uuid1 uuid2 ... uuidN]""" + uuids = line.split() + uuid_list = [] + for uuid in uuids: + if len(uuid) == 4: + uuid = self.generic_uuid.format(line) + uuid_list.append(uuid) + self.dut.droid.bleSetAdvertiseDataSetServiceUuids(uuid_list) + + def adv_data_include_local_name(self, is_included): + """Include local name in the advertisement. inputs: [true|false]""" + self.dut.droid.bleSetAdvertiseDataIncludeDeviceName(bool(is_included)) + + def adv_data_include_tx_power_level(self, is_included): + """Include tx power level in the advertisement. inputs: [true|false]""" + self.dut.droid.bleSetAdvertiseDataIncludeTxPowerLevel(bool(is_included)) + + def adv_data_add_manufacturer_data(self, line): + """Include manufacturer id and data to the advertisment: + [id data1 data2 ... dataN]""" + info = line.split() + manu_id = int(info[0]) + manu_data = [] + for data in info[1:]: + manu_data.append(int(data)) + self.dut.droid.bleAddAdvertiseDataManufacturerId(manu_id, manu_data) + + def start_generic_nonconnectable_advertisement(self, line): + """Start a nonconnectable LE advertisement""" + self.dut.droid.bleSetAdvertiseSettingsAdvertiseMode(ble_advertise_settings_modes['low_latency']) + self.dut.droid.bleSetAdvertiseSettingsIsConnectable(False) + advertise_callback, advertise_data, advertise_settings = (generate_ble_advertise_objects(self.dut.droid)) + self.dut.droid.bleStartBleAdvertising(advertise_callback, advertise_data, advertise_settings) + if self._verify_ble_adv_started(advertise_callback): + self.log.info("Tracking Callback ID: {}".format(advertise_callback)) + self.advertisement_list.append(advertise_callback) + self.log.info(self.advertisement_list) + + def stop_all_advertisements(self, line): + """Stop all LE advertisements""" + for callback_id in self.advertisement_list: + self.log.info("Stopping Advertisement {}".format(callback_id)) + self.dut.droid.bleStopBleAdvertising(callback_id) + time.sleep(1) + self.advertisement_list = [] + + def ble_stop_advertisement(self, callback_id): + """Stop an LE advertisement""" + if not callback_id: + self.log.info("Need a callback ID") + return + callback_id = int(callback_id) + if callback_id not in self.advertisement_list: + self.log.info("Callback not in list of advertisements.") + return + self.dut.droid.bleStopBleAdvertising(callback_id) + self.advertisement_list.remove(callback_id) + + def start_max_advertisements(self, line): + scan_response = None + if line: + scan_response = bool(line) + while (True): + try: + self.dut.droid.bleSetAdvertiseSettingsAdvertiseMode(ble_advertise_settings_modes['low_latency']) + self.dut.droid.bleSetAdvertiseSettingsIsConnectable(True) + advertise_callback, advertise_data, advertise_settings = (generate_ble_advertise_objects( + self.dut.droid)) + if scan_response: + self.dut.droid.bleStartBleAdvertisingWithScanResponse(advertise_callback, advertise_data, + advertise_settings, advertise_data) + else: + self.dut.droid.bleStartBleAdvertising(advertise_callback, advertise_data, advertise_settings) + if self._verify_ble_adv_started(advertise_callback): + self.log.info("Tracking Callback ID: {}".format(advertise_callback)) + self.advertisement_list.append(advertise_callback) + self.log.info(self.advertisement_list) + else: + self.log.info("Advertisements active: {}".format(len(self.advertisement_list))) + return False + except Exception as err: + self.log.info("Advertisements active: {}".format(len(self.advertisement_list))) + return True diff --git a/gd/cert/bt_constants.py b/gd/cert/bt_constants.py new file mode 100644 index 000000000..f144ef57f --- /dev/null +++ b/gd/cert/bt_constants.py @@ -0,0 +1,740 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2016 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +### Generic Constants Begin ### + +bt_default_timeout = 15 +default_rfcomm_timeout_ms = 10000 +default_bluetooth_socket_timeout_ms = 10000 +pan_connect_timeout = 5 +bt_discovery_timeout = 3 +small_timeout = 0.0001 + +# Time delay (in seconds) at the end of each LE CoC Test to give sufficient time +# for the ACL LE link to be disconnected. The ACL link stays connected after +# L2CAP disconnects. An example of the timeout is L2CAP_LINK_INACTIVITY_TOUT. +# This delay must be greater than the maximum of these timeouts. +# TODO: Investigate the use of broadcast intent +# BluetoothDevice.ACTION_ACL_DISCONNECTED to replace this delay method. +l2cap_max_inactivity_delay_after_disconnect = 5 + +# LE specifications related constants +le_connection_interval_time_step_ms = 1.25 +le_default_supervision_timeout = 2000 +default_le_data_length = 23 +default_le_connection_interval_ms = 30 +le_connection_event_time_step_ms = 0.625 + +# Headers of LE L2CAP Connection-oriented Channels. See section 3.4, Vol +# 3, Part A, Version 5.0. +l2cap_header_size = 4 +l2cap_coc_sdu_length_field_size = 2 +l2cap_coc_header_size = l2cap_header_size + l2cap_coc_sdu_length_field_size + +java_integer = {"min": -2147483648, "max": 2147483647} + +btsnoop_log_path_on_device = "/data/misc/bluetooth/logs/btsnoop_hci.log" +btsnoop_last_log_path_on_device = \ + "/data/misc/bluetooth/logs/btsnoop_hci.log.last" +pairing_variant_passkey_confirmation = 2 + +# Callback strings +scan_result = "BleScan{}onScanResults" +scan_failed = "BleScan{}onScanFailed" +batch_scan_result = "BleScan{}onBatchScanResult" +adv_fail = "BleAdvertise{}onFailure" +adv_succ = "BleAdvertise{}onSuccess" +bluetooth_off = "BluetoothStateChangedOff" +bluetooth_on = "BluetoothStateChangedOn" +mtu_changed = "GattConnect{}onMtuChanged" +advertising_set_started = "AdvertisingSet{}onAdvertisingSetStarted" +advertising_set_stopped = "AdvertisingSet{}onAdvertisingSetStopped" +advertising_set_on_own_address_read = "AdvertisingSet{}onOwnAddressRead" +advertising_set_enabled = "AdvertisingSet{}onAdvertisingEnabled" +advertising_set_data_set = "AdvertisingSet{}onAdvertisingDataSet" +advertising_set_scan_response_set = "AdvertisingSet{}onScanResponseDataSet" +advertising_set_parameters_update = \ + "AdvertisingSet{}onAdvertisingParametersUpdated" +advertising_set_periodic_parameters_updated = \ + "AdvertisingSet{}onPeriodicAdvertisingParametersUpdated" +advertising_set_periodic_data_set = \ + "AdvertisingSet{}onPeriodicAdvertisingDataSet" +advertising_set_periodic_enable = "AdvertisingSet{}onPeriodicAdvertisingEnable" +bluetooth_profile_connection_state_changed = \ + "BluetoothProfileConnectionStateChanged" +bluetooth_le_on = "BleStateChangedOn" +bluetooth_le_off = "BleStateChangedOff" +bluetooth_a2dp_codec_config_changed = "BluetoothA2dpCodecConfigChanged" +# End Callback Strings + +batch_scan_not_supported_list = [ + "Nexus 4", + "Nexus 5", + "Nexus 7", +] + +### Generic Constants End ### + +### Bluetooth Constants Begin ### + +# rfcomm test uuids +rfcomm_secure_uuid = "fa87c0d0-afac-11de-8a39-0800200c9a66" +rfcomm_insecure_uuid = "8ce255c0-200a-11e0-ac64-0800200c9a66" + +# bluetooth socket connection test uuid +bluetooth_socket_conn_test_uuid = "12345678-1234-5678-9abc-123456789abc" + +# Bluetooth Adapter Scan Mode Types +bt_scan_mode_types = {"state_off": -1, "none": 0, "connectable": 1, "connectable_discoverable": 3} + +# Bluetooth Adapter State Constants +bt_adapter_states = { + "off": 10, + "turning_on": 11, + "on": 12, + "turning_off": 13, + "ble_turning_on": 14, + "ble_on": 15, + "ble_turning_off": 16 +} + +# Should be kept in sync with BluetoothProfile.java +bt_profile_constants = { + "headset": 1, + "a2dp": 2, + "health": 3, + "input_device": 4, + "pan": 5, + "pbap_server": 6, + "gatt": 7, + "gatt_server": 8, + "map": 9, + "sap": 10, + "a2dp_sink": 11, + "avrcp_controller": 12, + "headset_client": 16, + "pbap_client": 17, + "map_mce": 18 +} + +# Bluetooth RFCOMM UUIDs as defined by the SIG +bt_rfcomm_uuids = { + "default_uuid": "457807c0-4897-11df-9879-0800200c9a66", + "base_uuid": "00000000-0000-1000-8000-00805F9B34FB", + "sdp": "00000001-0000-1000-8000-00805F9B34FB", + "udp": "00000002-0000-1000-8000-00805F9B34FB", + "rfcomm": "00000003-0000-1000-8000-00805F9B34FB", + "tcp": "00000004-0000-1000-8000-00805F9B34FB", + "tcs_bin": "00000005-0000-1000-8000-00805F9B34FB", + "tcs_at": "00000006-0000-1000-8000-00805F9B34FB", + "att": "00000007-0000-1000-8000-00805F9B34FB", + "obex": "00000008-0000-1000-8000-00805F9B34FB", + "ip": "00000009-0000-1000-8000-00805F9B34FB", + "ftp": "0000000A-0000-1000-8000-00805F9B34FB", + "http": "0000000C-0000-1000-8000-00805F9B34FB", + "wsp": "0000000E-0000-1000-8000-00805F9B34FB", + "bnep": "0000000F-0000-1000-8000-00805F9B34FB", + "upnp": "00000010-0000-1000-8000-00805F9B34FB", + "hidp": "00000011-0000-1000-8000-00805F9B34FB", + "hardcopy_control_channel": "00000012-0000-1000-8000-00805F9B34FB", + "hardcopy_data_channel": "00000014-0000-1000-8000-00805F9B34FB", + "hardcopy_notification": "00000016-0000-1000-8000-00805F9B34FB", + "avctp": "00000017-0000-1000-8000-00805F9B34FB", + "avdtp": "00000019-0000-1000-8000-00805F9B34FB", + "cmtp": "0000001B-0000-1000-8000-00805F9B34FB", + "mcap_control_channel": "0000001E-0000-1000-8000-00805F9B34FB", + "mcap_data_channel": "0000001F-0000-1000-8000-00805F9B34FB", + "l2cap": "00000100-0000-1000-8000-00805F9B34FB" +} + +# Should be kept in sync with BluetoothProfile#STATE_* constants. +bt_profile_states = {"disconnected": 0, "connecting": 1, "connected": 2, "disconnecting": 3} + +# Access Levels from BluetoothDevice. +bt_access_levels = {"access_allowed": 1, "access_denied": 2} + +# Priority levels as defined in BluetoothProfile.java. +bt_priority_levels = {"auto_connect": 1000, "on": 100, "off": 0, "undefined": -1} + +# A2DP codec configuration constants as defined in +# frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java +codec_types = {'SBC': 0, 'AAC': 1, 'APTX': 2, 'APTX-HD': 3, 'LDAC': 4, 'MAX': 5, 'INVALID': 1000000} + +codec_priorities = {'DISABLED': -1, 'DEFAULT': 0, 'HIGHEST': 1000000} + +sample_rates = { + 'NONE': 0, + '44100': 0x1 << 0, + '48000': 0x1 << 1, + '88200': 0x1 << 2, + '96000': 0x1 << 3, + '176400': 0x1 << 4, + '192000': 0x1 << 5 +} + +bits_per_samples = {'NONE': 0, '16': 0x1 << 0, '24': 0x1 << 1, '32': 0x1 << 2} + +channel_modes = {'NONE': 0, 'MONO': 0x1 << 0, 'STEREO': 0x1 << 1} + +# Bluetooth HID constants. +hid_connection_timeout = 5 + +# Bluetooth HID EventFacade constants. +hid_on_set_report_event = "onSetReport" +hid_on_get_report_event = "onGetReport" +hid_on_set_protocol_event = "onSetProtocol" +hid_on_intr_data_event = "onInterruptData" +hid_on_virtual_cable_unplug_event = "onVirtualCableUnplug" +hid_id_keyboard = 1 +hid_id_mouse = 2 +hid_default_event_timeout = 15 +hid_default_set_report_payload = "Haha" + +### Bluetooth Constants End ### + +### Bluetooth Low Energy Constants Begin ### + +# Bluetooth Low Energy address types +ble_address_types = {"public": 0, "random": 1} + +# Bluetooth Low Energy scan callback types +ble_scan_settings_callback_types = {"all_matches": 1, "first_match": 2, "match_lost": 4, "found_and_lost": 6} + +# Bluetooth Low Energy scan settings match mode +ble_scan_settings_match_modes = {"aggresive": 1, "sticky": 2} + +# Bluetooth Low Energy scan settings match nums +ble_scan_settings_match_nums = {"one": 1, "few": 2, "max": 3} + +# Bluetooth Low Energy scan settings result types +ble_scan_settings_result_types = {"full": 0, "abbreviated": 1} + +# Bluetooth Low Energy scan settings mode +ble_scan_settings_modes = { + "opportunistic": -1, + "low_power": 0, + "balanced": 1, + "low_latency": 2, + "ambient_discovery": 3, +} + +# Bluetooth Low Energy scan settings report delay millis +ble_scan_settings_report_delay_milli_seconds = {"min": 0, "max": 9223372036854775807} + +# Bluetooth Low Energy scan settings phy +ble_scan_settings_phys = {"1m": 1, "2m": 2, "coded": 3, "all_supported": 255} + +# Bluetooth Low Energy advertise settings types +ble_advertise_settings_types = {"non_connectable": 0, "connectable": 1} + +# Bluetooth Low Energy advertise settings modes +ble_advertise_settings_modes = {"low_power": 0, "balanced": 1, "low_latency": 2} + +# Bluetooth Low Energy advertise settings tx power +ble_advertise_settings_tx_powers = {"ultra_low": 0, "low": 1, "medium": 2, "high": 3} + +# Bluetooth Low Energy service uuids for specific devices +ble_uuids = {"p_service": "0000feef-0000-1000-8000-00805f9b34fb", "hr_service": "0000180d-0000-1000-8000-00805f9b34fb"} + +# Bluetooth Low Energy advertising error codes +ble_advertise_error_code = { + "data_too_large": 1, + "too_many_advertisers": 2, + "advertisement_already_started": 3, + "bluetooth_internal_failure": 4, + "feature_not_supported": 5 +} + +### Bluetooth Low Energy Constants End ### + +### Bluetooth GATT Constants Begin ### + +# Gatt Callback error messages +gatt_cb_err = { + "char_write_req_err": "Characteristic Write Request event not found. Expected {}", + "char_write_err": "Characteristic Write event not found. Expected {}", + "desc_write_req_err": "Descriptor Write Request event not found. Expected {}", + "desc_write_err": "Descriptor Write event not found. Expected {}", + "char_read_err": "Characteristic Read event not found. Expected {}", + "char_read_req_err": "Characteristic Read Request not found. Expected {}", + "desc_read_err": "Descriptor Read event not found. Expected {}", + "desc_read_req_err": "Descriptor Read Request event not found. Expected {}", + "rd_remote_rssi_err": "Read Remote RSSI event not found. Expected {}", + "gatt_serv_disc_err": "GATT Services Discovered event not found. Expected {}", + "serv_added_err": "Service Added event not found. Expected {}", + "mtu_changed_err": "MTU Changed event not found. Expected {}", + "mtu_serv_changed_err": "MTU Server Changed event not found. Expected {}", + "gatt_conn_changed_err": "GATT Connection Changed event not found. Expected {}", + "char_change_err": "GATT Characteristic Changed event not fond. Expected {}", + "phy_read_err": "Phy Read event not fond. Expected {}", + "phy_update_err": "Phy Update event not fond. Expected {}", + "exec_write_err": "GATT Execute Write event not found. Expected {}" +} + +# GATT callback strings as defined in GattClientFacade.java and +# GattServerFacade.java implemented callbacks. +gatt_cb_strings = { + "char_write_req": "GattServer{}onCharacteristicWriteRequest", + "exec_write": "GattServer{}onExecuteWrite", + "char_write": "GattConnect{}onCharacteristicWrite", + "desc_write_req": "GattServer{}onDescriptorWriteRequest", + "desc_write": "GattConnect{}onDescriptorWrite", + "char_read": "GattConnect{}onCharacteristicRead", + "char_read_req": "GattServer{}onCharacteristicReadRequest", + "desc_read": "GattConnect{}onDescriptorRead", + "desc_read_req": "GattServer{}onDescriptorReadRequest", + "rd_remote_rssi": "GattConnect{}onReadRemoteRssi", + "gatt_serv_disc": "GattConnect{}onServicesDiscovered", + "serv_added": "GattServer{}onServiceAdded", + "mtu_changed": "GattConnect{}onMtuChanged", + "mtu_serv_changed": "GattServer{}onMtuChanged", + "gatt_conn_change": "GattConnect{}onConnectionStateChange", + "char_change": "GattConnect{}onCharacteristicChanged", + "phy_read": "GattConnect{}onPhyRead", + "phy_update": "GattConnect{}onPhyUpdate", + "serv_phy_read": "GattServer{}onPhyRead", + "serv_phy_update": "GattServer{}onPhyUpdate", +} + +# GATT event dictionary of expected callbacks and errors. +gatt_event = { + "char_write_req": { + "evt": gatt_cb_strings["char_write_req"], + "err": gatt_cb_err["char_write_req_err"] + }, + "exec_write": { + "evt": gatt_cb_strings["exec_write"], + "err": gatt_cb_err["exec_write_err"] + }, + "char_write": { + "evt": gatt_cb_strings["char_write"], + "err": gatt_cb_err["char_write_err"] + }, + "desc_write_req": { + "evt": gatt_cb_strings["desc_write_req"], + "err": gatt_cb_err["desc_write_req_err"] + }, + "desc_write": { + "evt": gatt_cb_strings["desc_write"], + "err": gatt_cb_err["desc_write_err"] + }, + "char_read": { + "evt": gatt_cb_strings["char_read"], + "err": gatt_cb_err["char_read_err"] + }, + "char_read_req": { + "evt": gatt_cb_strings["char_read_req"], + "err": gatt_cb_err["char_read_req_err"] + }, + "desc_read": { + "evt": gatt_cb_strings["desc_read"], + "err": gatt_cb_err["desc_read_err"] + }, + "desc_read_req": { + "evt": gatt_cb_strings["desc_read_req"], + "err": gatt_cb_err["desc_read_req_err"] + }, + "rd_remote_rssi": { + "evt": gatt_cb_strings["rd_remote_rssi"], + "err": gatt_cb_err["rd_remote_rssi_err"] + }, + "gatt_serv_disc": { + "evt": gatt_cb_strings["gatt_serv_disc"], + "err": gatt_cb_err["gatt_serv_disc_err"] + }, + "serv_added": { + "evt": gatt_cb_strings["serv_added"], + "err": gatt_cb_err["serv_added_err"] + }, + "mtu_changed": { + "evt": gatt_cb_strings["mtu_changed"], + "err": gatt_cb_err["mtu_changed_err"] + }, + "gatt_conn_change": { + "evt": gatt_cb_strings["gatt_conn_change"], + "err": gatt_cb_err["gatt_conn_changed_err"] + }, + "char_change": { + "evt": gatt_cb_strings["char_change"], + "err": gatt_cb_err["char_change_err"] + }, + "phy_read": { + "evt": gatt_cb_strings["phy_read"], + "err": gatt_cb_err["phy_read_err"] + }, + "phy_update": { + "evt": gatt_cb_strings["phy_update"], + "err": gatt_cb_err["phy_update_err"] + }, + "serv_phy_read": { + "evt": gatt_cb_strings["serv_phy_read"], + "err": gatt_cb_err["phy_read_err"] + }, + "serv_phy_update": { + "evt": gatt_cb_strings["serv_phy_update"], + "err": gatt_cb_err["phy_update_err"] + } +} + +# Matches constants of connection states defined in BluetoothGatt.java +gatt_connection_state = {"disconnected": 0, "connecting": 1, "connected": 2, "disconnecting": 3, "closed": 4} + +# Matches constants of Bluetooth GATT Characteristic values as defined +# in BluetoothGattCharacteristic.java +gatt_characteristic = { + "property_broadcast": 0x01, + "property_read": 0x02, + "property_write_no_response": 0x04, + "property_write": 0x08, + "property_notify": 0x10, + "property_indicate": 0x20, + "property_signed_write": 0x40, + "property_extended_props": 0x80, + "permission_read": 0x01, + "permission_read_encrypted": 0x02, + "permission_read_encrypted_mitm": 0x04, + "permission_write": 0x10, + "permission_write_encrypted": 0x20, + "permission_write_encrypted_mitm": 0x40, + "permission_write_signed": 0x80, + "permission_write_signed_mitm": 0x100, + "write_type_default": 0x02, + "write_type_no_response": 0x01, + "write_type_signed": 0x04, +} + +# Matches constants of Bluetooth GATT Characteristic values as defined +# in BluetoothGattDescriptor.java +gatt_descriptor = { + "enable_notification_value": [0x01, 0x00], + "enable_indication_value": [0x02, 0x00], + "disable_notification_value": [0x00, 0x00], + "permission_read": 0x01, + "permission_read_encrypted": 0x02, + "permission_read_encrypted_mitm": 0x04, + "permission_write": 0x10, + "permission_write_encrypted": 0x20, + "permission_write_encrypted_mitm": 0x40, + "permission_write_signed": 0x80, + "permission_write_signed_mitm": 0x100 +} + +# https://www.bluetooth.com/specifications/gatt/descriptors +gatt_char_desc_uuids = { + "char_ext_props": '00002900-0000-1000-8000-00805f9b34fb', + "char_user_desc": '00002901-0000-1000-8000-00805f9b34fb', + "client_char_cfg": '00002902-0000-1000-8000-00805f9b34fb', + "server_char_cfg": '00002903-0000-1000-8000-00805f9b34fb', + "char_fmt_uuid": '00002904-0000-1000-8000-00805f9b34fb', + "char_agreg_fmt": '00002905-0000-1000-8000-00805f9b34fb', + "char_valid_range": '00002906-0000-1000-8000-00805f9b34fb', + "external_report_reference": '00002907-0000-1000-8000-00805f9b34fb', + "report_reference": '00002908-0000-1000-8000-00805f9b34fb' +} + +# https://www.bluetooth.com/specifications/gatt/characteristics +gatt_char_types = { + "device_name": '00002a00-0000-1000-8000-00805f9b34fb', + "appearance": '00002a01-0000-1000-8000-00805f9b34fb', + "peripheral_priv_flag": '00002a02-0000-1000-8000-00805f9b34fb', + "reconnection_address": '00002a03-0000-1000-8000-00805f9b34fb', + "peripheral_pref_conn": '00002a04-0000-1000-8000-00805f9b34fb', + "service_changed": '00002a05-0000-1000-8000-00805f9b34fb', + "system_id": '00002a23-0000-1000-8000-00805f9b34fb', + "model_number_string": '00002a24-0000-1000-8000-00805f9b34fb', + "serial_number_string": '00002a25-0000-1000-8000-00805f9b34fb', + "firmware_revision_string": '00002a26-0000-1000-8000-00805f9b34fb', + "hardware_revision_string": '00002a27-0000-1000-8000-00805f9b34fb', + "software_revision_string": '00002a28-0000-1000-8000-00805f9b34fb', + "manufacturer_name_string": '00002a29-0000-1000-8000-00805f9b34fb', + "pnp_id": '00002a50-0000-1000-8000-00805f9b34fb', +} + +# Matches constants of Bluetooth GATT Characteristic values as defined +# in BluetoothGattCharacteristic.java +gatt_characteristic_value_format = { + "string": 0x1, + "byte": 0x2, + "sint8": 0x21, + "uint8": 0x11, + "sint16": 0x22, + "unit16": 0x12, + "sint32": 0x24, + "uint32": 0x14 +} + +# Matches constants of Bluetooth Gatt Service types as defined in +# BluetoothGattService.java +gatt_service_types = {"primary": 0, "secondary": 1} + +# Matches constants of Bluetooth Gatt Connection Priority values as defined in +# BluetoothGatt.java +gatt_connection_priority = {"balanced": 0, "high": 1, "low_power": 2} + +# Min and max MTU values +gatt_mtu_size = {"min": 23, "max": 217} + +# Gatt Characteristic attribute lengths +gatt_characteristic_attr_length = {"attr_1": 1, "attr_2": 3, "attr_3": 15} + +# Matches constants of Bluetooth Gatt operations status as defined in +# BluetoothGatt.java +gatt_status = {"success": 0, "failure": 0x101} + +# Matches constants of Bluetooth transport values as defined in +# BluetoothDevice.java +gatt_transport = {"auto": 0x00, "bredr": 0x01, "le": 0x02} + +# Matches constants of Bluetooth physical channeling values as defined in +# BluetoothDevice.java +gatt_phy = {"1m": 1, "2m": 2, "le_coded": 3} + +# Matches constants of Bluetooth physical channeling bitmask values as defined +# in BluetoothDevice.java +gatt_phy_mask = {"1m_mask": 1, "2m_mask": 2, "coded_mask": 4} + +# Values as defiend in the Bluetooth GATT specification +gatt_server_responses = { + "GATT_SUCCESS": 0x0, + "GATT_FAILURE": 0x1, + "GATT_READ_NOT_PERMITTED": 0x2, + "GATT_WRITE_NOT_PERMITTED": 0x3, + "GATT_INVALID_PDU": 0x4, + "GATT_INSUFFICIENT_AUTHENTICATION": 0x5, + "GATT_REQUEST_NOT_SUPPORTED": 0x6, + "GATT_INVALID_OFFSET": 0x7, + "GATT_INSUFFICIENT_AUTHORIZATION": 0x8, + "GATT_INVALID_ATTRIBUTE_LENGTH": 0xd, + "GATT_INSUFFICIENT_ENCRYPTION": 0xf, + "GATT_CONNECTION_CONGESTED": 0x8f, + "GATT_13_ERR": 0x13, + "GATT_12_ERR": 0x12, + "GATT_0C_ERR": 0x0C, + "GATT_16": 0x16 +} + +### Bluetooth GATT Constants End ### + +### Chameleon Constants Begin ### + +# Chameleon audio bits per sample. +audio_bits_per_sample_16 = 16 +audio_bits_per_sample_24 = 24 +audio_bits_per_sample_32 = 32 + +# Chameleon audio sample rates. +audio_sample_rate_44100 = 44100 +audio_sample_rate_48000 = 48000 +audio_sample_rate_88200 = 88200 +audio_sample_rate_96000 = 96000 + +# Chameleon audio channel modes. +audio_channel_mode_mono = 1 +audio_channel_mode_stereo = 2 +audio_channel_mode_8 = 8 + +# Chameleon time delays. +delay_after_binding_seconds = 0.5 +delay_before_record_seconds = 0.5 +silence_wait_seconds = 5 + +# Chameleon bus endpoints. +fpga_linein_bus_endpoint = 'Chameleon FPGA line-in' +headphone_bus_endpoint = 'Cros device headphone' + +### Chameleon Constants End ### + +# Begin logcat strings dict""" +logcat_strings = { + "media_playback_vol_changed": "onRouteVolumeChanged", +} + +# End logcat strings dict""" + +### Begin Service Discovery UUIDS ### +# Values match the Bluetooth SIG defined values: """ +""" https://www.bluetooth.com/specifications/assigned-numbers/service-discovery """ +sig_uuid_constants = { + "BASE_UUID": "0000{}-0000-1000-8000-00805F9B34FB", + "SDP": "0001", + "UDP": "0002", + "RFCOMM": "0003", + "TCP": "0004", + "TCS-BIN": "0005", + "TCS-AT": "0006", + "ATT": "0007", + "OBEX": "0008", + "IP": "0009", + "FTP": "000A", + "HTTP": "000C", + "WSP": "000E", + "BNEP": "000F", + "UPNP": "0010", + "HIDP": "0011", + "HardcopyControlChannel": "0012", + "HardcopyDataChannel": "0014", + "HardcopyNotification": "0016", + "AVCTP": "0017", + "AVDTP": "0019", + "CMTP": "001B", + "MCAPControlChannel": "001E", + "MCAPDataChannel": "001F", + "L2CAP": "0100", + "ServiceDiscoveryServerServiceClassID": "1000", + "BrowseGroupDescriptorServiceClassID": "1001", + "SerialPort": "1101", + "LANAccessUsingPPP": "1102", + "DialupNetworking": "1103", + "IrMCSync": "1104", + "OBEXObjectPush": "1105", + "OBEXFileTransfer": "1106", + "IrMCSyncCommand": "1107", + "Headset": "1108", + "CordlessTelephony": "1109", + "AudioSource": "110A", + "AudioSink": "110B", + "A/V_RemoteControlTarget": "110C", + "AdvancedAudioDistribution": "110D", + "A/V_RemoteControl": "110E", + "A/V_RemoteControlController": "110F", + "Intercom": "1110", + "Fax": "1111", + "Headset - Audio Gateway (AG)": "1112", + "WAP": "1113", + "WAP_CLIENT": "1114", + "PANU": "1115", + "NAP": "1116", + "GN": "1117", + "DirectPrinting": "1118", + "ReferencePrinting": "1119", + "ImagingResponder": "111B", + "ImagingAutomaticArchive": "111C", + "ImagingReferencedObjects": "111D", + "Handsfree": "111E", + "HandsfreeAudioGateway": "111F", + "DirectPrintingReferenceObjectsService": "1120", + "ReflectedUI": "1121", + "BasicPrinting": "1122", + "PrintingStatus": "1123", + "HumanInterfaceDeviceService": "1124", + "HardcopyCableReplacement": "1125", + "HCR_Print": "1126", + "HCR_Scan": "1127", + "Common_ISDN_Access": "1128", + "SIM_Access": "112D", + "Phonebook Access - PCE": "112E", + "Phonebook Access - PSE": "112F", + "Phonebook Access": "1130", + "Headset - HS": "1131", + "Message Access Server": "1132", + "Message Notification Server": "1133", + "Message Access Profile": "1134", + "GNSS": "1135", + "GNSS_Server": "1136", + "PnPInformation": "1200", + "GenericNetworking": "1201", + "GenericFileTransfer": "1202", + "GenericAudio": "1203", + "GenericTelephony": "1204", + "UPNP_Service": "1205", + "UPNP_IP_Service": "1206", + "ESDP_UPNP_IP_PAN": "1300", + "ESDP_UPNP_IP_LAP": "1301", + "ESDP_UPNP_L2CAP": "1302", + "VideoSource": "1303", + "VideoSink": "1304", + "VideoDistribution": "1305", + "HDP": "1400" +} + +### End Service Discovery UUIDS ### + +### Begin Appearance Constants ### +# https://www.bluetooth.com/wp-content/uploads/Sitecore-Media-Library/Gatt/Xml/Characteristics/org.bluetooth.characteristic.gap.appearance.xml +sig_appearance_constants = { + "UNKNOWN": 0, + "PHONE": 64, + "COMPUTER": 128, + "WATCH": 192, + "WATCH_SPORTS": 193, + "CLOCK": 256, + "DISPLAY": 320, + "REMOTE_CONTROL": 384, + "EYE_GLASSES": 448, + "TAG": 512, + "KEYRING": 576, + "MEDIA_PLAYER": 640, + "BARCODE_SCANNER": 704, + "THERMOMETER": 768, + "THERMOMETER_EAR": 769, + "HEART_RATE_SENSOR": 832, + "HEART_RATE_SENSOR_BELT": 833, + "BLOOD_PRESSURE": 896, + "BLOOD_PRESSURE_ARM": 897, + "BLOOD_PRESSURE_WRIST": 898, + "HID": 960, + "HID_KEYBOARD": 961, + "HID_MOUSE": 962, + "HID_JOYSTICK": 963, + "HID_GAMEPAD": 964, + "HID_DIGITIZER_TABLET": 965, + "HID_CARD_READER": 966, + "HID_DIGITAL_PEN": 967, + "HID_BARCODE_SCANNER": 968, + "GLUCOSE_METER": 1024, + "RUNNING_WALKING_SENSOR": 1088, + "RUNNING_WALKING_SENSOR_IN_SHOE": 1089, + "RUNNING_WALKING_SENSOR_ON_SHOE": 1090, + "RUNNING_WALKING_SENSOR_ON_HIP": 1091, + "CYCLING": 1152, + "CYCLING_COMPUTER": 1153, + "CYCLING_SPEED_SENSOR": 1154, + "CYCLING_CADENCE_SENSOR": 1155, + "CYCLING_POWER_SENSOR": 1156, + "CYCLING_SPEED_AND_CADENCE_SENSOR": 1157, + "PULSE_OXIMETER": 3136, + "PULSE_OXIMETER_FINGERTIP": 3137, + "PULSE_OXIMETER_WRIST": 3138, + "WEIGHT_SCALE": 3200, + "PERSONAL_MOBILITY": 3264, + "PERSONAL_MOBILITY_WHEELCHAIR": 3265, + "PERSONAL_MOBILITY_SCOOTER": 3266, + "GLUCOSE_MONITOR": 3328, + "SPORTS_ACTIVITY": 5184, + "SPORTS_ACTIVITY_LOCATION_DISPLAY": 5185, + "SPORTS_ACTIVITY_LOCATION_AND_NAV_DISPLAY": 5186, + "SPORTS_ACTIVITY_LOCATION_POD": 5187, + "SPORTS_ACTIVITY_LOCATION_AND_NAV_POD": 5188, +} + +### End Appearance Constants ### + +# Attribute Record values from the Bluetooth Specification +# Version 5, Vol 3, Part B +bt_attribute_values = { + 'ATTR_SERVICE_RECORD_HANDLE': 0x0000, + 'ATTR_SERVICE_CLASS_ID_LIST': 0x0001, + 'ATTR_SERVICE_RECORD_STATE': 0x0002, + 'ATTR_SERVICE_ID': 0x0003, + 'ATTR_PROTOCOL_DESCRIPTOR_LIST': 0x0004, + 'ATTR_ADDITIONAL_PROTOCOL_DESCRIPTOR_LIST': 0x000D, + 'ATTR_BROWSE_GROUP_LIST': 0x0005, + 'ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST': 0x0006, + 'ATTR_SERVICE_INFO_TIME_TO_LIVE': 0x0007, + 'ATTR_SERVICE_AVAILABILITY': 0x0008, + 'ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST': 0x0009, + 'ATTR_A2DP_SUPPORTED_FEATURES': 0x0311, +} diff --git a/gd/cert/gd_base_test.py b/gd/cert/gd_base_test.py index b382e6a22..4c02754f7 100644 --- a/gd/cert/gd_base_test.py +++ b/gd/cert/gd_base_test.py @@ -63,6 +63,7 @@ class GdBaseTestClass(BaseTestClass): self.cert_module = self.info['cert_module'] self.rootcanal_running = self.info['rootcanal_running'] self.rootcanal_logpath = self.info['rootcanal_logpath'] + self.rootcanal_logger = self.info['rootcanal_logger'] self.rootcanal_process = self.info['rootcanal_process'] if 'rootcanal' in self.controller_configs: @@ -77,7 +78,6 @@ class GdBaseTestClass(BaseTestClass): msg="Cannot start root-canal at " + str(self.info['rootcanal'])) asserts.assert_true(self.info['is_subprocess_alive'], msg="root-canal stopped immediately after running") - self.rootcanal_logger = self.info['rootcanal_logger'] self.controller_configs = self.info['controller_configs'] # Parse and construct GD device objects diff --git a/gd/cert/gd_base_test_lib.py b/gd/cert/gd_base_test_lib.py index 19b83f1c9..b480f1d2a 100644 --- a/gd/cert/gd_base_test_lib.py +++ b/gd/cert/gd_base_test_lib.py @@ -42,6 +42,9 @@ def setup_class_core(dut_module, cert_module, verbose_mode, log_path_base, contr # Start root-canal if needed info['rootcanal_running'] = False + info['rootcanal_logpath'] = "" + info['rootcanal_process'] = None + info['rootcanal_logger'] = None if 'rootcanal' in info['controller_configs']: info['rootcanal_running'] = True # Get root canal binary diff --git a/gd/cert/gd_device.py b/gd/cert/gd_device.py index 65d85d216..228e3ad7c 100644 --- a/gd/cert/gd_device.py +++ b/gd/cert/gd_device.py @@ -426,22 +426,22 @@ class GdAndroidDevice(GdDeviceBase): try: self.adb.shell("rm /data/misc/bluetooth/logs/btsnoop_hci.log") except AdbCommandError as error: - logging.error("Error during setup: " + str(error)) + logging.warning("Failed to remove old btsnoop log: " + str(error)) try: self.adb.shell("rm /data/misc/bluetooth/logs/btsnooz_hci.log") except AdbCommandError as error: - logging.error("Error during setup: " + str(error)) + logging.warning("Failed to remove old btsnooz log: " + str(error)) try: self.adb.shell("rm /data/misc/bluedroid/bt_config.conf") except AdbCommandError as error: - logging.error("Error during setup: " + str(error)) + logging.warning("Failed to remove old bt config: " + str(error)) try: self.adb.shell("rm /data/misc/bluedroid/bt_config.bak") except AdbCommandError as error: - logging.error("Error during setup: " + str(error)) + logging.warning("Failed to remove back up config: " + str(error)) self.ensure_no_output(self.adb.shell("svc bluetooth disable")) @@ -486,28 +486,34 @@ class GdAndroidDevice(GdDeviceBase): logging.error("logcat_process %s_%s stopped with code: %d" % (self.label, self.serial_number, return_code)) self.logcat_logger.stop() self.cleanup_port_forwarding() - self.adb.pull("/data/misc/bluetooth/logs/btsnoop_hci.log %s" % os.path.join(self.log_path_base, - "%s_btsnoop_hci.log" % self.label)) - self.adb.pull("/data/misc/bluedroid/bt_config.conf %s" % os.path.join(self.log_path_base, - "%s_bt_config.conf" % self.label)) - self.adb.pull( - "/data/misc/bluedroid/bt_config.bak %s" % os.path.join(self.log_path_base, "%s_bt_config.bak" % self.label)) + self.pull_logs(self.log_path_base) + + def pull_logs(self, base_dir): + try: + self.adb.pull("/data/misc/bluetooth/logs/btsnoop_hci.log %s" % os.path.join( + base_dir, "%s_btsnoop_hci.log" % self.label)) + self.adb.pull( + "/data/misc/bluedroid/bt_config.conf %s" % os.path.join(base_dir, "%s_bt_config.conf" % self.label)) + self.adb.pull( + "/data/misc/bluedroid/bt_config.bak %s" % os.path.join(base_dir, "%s_bt_config.bak" % self.label)) + except AdbCommandError as error: + logging.warning("Failed to pull logs from device: " + str(error)) def cleanup_port_forwarding(self): try: self.adb.remove_tcp_forward(self.grpc_port) except AdbError as error: - logging.error("Error during port forwarding cleanup: " + str(error)) + logging.warning("Failed to cleanup gRPC port: " + str(error)) try: self.adb.remove_tcp_forward(self.grpc_root_server_port) except AdbError as error: - logging.error("Error during port forwarding cleanup: " + str(error)) + logging.warning("Failed to cleanup gRPC server port: " + str(error)) try: self.adb.reverse("--remove tcp:%d" % self.signal_port) except AdbError as error: - logging.error("Error during port forwarding cleanup: " + str(error)) + logging.warning("Failed to cleanup signal port: " + str(error)) @staticmethod def ensure_no_output(result): diff --git a/gd/cert/gd_sl4a_base_test.py b/gd/cert/gd_sl4a_base_test.py new file mode 100644 index 000000000..be7669896 --- /dev/null +++ b/gd/cert/gd_sl4a_base_test.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# +# Copyright 2021 - The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import importlib +import traceback +import os +import logging + +from functools import wraps +from grpc import RpcError + +from acts import signals +from acts.base_test import BaseTestClass +from acts.context import get_current_context +from acts.controllers.adb_lib.error import AdbCommandError + +from cert.ble_lib import enable_bluetooth, disable_bluetooth +from cert.gd_device import MOBLY_CONTROLLER_CONFIG_NAME as CONTROLLER_CONFIG_NAME +from cert.ble_lib import BleLib +from facade import rootservice_pb2 as facade_rootservice + + +class GdSl4aBaseTestClass(BaseTestClass): + + SUBPROCESS_WAIT_TIMEOUT_SECONDS = 10 + + def setup_class(self, cert_module): + self.log_path_base = get_current_context().get_full_output_path() + self.verbose_mode = bool(self.user_params.get('verbose_mode', False)) + for config in self.controller_configs[CONTROLLER_CONFIG_NAME]: + config['verbose_mode'] = self.verbose_mode + self.cert_module = cert_module + + # Parse and construct GD device objects + self.register_controller(importlib.import_module('cert.gd_device'), builtin=True) + self.dut = self.android_devices[0] + self.cert = self.gd_devices[0] + + # Enable full btsnoop log + self.dut.adb.shell("setprop persist.bluetooth.btsnooplogmode full") + getprop_result = self.dut.adb.shell("getprop persist.bluetooth.btsnooplogmode") == "full" + if not getprop_result: + self.dut.log.warning("Failed to enable Bluetooth Hci Snoop Logging.") + + self.ble = BleLib(log=self.log, dut=self.dut) + + def teardown_class(self): + pass + + def setup_test(self): + self.cert.rootservice.StartStack( + facade_rootservice.StartStackRequest( + module_under_test=facade_rootservice.BluetoothModule.Value(self.cert_module),)) + self.cert.wait_channel_ready() + + self.timer_list = [] + self.dut.ed.clear_all_events() + self.dut.droid.setScreenTimeout(500) + self.dut.droid.wakeUpNow() + + # Always start tests with Bluetooth enabled and BLE disabled. + self.dut.droid.bluetoothDisableBLE() + disable_bluetooth(self.dut.droid, self.dut.ed) + # Enable full verbose logging for Bluetooth + self.dut.adb.shell("device_config put bluetooth INIT_logging_debug_enabled_for_all true") + # Then enable Bluetooth + enable_bluetooth(self.dut.droid, self.dut.ed) + self.dut.droid.bluetoothDisableBLE() + return True + + def teardown_test(self): + # Make sure BLE is disabled and Bluetooth is disabled after test + self.dut.droid.bluetoothDisableBLE() + disable_bluetooth(self.dut.droid, self.dut.ed) + self.cert.rootservice.StopStack(facade_rootservice.StopStackRequest()) + + # TODO: split cert logcat logs into individual tests + current_test_dir = get_current_context().get_full_output_path() + + # Pull DUT logs + self.pull_dut_logs(current_test_dir) + + # Pull CERT logs + self.cert.pull_logs(current_test_dir) + + def pull_dut_logs(self, base_dir): + try: + self.dut.pull_files("/data/misc/bluetooth/logs/btsnoop_hci.log", + os.path.join(base_dir, "DUT_%s_btsnoop_hci.log" % self.dut.serial)) + self.dut.pull_files("/data/misc/bluedroid/bt_config.conf", + os.path.join(base_dir, "DUT_%s_bt_config.conf" % self.dut.serial)) + self.dut.pull_files("/data/misc/bluedroid/bt_config.bak", + os.path.join(base_dir, "DUT_%s_bt_config.bak" % self.dut.serial)) + except AdbCommandError as error: + logging.warning("Failed to pull logs from DUT: " + str(error)) + + def __getattribute__(self, name): + attr = super().__getattribute__(name) + if not callable(attr) or not GdSl4aBaseTestClass.__is_entry_function(name): + return attr + + @wraps(attr) + def __wrapped(*args, **kwargs): + try: + return attr(*args, **kwargs) + except RpcError as e: + exception_info = "".join(traceback.format_exception(e.__class__, e, e.__traceback__)) + raise signals.TestFailure("RpcError during test\n\nRpcError:\n\n%s" % (exception_info)) + + return __wrapped + + __ENTRY_METHODS = {"setup_class", "teardown_class", "setup_test", "teardown_test"} + + @staticmethod + def __is_entry_function(name): + return name.startswith("test_") or name in GdSl4aBaseTestClass.__ENTRY_METHODS diff --git a/gd/cert/gd_sl4a_device_config.json b/gd/cert/gd_sl4a_device_config.json new file mode 100644 index 000000000..f3451d2e1 --- /dev/null +++ b/gd/cert/gd_sl4a_device_config.json @@ -0,0 +1,46 @@ +{ "_description": "Bluetooth cert testing", + "testbed": + [ + { + "_description": "Two Android devices with GD cert and SL4A dut", + "name": "AndroidDeviceCert", + "GdDevice": + [ + { + "grpc_port": "8898", + "grpc_root_server_port": "8896", + "signal_port": "8894", + "label": "cert", + "serial_number": "CERT", + "name": "Cert Device", + "cmd": + [ + "adb", + "-s", + "$(serial_number)", + "shell", + "ASAN_OPTIONS=detect_container_overflow=0", + "/system/bin/bluetooth_stack_with_facade", + "--grpc-port=$(grpc_port)", + "--root-server-port=$(grpc_root_server_port)", + "--btsnoop=/data/misc/bluetooth/logs/btsnoop_hci.log", + "--btsnooz=/data/misc/bluetooth/logs/btsnooz_hci.log", + "--btconfig=/data/misc/bluedroid/bt_config.conf", + "--signal-port=$(signal_port)" + ] + } + ], + "AndroidDevice": + [ + { + "serial": "DUT", + "label": "dut", + "client_port": "8895", + "forwarded_port": "8899", + "server_port": "8899" + } + ] + } + ], + "logpath": "/tmp/logs" +} diff --git a/gd/cert/run b/gd/cert/run index e666c5fbb..f6f4a36d8 100755 --- a/gd/cert/run +++ b/gd/cert/run @@ -89,6 +89,7 @@ NUM_REPETITIONS="1" SKIP_SOONG_BUILD=false USE_ASHMEM_VENV=true VERBOSE_MODE=false +DEVICE_TEST=false # Directory for test configs to modify CONFIG_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" @@ -156,29 +157,7 @@ function parse_options { ;; --device) TEST_CONFIG="${ANDROID_BUILD_TOP}/system/bt/gd/cert/devices_config.json" - RR="$(cat ${TEST_CONFIG}|grep \"CERT\\\|DUT\")" - if [ "$RR" != "" ]; then - DUT_SERIAL="$(menu-adb DUT)" - DUT_ADB="adb -s ${DUT_SERIAL}" - DUT_NAME="$(adb devices -l | grep -v "List of device" | grep ${DUT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)" - CERT_SERIAL="$(menu-adb CERT)" - CERT_ADB="adb -s ${CERT_SERIAL}" - CERT_NAME="$(adb devices -l | grep -v "List of device" | grep ${CERT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)" - - if [ "${CERT_SERIAL}" == "${DUT_SERIAL}" ]; then - echo - echo "ERROR: CERT and DUT cannot be the same device, or you only have one device connected!" - echo - exit 1 - fi - - ## Set android devices in config - pushd . - cd "${CONFIG_DIR}" - popd - sed -i "s/\"DUT\"/\"${DUT_SERIAL}\"/g" ${CONFIG_DIR}/devices_config.json - sed -i "s/\"CERT\"/\"${CERT_SERIAL}\"/g" ${CONFIG_DIR}/devices_config.json - fi + DEVICE_TEST=true shift # past argument ;; # Repeat running the specified test cases by N times in one single setup @@ -198,6 +177,7 @@ function parse_options { BUILD_TARGET=$RUST_BUILD_TARGET export RUST_BACKTRACE=1 TEST_CONFIG=$ANDROID_BUILD_TOP/system/bt/gd/cert/rust_android_devices_config.json + DEVICE_TEST=true shift # past argument ;; --rhost) @@ -237,6 +217,34 @@ function parse_options { } +function select_devices { + if [ "$DEVICE_TEST" == true ] ; then + RR="$(cat ${TEST_CONFIG}|grep \"CERT\\\|DUT\")" + if [ "$RR" != "" ]; then + DUT_SERIAL="$(menu-adb DUT)" + DUT_ADB="adb -s ${DUT_SERIAL}" + DUT_NAME="$(adb devices -l | grep -v "List of device" | grep ${DUT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)" + CERT_SERIAL="$(menu-adb CERT)" + CERT_ADB="adb -s ${CERT_SERIAL}" + CERT_NAME="$(adb devices -l | grep -v "List of device" | grep ${CERT_SERIAL} | awk '{ print $6 }' | cut -d ':' -f 2)" + + if [ "${CERT_SERIAL}" == "${DUT_SERIAL}" ]; then + echo + echo "ERROR: CERT and DUT cannot be the same device, or you only have one device connected!" + echo + exit 1 + fi + + ## Set android devices in config + pushd . + cd "${CONFIG_DIR}" + popd + sed -i "s/\"DUT\"/\"${DUT_SERIAL}\"/g" ${TEST_CONFIG} + sed -i "s/\"CERT\"/\"${CERT_SERIAL}\"/g" ${TEST_CONFIG} + fi + fi +} + function soong_build { if [ "$CLEAN_VENV" == true ] ; then $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --build-mode --"modules-in-a-dir" --dir="${ANDROID_BUILD_TOP}/system/bt/gd" dist $BUILD_TARGET -j20 @@ -475,6 +483,7 @@ function menu-adb() { function main { check_environment parse_options $@ + select_devices if [[ "${SKIP_SOONG_BUILD}" != true ]] ; then soong_build fi diff --git a/gd/hci/cert/le_advanced_scanning_test.py b/gd/hci/cert/le_advanced_scanning_test.py new file mode 100644 index 000000000..a47f79c6e --- /dev/null +++ b/gd/hci/cert/le_advanced_scanning_test.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python3 +# +# Copyright 2021 - The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import queue +import logging + +from google.protobuf import empty_pb2 as empty_proto + +from bluetooth_packets_python3 import hci_packets +from cert.bt_constants import ble_scan_settings_modes, ble_address_types, scan_result, ble_scan_settings_phys +from cert.ble_lib import generate_ble_scan_objects +from cert.gd_sl4a_base_test import GdSl4aBaseTestClass +from hci.facade import \ + le_advertising_manager_facade_pb2 as le_advertising_facade +from hci.facade import le_initiator_address_facade_pb2 as le_initiator_address_facade +from facade import common_pb2 as common + + +class LeAdvancedScanningTest(GdSl4aBaseTestClass): + + def setup_class(self): + super().setup_class(cert_module='HCI_INTERFACES') + self.default_timeout = 10 # seconds + + def setup_test(self): + super().setup_test() + + def teardown_test(self): + super().teardown_test() + + def set_cert_privacy_policy_with_random_address(self, random_address): + private_policy = le_initiator_address_facade.PrivacyPolicy( + address_policy=le_initiator_address_facade.AddressPolicy.USE_STATIC_ADDRESS, + address_with_type=common.BluetoothAddressWithType( + address=common.BluetoothAddress(address=bytes(random_address, encoding='utf8')), + type=common.RANDOM_DEVICE_ADDRESS)) + self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(private_policy) + + def set_cert_privacy_policy_with_public_address(self): + public_address_bytes = self.cert.hci_controller.GetMacAddress(empty_proto.Empty()).address + private_policy = le_initiator_address_facade.PrivacyPolicy( + address_policy=le_initiator_address_facade.AddressPolicy.USE_PUBLIC_ADDRESS, + address_with_type=common.BluetoothAddressWithType( + address=common.BluetoothAddress(address=public_address_bytes), type=common.PUBLIC_DEVICE_ADDRESS)) + self.cert.hci_le_initiator_address.SetPrivacyPolicyForInitiatorAddress(private_policy) + # Bluetooth MAC address must be upper case + return public_address_bytes.decode('utf-8').upper() + + def test_scan_filter_device_name_legacy_pdu(self): + # Use public address on cert side + logging.info("Setting public address") + DEVICE_NAME = 'Im_The_CERT!' + public_address = self.set_cert_privacy_policy_with_public_address() + logging.info("Set public address") + + # Setup cert side to advertise + gap_name = hci_packets.GapData() + gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME + gap_name.data = list(bytes(DEVICE_NAME, encoding='utf8')) + gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize())) + config = le_advertising_facade.AdvertisingConfig( + advertisement=[gap_data], + interval_min=512, + interval_max=768, + advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND, + own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS, + channel_map=7, + filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES, + tx_power=20) + request = le_advertising_facade.CreateAdvertiserRequest(config=config) + logging.info("Creating advertiser") + create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request) + logging.info("Created advertiser") + + # Setup SL4A DUT side to scan + logging.info("Start scanning with public address %s" % public_address) + self.dut.droid.bleSetScanSettingsScanMode(ble_scan_settings_modes['low_latency']) + filter_list, scan_settings, scan_callback = generate_ble_scan_objects(self.dut.droid) + expected_event_name = scan_result.format(scan_callback) + + # Setup SL4A DUT filter + self.dut.droid.bleSetScanFilterDeviceName(DEVICE_NAME) + self.dut.droid.bleBuildScanFilter(filter_list) + + # Start scanning on SL4A DUT side + self.dut.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) + logging.info("Started scanning") + try: + # Verify if there is scan result + event_info = self.dut.ed.pop_event(expected_event_name, self.default_timeout) + except queue.Empty as error: + self.log.error("Could not find initial advertisement.") + return False + # Print out scan result + mac_address = event_info['data']['Result']['deviceInfo']['address'] + self.log.info("Filter advertisement with address {}".format(mac_address)) + + # Stop scanning + logging.info("Stop scanning") + self.dut.droid.bleStopBleScan(scan_callback) + logging.info("Stopped scanning") + + # Stop advertising + logging.info("Stop advertising") + remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id) + self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request) + logging.info("Stopped advertising") + + return True + + def test_scan_filter_device_random_address_legacy_pdu(self): + # Use random address on cert side + logging.info("Setting random address") + RANDOM_ADDRESS = 'D0:05:04:03:02:01' + DEVICE_NAME = 'Im_The_CERT!' + self.set_cert_privacy_policy_with_random_address(RANDOM_ADDRESS) + logging.info("Set random address") + + # Setup cert side to advertise + gap_name = hci_packets.GapData() + gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME + gap_name.data = list(bytes(DEVICE_NAME, encoding='utf8')) + gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize())) + config = le_advertising_facade.AdvertisingConfig( + advertisement=[gap_data], + interval_min=512, + interval_max=768, + advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND, + own_address_type=common.USE_RANDOM_DEVICE_ADDRESS, + channel_map=7, + filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES) + request = le_advertising_facade.CreateAdvertiserRequest(config=config) + logging.info("Creating advertiser") + create_response = self.cert.hci_le_advertising_manager.CreateAdvertiser(request) + logging.info("Created advertiser") + + # Setup SL4A DUT side to scan + addr_type = ble_address_types["random"] + logging.info("Start scanning for RANDOM_ADDRESS %s with address type %d" % (RANDOM_ADDRESS, addr_type)) + self.dut.droid.bleSetScanSettingsScanMode(ble_scan_settings_modes['low_latency']) + filter_list, scan_settings, scan_callback = generate_ble_scan_objects(self.dut.droid) + expected_event_name = scan_result.format(scan_callback) + + # Setup SL4A DUT filter + self.dut.droid.bleSetScanFilterDeviceAddressAndType(RANDOM_ADDRESS, int(addr_type)) + self.dut.droid.bleBuildScanFilter(filter_list) + + # Start scanning on SL4A DUT side + self.dut.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) + logging.info("Started scanning") + try: + # Verify if there is scan result + event_info = self.dut.ed.pop_event(expected_event_name, self.default_timeout) + except queue.Empty as error: + self.log.error("Could not find initial advertisement.") + return False + # Print out scan result + mac_address = event_info['data']['Result']['deviceInfo']['address'] + self.log.info("Filter advertisement with address {}".format(mac_address)) + + # Stop scanning + logging.info("Stop scanning") + self.dut.droid.bleStopBleScan(scan_callback) + logging.info("Stopped scanning") + + # Stop advertising + logging.info("Stop advertising") + remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id) + self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request) + logging.info("Stopped advertising") + + return True + + def test_scan_filter_device_public_address_extended_pdu(self): + # Use public address on cert side + logging.info("Setting public address") + DEVICE_NAME = 'Im_The_CERT!' + public_address = self.set_cert_privacy_policy_with_public_address() + logging.info("Set public address") + + # Setup cert side to advertise + gap_name = hci_packets.GapData() + gap_name.data_type = hci_packets.GapDataType.COMPLETE_LOCAL_NAME + gap_name.data = list(bytes(DEVICE_NAME, encoding='utf8')) + gap_data = le_advertising_facade.GapDataMsg(data=bytes(gap_name.Serialize())) + config = le_advertising_facade.AdvertisingConfig( + advertisement=[gap_data], + interval_min=512, + interval_max=768, + advertising_type=le_advertising_facade.AdvertisingEventType.ADV_IND, + own_address_type=common.USE_PUBLIC_DEVICE_ADDRESS, + channel_map=7, + filter_policy=le_advertising_facade.AdvertisingFilterPolicy.ALL_DEVICES) + extended_config = le_advertising_facade.ExtendedAdvertisingConfig( + advertising_config=config, secondary_advertising_phy=ble_scan_settings_phys["1m"]) + request = le_advertising_facade.ExtendedCreateAdvertiserRequest(config=extended_config) + logging.info("Creating advertiser") + create_response = self.cert.hci_le_advertising_manager.ExtendedCreateAdvertiser(request) + logging.info("Created advertiser") + + # Setup SL4A DUT side to scan + addr_type = ble_address_types["public"] + logging.info("Start scanning for PUBLIC_ADDRESS %s with address type %d" % (public_address, addr_type)) + self.dut.droid.bleSetScanSettingsScanMode(ble_scan_settings_modes['low_latency']) + self.dut.droid.bleSetScanSettingsLegacy(False) + filter_list, scan_settings, scan_callback = generate_ble_scan_objects(self.dut.droid) + expected_event_name = scan_result.format(scan_callback) + + # Setup SL4A DUT filter + self.dut.droid.bleSetScanFilterDeviceAddressAndType(public_address, int(addr_type)) + self.dut.droid.bleBuildScanFilter(filter_list) + + # Start scanning on SL4A DUT side + self.dut.droid.bleStartBleScan(filter_list, scan_settings, scan_callback) + logging.info("Started scanning") + try: + # Verify if there is scan result + event_info = self.dut.ed.pop_event(expected_event_name, self.default_timeout) + except queue.Empty as error: + self.log.error("Could not find initial advertisement.") + return False + # Print out scan result + mac_address = event_info['data']['Result']['deviceInfo']['address'] + self.log.info("Filter advertisement with address {}".format(mac_address)) + + # Stop scanning + logging.info("Stop scanning") + self.dut.droid.bleStopBleScan(scan_callback) + logging.info("Stopped scanning") + + # Stop advertising + logging.info("Stop advertising") + remove_request = le_advertising_facade.RemoveAdvertiserRequest(advertiser_id=create_response.advertiser_id) + self.cert.hci_le_advertising_manager.RemoveAdvertiser(remove_request) + logging.info("Stopped advertising") + + return True diff --git a/gd/hci/facade/le_advertising_manager_facade.cc b/gd/hci/facade/le_advertising_manager_facade.cc index 8e017bb1b..598d7ba99 100644 --- a/gd/hci/facade/le_advertising_manager_facade.cc +++ b/gd/hci/facade/le_advertising_manager_facade.cc @@ -93,6 +93,38 @@ bool AdvertisingConfigFromProto(const AdvertisingConfig& config_proto, hci::Adve config->filter_policy = static_cast<hci::AdvertisingFilterPolicy>(config_proto.filter_policy()); config->tx_power = static_cast<uint8_t>(config_proto.tx_power()); + + return true; +} + +bool ExtendedAdvertisingConfigFromProto( + const ExtendedAdvertisingConfig& config_proto, hci::ExtendedAdvertisingConfig* config) { + AdvertisingConfigFromProto(config_proto.advertising_config(), config); + config->connectable = config_proto.connectable(); + config->scannable = config_proto.scannable(); + config->directed = config_proto.directed(); + config->high_duty_directed_connectable = config_proto.high_duty_directed_connectable(); + config->legacy_pdus = config_proto.legacy_pdus(); + config->anonymous = config_proto.anonymous(); + config->include_tx_power = config_proto.include_tx_power(); + config->use_le_coded_phy = config_proto.use_le_coded_phy(); + if (config_proto.secondary_map_skip() < 0 || config_proto.secondary_map_skip() > 0xFF) { + LOG_WARN("Base secondary_map_skip: 0x%x", config_proto.secondary_map_skip()); + return false; + } + config->secondary_max_skip = config_proto.secondary_map_skip(); + if (config_proto.secondary_advertising_phy() <= 0 || config_proto.secondary_advertising_phy() > 3) { + LOG_WARN("Base secondary_advertising_phy: 0x%x", config_proto.secondary_advertising_phy()); + return false; + } + config->secondary_advertising_phy = static_cast<SecondaryPhyType>(config_proto.secondary_advertising_phy()); + if (config_proto.sid() < 0 || config_proto.sid() > 0xF) { + LOG_WARN("Base sid: 0x%x", config_proto.sid()); + return false; + } + config->sid = config_proto.sid(); + config->enable_scan_request_notifications = + config_proto.enable_scan_request_notification() ? Enable::ENABLED : Enable::DISABLED; return true; } @@ -128,6 +160,8 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser ::grpc::Status CreateAdvertiser(::grpc::ServerContext* context, const CreateAdvertiserRequest* request, CreateAdvertiserResponse* response) override { hci::ExtendedAdvertisingConfig config = {}; + config.legacy_pdus = true; + config.secondary_advertising_phy = SecondaryPhyType::LE_1M; if (!AdvertisingConfigFromProto(request->config(), &config)) { LOG_WARN("Error parsing advertising config %s", request->SerializeAsString().c_str()); response->set_advertiser_id(LeAdvertisingManager::kInvalidId); @@ -155,9 +189,29 @@ class LeAdvertisingManagerFacadeService : public LeAdvertisingManagerFacade::Ser ::grpc::Status ExtendedCreateAdvertiser(::grpc::ServerContext* context, const ExtendedCreateAdvertiserRequest* request, ExtendedCreateAdvertiserResponse* response) override { - LOG_WARN("ExtendedCreateAdvertiser is not implemented"); - response->set_advertiser_id(LeAdvertisingManager::kInvalidId); - return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "ExtendedCreateAdvertiser is not implemented"); + hci::ExtendedAdvertisingConfig config = {}; + if (!ExtendedAdvertisingConfigFromProto(request->config(), &config)) { + LOG_WARN("Error parsing extended advertising config %s", request->SerializeAsString().c_str()); + response->set_advertiser_id(LeAdvertisingManager::kInvalidId); + return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Error while parsing extended advertising config"); + } + LeAdvertiser le_advertiser(config); + auto advertiser_id = le_advertising_manager_->ExtendedCreateAdvertiser( + -1, + config, + common::Bind(&LeAdvertiser::ScanCallback, common::Unretained(&le_advertiser)), + common::Bind(&LeAdvertiser::TerminatedCallback, common::Unretained(&le_advertiser)), + 0, + 0, + facade_handler_); + if (advertiser_id != LeAdvertisingManager::kInvalidId) { + le_advertiser.SetAdvertiserId(advertiser_id); + le_advertisers_.push_back(le_advertiser); + } else { + LOG_WARN("Failed to create advertiser"); + } + response->set_advertiser_id(advertiser_id); + return ::grpc::Status::OK; } ::grpc::Status GetNumberOfAdvertisingInstances(::grpc::ServerContext* context, diff --git a/osi/src/config.cc b/osi/src/config.cc index 29d620640..18176d0bd 100644 --- a/osi/src/config.cc +++ b/osi/src/config.cc @@ -493,8 +493,8 @@ static bool config_parse(FILE* fp, config_t* config) { CHECK(config != nullptr); int line_num = 0; - char line[1024]; - char section[1024]; + char line[4096]; + char section[4096]; strcpy(section, CONFIG_DEFAULT_SECTION); while (fgets(line, sizeof(line), fp)) { @@ -511,7 +511,7 @@ static bool config_parse(FILE* fp, config_t* config) { << line_num; return false; } - strncpy(section, line_ptr + 1, len - 2); // NOLINT (len < 1024) + strncpy(section, line_ptr + 1, len - 2); // NOLINT (len < 4096) section[len - 2] = '\0'; } else { char* split = strchr(line_ptr, '='); diff --git a/profile/avrcp/avrcp_config.h b/profile/avrcp/avrcp_config.h index f6a872443..3f9e74d0e 100644 --- a/profile/avrcp/avrcp_config.h +++ b/profile/avrcp/avrcp_config.h @@ -50,3 +50,10 @@ #ifndef AVRCP_SUPF_TG #define AVRCP_SUPF_TG_DEFAULT AVRCP_SUPF_TG_1_4 #endif + +/** + * Supported Feature for AVRCP tartget control + */ +#ifndef AVRCP_SUPF_TG_CT +#define AVRCP_SUPF_TG_CT AVRC_SUPF_CT_CAT2 +#endif diff --git a/stack/acl/btm_acl.cc b/stack/acl/btm_acl.cc index 4c7e06696..1e8b0a85b 100644 --- a/stack/acl/btm_acl.cc +++ b/stack/acl/btm_acl.cc @@ -369,7 +369,9 @@ void btm_acl_created(const RawAddress& bda, uint16_t hci_handle, p_acl->hci_handle = hci_handle; p_acl->link_role = link_role; p_acl->transport = transport; - btm_set_link_policy(p_acl, btm_cb.acl_cb_.DefaultLinkPolicy()); + if (transport == BT_TRANSPORT_BR_EDR) { + btm_set_link_policy(p_acl, btm_cb.acl_cb_.DefaultLinkPolicy()); + } LOG_WARN( "Unable to create duplicate acl when one already exists handle:%hu" " role:%s transport:%s", @@ -399,7 +401,10 @@ void btm_acl_created(const RawAddress& bda, uint16_t hci_handle, "Created new ACL connection peer:%s role:%s handle:0x%04x transport:%s", PRIVATE_ADDRESS(bda), RoleText(p_acl->link_role).c_str(), hci_handle, bt_transport_text(transport).c_str()); - btm_set_link_policy(p_acl, btm_cb.acl_cb_.DefaultLinkPolicy()); + + if (transport == BT_TRANSPORT_BR_EDR) { + btm_set_link_policy(p_acl, btm_cb.acl_cb_.DefaultLinkPolicy()); + } if (transport == BT_TRANSPORT_LE) { btm_ble_refresh_local_resolvable_private_addr( diff --git a/stack/gatt/gatt_sr.cc b/stack/gatt/gatt_sr.cc index 9fe642cba..0396bb16f 100644 --- a/stack/gatt/gatt_sr.cc +++ b/stack/gatt/gatt_sr.cc @@ -173,6 +173,9 @@ static void build_read_multi_rsp(tGATT_SR_CMD* p_cmd, uint16_t mtu) { if (p_rsp != NULL) { total_len = (p_buf->len + p_rsp->attr_value.len); + if (p_cmd->multi_req.variable_len) { + total_len += 2; + } if (total_len > mtu) { /* just send the partial response for the overflow case */ diff --git a/stack/include/l2c_api.h b/stack/include/l2c_api.h index 9de3b9bb9..52f41614e 100644 --- a/stack/include/l2c_api.h +++ b/stack/include/l2c_api.h @@ -469,6 +469,18 @@ extern bool L2CA_GetPeerLECocConfig(uint16_t lcid, /******************************************************************************* * + * Function L2CA_GetPeerLECocCredit + * + * Description Get peers current credit for LE Connection Oriented + * Channel. + * + * Return value: Number of the peer current credit + * + ******************************************************************************/ +uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid); + +/******************************************************************************* + * * Function L2CA_ReconfigCreditBasedConnsReq * * Description Start reconfigure procedure on Connection Oriented Channel. diff --git a/stack/l2cap/l2c_api.cc b/stack/l2cap/l2c_api.cc index c8f2659ef..9e7e15159 100644 --- a/stack/l2cap/l2c_api.cc +++ b/stack/l2cap/l2c_api.cc @@ -616,6 +616,34 @@ bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) { /******************************************************************************* * + * Function L2CA_GetPeerLECocCredit + * + * Description Get peers current credit for LE Connection Oriented + * Channel. + * + * Return value: Number of the peer current credit + * + ******************************************************************************/ +uint16_t L2CA_GetPeerLECocCredit(const RawAddress& bd_addr, uint16_t lcid) { + /* First, find the link control block */ + tL2C_LCB* p_lcb = l2cu_find_lcb_by_bd_addr(bd_addr, BT_TRANSPORT_LE); + if (p_lcb == NULL) { + /* No link. Get an LCB and start link establishment */ + L2CAP_TRACE_WARNING("%s no LCB", __func__); + return L2CAP_LE_CREDIT_MAX; + } + + tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(p_lcb, lcid); + if (p_ccb == NULL) { + L2CAP_TRACE_ERROR("%s No CCB for CID:0x%04x", __func__, lcid); + return L2CAP_LE_CREDIT_MAX; + } + + return p_ccb->peer_conn_cfg.credits; +} + +/******************************************************************************* + * * Function L2CA_ConnectCreditBasedRsp * * Description Response for the pL2CA_CreditBasedConnectInd_Cb which is the |