xref: /aosp_15_r20/external/autotest/server/cros/bluetooth/bluetooth_default_state_test.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright (c) 2013 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
6from __future__ import absolute_import
7
8import logging
9import time
10
11import common
12from autotest_lib.client.common_lib import error
13from autotest_lib.client.common_lib.cros.bluetooth import bluetooth_socket
14from autotest_lib.server.cros.bluetooth import bluetooth_adapter_tests
15
16DEVICE_ADDRESS = '01:02:03:04:05:06'
17ADDRESS_TYPE = 0
18
19class bluetooth_Health_DefaultStateTest(
20        bluetooth_adapter_tests.BluetoothAdapterTests):
21    """
22    This class implements the default state test
23    and all the helper functions it needs.
24    """
25    version = 1
26
27
28
29    def compare_property(self, bluez_property, mgmt_setting, current_settings):
30        """ Compare bluez property value and Kernel property
31
32            @param bluez_property : Bluez property to be compared
33            @param mgmt_setting   : Bit mask of management setting
34            @param current_settings : Current kernel settings
35            @return : True if bluez property and the current settings agree """
36
37        cur_kernel_value = 1 if mgmt_setting & current_settings else 0
38        return bluez_property == cur_kernel_value
39
40    def default_state_test(self):
41        """Test Default state of Bluetooth adapter after power cycling."""
42
43        # Reset the adapter to the powered off state.
44        self.test_reset_off_adapter()
45
46        # Kernel default state depends on whether the kernel supports the
47        # BR/EDR Allowlist. When this is supported the 'connectable' setting
48        # remains unset and instead page scan is managed by the kernel based
49        # on whether or not a BR/EDR device is in the allowlist.
50        ( commands, events ) = self.read_supported_commands()
51        supports_add_device = bluetooth_socket.MGMT_OP_ADD_DEVICE in commands
52
53        # Read the initial state of the adapter. Verify that it is powered down.
54        ( address, bluetooth_version, manufacturer_id,
55                supported_settings, current_settings, class_of_device,
56                name, short_name ) = self.read_info()
57        self.log_settings('Initial state', current_settings)
58
59        if current_settings & bluetooth_socket.MGMT_SETTING_POWERED:
60            raise error.TestFail('Bluetooth adapter is powered')
61
62        # The other kernel settings (connectable, pairable, etc.) reflect the
63        # initial state before the bluetooth daemon adjusts them - we're ok
64        # with them being on or off during that brief period.
65        #
66
67        # Verify that the Bluetooth Daemon sees that it is also powered down,
68        # non-discoverable and not discovering devices.
69        bluez_properties = self.get_adapter_properties()
70
71        if bluez_properties['Powered']:
72            raise error.TestFail('Bluetooth daemon Powered property does not '
73                                 'match kernel while powered off')
74        if not self.compare_property(bluez_properties['Discoverable'],
75                                     bluetooth_socket.MGMT_SETTING_DISCOVERABLE,
76                                     current_settings):
77            raise error.TestFail('Bluetooth daemon Discoverable property '
78                                 'does not match kernel while powered off')
79        if bluez_properties['Discovering']:
80            raise error.TestFail('Bluetooth daemon believes adapter is '
81                                 'discovering while powered off')
82
83        # Compare with the raw HCI state of the adapter as well, this should
84        # be just not "UP", otherwise something deeply screwy is happening.
85        flags = self.get_dev_info()[3]
86        self.log_flags('Initial state', flags)
87
88        if flags & bluetooth_socket.HCI_UP:
89            raise error.TestFail('HCI UP flag does not match kernel while '
90                                 'powered off')
91
92        # Power on the adapter, then read the state again. Verify that it is
93        # powered up, pairable, but not discoverable.
94        self.test_power_on_adapter()
95        current_settings = self.read_info()[4]
96        self.log_settings("Powered up", current_settings)
97
98        if not current_settings & bluetooth_socket.MGMT_SETTING_POWERED:
99            raise error.TestFail('Bluetooth adapter is not powered')
100
101        # If the kernel does not supports the BR/EDR allowlist, the adapter
102        # should be generically connectable;
103        # if it doesn't, then it depends on previous settings.
104        if not supports_add_device:
105            if not current_settings & bluetooth_socket.MGMT_SETTING_CONNECTABLE:
106                raise error.TestFail('Bluetooth adapter is not connectable '
107                                     'though kernel does not support '
108                                     'BR/EDR allowlist')
109
110        # Verify that the Bluetooth Daemon sees the same state as the kernel
111        # and that it's not discovering.
112        bluez_properties = self.get_adapter_properties()
113
114        if not bluez_properties['Powered']:
115            raise error.TestFail('Bluetooth daemon Powered property does not '
116                                 'match kernel while powered on')
117        if not self.compare_property(bluez_properties['Pairable'],
118                                     bluetooth_socket.MGMT_SETTING_PAIRABLE,
119                                     current_settings):
120            raise error.TestFail('Bluetooth daemon Pairable property does not '
121                                 'match kernel while powered on')
122        if not self.compare_property(bluez_properties['Discoverable'],
123                                     bluetooth_socket.MGMT_SETTING_DISCOVERABLE,
124                                     current_settings):
125            raise error.TestFail('Bluetooth daemon Discoverable property '
126                                 'does not match kernel while powered on')
127        if bluez_properties['Discovering']:
128            raise error.TestFail('Bluetooth daemon believes adapter is '
129                                 'discovering while powered on')
130
131        # Compare with the raw HCI state of the adapter while powered up as
132        # well.
133        flags = self.get_dev_info()[3]
134        self.log_flags('Powered up', flags)
135
136        if not flags & bluetooth_socket.HCI_UP:
137            raise error.TestFail('HCI UP flag does not match kernel while '
138                                 'powered on')
139        if not flags & bluetooth_socket.HCI_RUNNING:
140            raise error.TestFail('HCI RUNNING flag does not match kernel while '
141                                 'powered on')
142        if bool(flags & bluetooth_socket.HCI_ISCAN) != \
143            bool(bluez_properties['Discoverable']):
144            raise error.TestFail('HCI ISCAN flag does not match kernel while '
145                                 'powered on')
146        if flags & bluetooth_socket.HCI_INQUIRY:
147            raise error.TestFail('HCI INQUIRY flag does not match kernel while '
148                                 'powered on')
149
150        # If the kernel does not supports the BR/EDR allowlist, the adapter
151        # should generically connectable, so should it should be in PSCAN
152        # mode. This matches the management API "connectable" setting so far.
153        if not supports_add_device:
154            if not flags & bluetooth_socket.HCI_PSCAN:
155                raise error.TestFail('HCI PSCAN flag not set though kernel'
156                                     'does not supports BR/EDR allowlist')
157
158        # Now we can examine the differences. Try adding and removing a device
159        # from the kernel BR/EDR allowlist. The management API "connectable"
160        # setting should remain off, but we should be able to see the PSCAN
161        # flag come and go.
162        if supports_add_device:
163            # If PSCAN is currently on then device is CONNECTABLE
164            # or a previous add device which was not removed.
165            # Turn on and off DISCOVERABLE to turn off CONNECTABLE and
166            # PSCAN
167            if flags & bluetooth_socket.HCI_PSCAN:
168                if not (current_settings &
169                        bluetooth_socket.MGMT_SETTING_CONNECTABLE):
170                    raise error.TestFail('PSCAN on but device not CONNECTABLE')
171                logging.debug('Toggle Discoverable to turn off CONNECTABLE')
172                self.test_discoverable()
173                self.test_nondiscoverable()
174                current_settings = self.read_info()[4]
175                flags = self.get_dev_info()[3]
176                self.log_flags('Discoverability Toggled', flags)
177                if flags & bluetooth_socket.HCI_PSCAN:
178                    raise error.TestFail('PSCAN on after toggling DISCOVERABLE')
179
180            previous_settings = current_settings
181            previous_flags = flags
182
183            self.add_device(DEVICE_ADDRESS, ADDRESS_TYPE, 1)
184
185            # Wait for a few seconds before reading the settings
186            time.sleep(3)
187            current_settings = self.read_info()[4]
188            self.log_settings("After add device",
189                                              current_settings)
190
191            flags = self.get_dev_info()[3]
192            self.log_flags('After add device', flags)
193
194            if current_settings != previous_settings:
195                self.log_settings("previous settings", previous_settings)
196                self.log_settings("current settings", current_settings)
197                raise error.TestFail(
198                    'Bluetooth adapter settings changed after add device')
199            if not flags & bluetooth_socket.HCI_PSCAN:
200                raise error.TestFail('HCI PSCAN flag not set after add device')
201
202            # Remove the device again, and make sure the PSCAN flag goes away.
203            self.remove_device(DEVICE_ADDRESS, ADDRESS_TYPE)
204
205            # PSCAN is still enabled for a few seconds after remove device
206            # on older devices. Wait for few second before reading the settigs
207            time.sleep(3)
208            current_settings = self.read_info()[4]
209            self.log_settings("After remove device", current_settings)
210
211            flags = self.get_dev_info()[3]
212            self.log_flags('After remove device', flags)
213
214            if current_settings != previous_settings:
215                raise error.TestFail(
216                    'Bluetooth adapter settings changed after remove device')
217            if flags & bluetooth_socket.HCI_PSCAN:
218                raise error.TestFail('HCI PSCAN flag set after remove device')
219
220        # Finally power off the adapter again, and verify that the adapter has
221        # returned to powered down.
222        self.test_power_off_adapter()
223        current_settings = self.read_info()[4]
224        self.log_settings("After power down", current_settings)
225
226        if current_settings & bluetooth_socket.MGMT_SETTING_POWERED:
227            raise error.TestFail('Bluetooth adapter is powered after power off')
228
229        # Verify that the Bluetooth Daemon sees the same state as the kernel.
230        bluez_properties = self.get_adapter_properties()
231
232        if bluez_properties['Powered']:
233            raise error.TestFail('Bluetooth daemon Powered property does not '
234                                 'match kernel after power off')
235        if not self.compare_property(bluez_properties['Discoverable'],
236                                     bluetooth_socket.MGMT_SETTING_DISCOVERABLE,
237                                     current_settings):
238            raise error.TestFail('Bluetooth daemon Discoverable property '
239                                 'does not match kernel after off')
240        if bluez_properties['Discovering']:
241            raise error.TestFail('Bluetooth daemon believes adapter is '
242                                 'discovering after power off')
243
244        # And one last comparison with the raw HCI state of the adapter.
245        flags = self.get_dev_info()[3]
246        self.log_flags('After power down', flags)
247
248        if flags & bluetooth_socket.HCI_UP:
249            raise error.TestFail('HCI UP flag does not match kernel after '
250                                 'power off')
251