1# Lint as: python2, python3 2# Copyright 2019 The Chromium OS Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5"""Provides utilities to support bluetooth adapter tests""" 6 7from __future__ import absolute_import 8 9import logging 10import re 11import uuid 12 13import common 14from autotest_lib.client.bin.input.linux_input import EV_KEY 15from autotest_lib.server.cros.bluetooth.debug_linux_keymap import ( 16 linux_input_keymap) 17from ast import literal_eval as make_tuple 18 19 20def reconstruct_string(events): 21 """ Tries to reconstruct a string from linux input in a simple way 22 23 @param events: list of event objects received over the BT channel 24 25 @returns: reconstructed string 26 """ 27 recon = [] 28 29 for ev in events: 30 # If it's a key pressed event 31 if ev.type == EV_KEY and ev.value == 1: 32 recon.append(linux_input_keymap.get(ev.code, "_")) 33 34 return "".join(recon) 35 36 37def parse_trace_file(filename): 38 """ Reads contents of trace file 39 40 @param filename: location of trace file on disk 41 42 @returns: structure containing contents of filename 43 """ 44 45 contents = [] 46 47 try: 48 with open(filename, 'r') as mf: 49 for line in mf: 50 # Reconstruct tuple and add to trace 51 contents.append(make_tuple(line)) 52 except EnvironmentError: 53 logging.error('Unable to open file %s', filename) 54 return None 55 56 return contents 57 58 59class Bluetooth_UUID(uuid.UUID): 60 """A class to manipulate Bluetooth UUIDs.""" 61 62 BLUETOOTH_BASE_UUID_FORMAT = '%s-0000-1000-8000-00805F9B34FB' 63 64 def __init__(self, hex_str): 65 super(Bluetooth_UUID, self).__init__(hex_str) 66 67 68 @classmethod 69 def create_valid_uuid(cls, hex_str): 70 """Create valid long UUIDs based on Bluetooth short UUIDs. 71 72 @param hex_str: the hex string that represents a short or long UUID. 73 74 @returns: the UUID object if successful; or None otherwise. 75 """ 76 h = re.sub('^0x', '', hex_str).replace('-', '') 77 78 # The Bluetooth spec only allowed short UUIDs in 16 bits or 32 bits. 79 # The long UUID takes 128 bits. 80 # Reference: 81 # www.bluetooth.com/specifications/assigned-numbers/service-discovery 82 hlen = len(h) 83 if hlen not in (4, 8, 32): 84 return None 85 86 # Convert the short UUIDs to the full UUID. 87 if hlen in (4, 8): 88 h = cls.BLUETOOTH_BASE_UUID_FORMAT % h.zfill(8) 89 90 return cls(h) 91 92 93class BluetoothPolicy(object): 94 """A helper class to keep popular bluetooth service lists. 95 96 Refer to 97 https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/ 98 """ 99 100 def to_allowlist(uuids): 101 """Helper function to convert a group of uuids to allowlist format 102 103 @param uuids: an iterable object of UUID string 104 105 @returns: comma-separated UUID string 106 """ 107 return ','.join(list(uuids)) 108 109 UUID_HID = '0x1124' 110 UUID_HOG = '0x1812' 111 UUID_DIS = '0x180a' 112 UUID_BATT = '0x180f' 113 114 UUID_A2DP = '0x110d' 115 UUID_AUDIO_SOURCE = '0x110a' 116 UUID_AUDIO_SINK = '0x110b' 117 UUID_AVRCP = '0x110e' 118 UUID_AVRCP_TARGET = '0x110c' 119 UUID_AVRCP_CONTROLLER = '0x110f' 120 UUID_GENERIC_AUDIO = '0x1203' 121 UUID_HANDSFREE = '0x111e' 122 UUID_HANDSFREE_AUDIO_GATEWAY = '0x111f' 123 UUID_HEADSET = '0x1108' 124 UUID_HEADSET_AUDIO_GATEWAY = '0x1112' 125 126 UUIDSET_BLE_HID = {UUID_HOG, UUID_DIS, UUID_BATT} 127 UUIDSET_AUDIO = {UUID_A2DP, UUID_AUDIO_SINK, UUID_AUDIO_SOURCE, 128 UUID_AVRCP, UUID_AVRCP_TARGET, UUID_AVRCP_CONTROLLER, 129 UUID_GENERIC_AUDIO, 130 UUID_HANDSFREE, UUID_HANDSFREE_AUDIO_GATEWAY, 131 UUID_HEADSET, UUID_HEADSET_AUDIO_GATEWAY} 132 133 ALLOWLIST_CLASSIC_HID = UUID_HID 134 ALLOWLIST_BLE_HID = to_allowlist(UUIDSET_BLE_HID) 135 ALLOWLIST_AUDIO = to_allowlist(UUIDSET_AUDIO) 136 ALLOWLIST_BLE_HID_AUDIO = to_allowlist(UUIDSET_BLE_HID.union(UUIDSET_AUDIO)) 137 ALLOWLIST_CLASSIC_BLE_HID = to_allowlist(UUIDSET_BLE_HID.union({UUID_HID})) 138