1#!/usr/bin/env python3
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16"""
17Test script to exercises different ways Ble Advertisements can run in
18concurrency. This test was designed to be run in a shield box.
19"""
20
21import concurrent
22import os
23import time
24
25from queue import Empty
26from acts.test_decorators import test_tracker_info
27from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
28from acts.test_utils.bt.bt_test_utils import BtTestUtilsError
29from acts.test_utils.bt.bt_constants import ble_advertise_settings_modes
30from acts.test_utils.bt.bt_constants import ble_scan_settings_callback_types
31from acts.test_utils.bt.bt_constants import ble_scan_settings_modes
32from acts.test_utils.bt.bt_constants import adv_succ
33from acts.test_utils.bt.bt_test_utils import generate_ble_advertise_objects
34from acts.test_utils.bt.bt_test_utils import generate_ble_scan_objects
35from acts.test_utils.bt.bt_test_utils import get_advanced_droid_list
36from acts.test_utils.bt.bt_test_utils import reset_bluetooth
37from acts.test_utils.bt.bt_test_utils import scan_and_verify_n_advertisements
38from acts.test_utils.bt.bt_constants import scan_result
39from acts.test_utils.bt.bt_test_utils import setup_n_advertisements
40from acts.test_utils.bt.bt_test_utils import take_btsnoop_logs
41from acts.test_utils.bt.bt_test_utils import teardown_n_advertisements
42
43
44class ConcurrentBleAdvertisingTest(BluetoothBaseTest):
45    default_timeout = 10
46    max_advertisements = -1
47
48    def setup_class(self):
49        super().setup_class()
50        self.droid_list = get_advanced_droid_list(self.android_devices)
51        self.scn_ad = self.android_devices[0]
52        self.adv_ad = self.android_devices[1]
53        self.max_advertisements = self.droid_list[1]['max_advertisements']
54
55    def setup_test(self):
56        super(BluetoothBaseTest, self).setup_test()
57        return reset_bluetooth(self.android_devices)
58
59    def _verify_n_advertisements(self, num_advertisements):
60        try:
61            advertise_callback_list = setup_n_advertisements(
62                self.adv_ad, num_advertisements)
63        except BtTestUtilsError:
64            return False
65        try:
66            scan_and_verify_n_advertisements(self.scn_ad, num_advertisements)
67        except BtTestUtilsError:
68            return False
69        teardown_n_advertisements(self.adv_ad,
70                                  len(advertise_callback_list),
71                                  advertise_callback_list)
72        return True
73
74    @BluetoothBaseTest.bt_test_wrap
75    @test_tracker_info(uuid='abc03874-6d7a-4b5d-9f29-18731a102793')
76    def test_max_advertisements_defaults(self):
77        """Testing max advertisements.
78
79        Test that a single device can have the max advertisements
80        concurrently advertising.
81
82        Steps:
83        1. Setup the scanning android device.
84        2. Setup the advertiser android device.
85        3. Start scanning on the max_advertisements as defined in the script.
86        4. Verify that all advertisements are found.
87
88        Expected Result:
89        All advertisements should start without errors.
90
91        Returns:
92          Pass if True
93          Fail if False
94
95        TAGS: LE, Advertising, Concurrency
96        Priority: 0
97        """
98        return self._verify_n_advertisements(self.max_advertisements)
99
100    @BluetoothBaseTest.bt_test_wrap
101    @test_tracker_info(uuid='50ee137e-eb71-40ef-b72f-a5fd646190d2')
102    def test_max_advertisements_include_device_name_and_filter_device_name(
103            self):
104        """Testing max advertisement variant.
105
106        Test that a single device can have the max advertisements
107        concurrently advertising. Include the device name as a part of the filter
108        and advertisement data.
109
110        Steps:
111        1. Setup the scanning android device.
112        2. Setup the advertiser android device.
113        3. Include device name in each advertisement.
114        4. Include device name filter in the scanner.
115        5. Start scanning on the max_advertisements as defined in the script.
116        6. Verify that all advertisements are found.
117
118        Expected Result:
119        All advertisements should start without errors.
120
121        Returns:
122          Pass if True
123          Fail if False
124
125        TAGS: LE, Advertising, Concurrency
126        Priority: 2
127        """
128        self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
129        self.scn_ad.droid.bleSetScanFilterDeviceName(
130            self.adv_ad.droid.bluetoothGetLocalName())
131        return self._verify_n_advertisements(self.max_advertisements)
132
133    @BluetoothBaseTest.bt_test_wrap
134    @test_tracker_info(uuid='f7e9ba2b-6286-4510-a8a0-f1df831056c0')
135    def test_max_advertisements_exclude_device_name_and_filter_device_name(
136            self):
137        """Test max advertisement variant.
138
139        Test that a single device can have the max advertisements concurrently
140        advertising. Include the device name as a part of the filter but not the
141        advertisement data.
142
143        Steps:
144        1. Setup the scanning android device.
145        2. Setup the advertiser android device.
146        3. Include device name filter in the scanner.
147        4. Start scanning on the max_advertisements as defined in the script.
148        5. Verify that no advertisements are found.
149
150        Expected Result:
151        All advertisements should start without errors.
152
153        Returns:
154          Pass if True
155          Fail if False
156
157        TAGS: LE, Advertising, Concurrency
158        Priority: 2
159        """
160        self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(False)
161        self.scn_ad.droid.bleSetScanFilterDeviceName(
162            self.adv_ad.droid.bluetoothGetLocalName())
163        return not self._verify_n_advertisements(self.max_advertisements)
164
165    @BluetoothBaseTest.bt_test_wrap
166    @test_tracker_info(uuid='6ce102d7-61e1-4ca0-bcfb-767437b86c2b')
167    def test_max_advertisements_with_manufacturer_data(self):
168        """Test max advertisement variant.
169
170        Test that a single device can have the max advertisements concurrently
171        advertising. Include the manufacturer data as a part of the filter and
172        advertisement data.
173
174        Steps:
175        1. Setup the scanning android device.
176        2. Setup the advertiser android device.
177        3. Include manufacturer data in each advertisement.
178        4. Include manufacturer data filter in the scanner.
179        5. Start scanning on the max_advertisements as defined in the script.
180        6. Verify that all advertisements are found.
181
182        Expected Result:
183        All advertisements should start without errors.
184
185        Returns:
186          Pass if True
187          Fail if False
188
189        TAGS: LE, Advertising, Concurrency
190        Priority: 2
191        """
192        self.scn_ad.droid.bleSetScanFilterManufacturerData(1, [1])
193        self.adv_ad.droid.bleAddAdvertiseDataManufacturerId(1, [1])
194        return self._verify_n_advertisements(self.max_advertisements)
195
196    @BluetoothBaseTest.bt_test_wrap
197    @test_tracker_info(uuid='2fc7d5e8-1539-42a8-8681-ce0b8bfc0924')
198    def test_max_advertisements_with_manufacturer_data_mask(self):
199        """Test max advertisements variant.
200
201        Test that a single device can have the max advertisements concurrently
202        advertising. Include the manufacturer data mask as a part of the filter
203        and advertisement data.
204
205        Steps:
206        1. Setup the scanning android device.
207        2. Setup the advertiser android device.
208        3. Include manufacturer data in each advertisement.
209        4. Include manufacturer data mask filter in the scanner.
210        5. Start scanning on the max_advertisements as defined in the script.
211        6. Verify that all advertisements are found.
212
213        Expected Result:
214        All advertisements should start without errors.
215
216        Returns:
217          Pass if True
218          Fail if False
219
220        TAGS: LE, Advertising, Concurrency
221        Priority: 2
222        """
223        self.scn_ad.droid.bleSetScanFilterManufacturerData(1, [1], [1])
224        self.adv_ad.droid.bleAddAdvertiseDataManufacturerId(1, [1])
225        return self._verify_n_advertisements(self.max_advertisements)
226
227    @BluetoothBaseTest.bt_test_wrap
228    @test_tracker_info(uuid='9ef615ed-1705-44ae-ab5b-f7e8fb4bb770')
229    def test_max_advertisements_with_service_data(self):
230        """Test max advertisement variant.
231
232        Test that a single device can have the max advertisements concurrently
233        advertising. Include the service data as a part of the filter and
234        advertisement data.
235
236        Steps:
237        1. Setup the scanning android device.
238        2. Setup the advertiser android device.
239        3. Include service data in each advertisement.
240        4. Include service data filter in the scanner.
241        5. Start scanning on the max_advertisements as defined in the script.
242        6. Verify that all advertisements are found.
243
244        Expected Result:
245        All advertisements should start without errors.
246
247        Returns:
248          Pass if True
249          Fail if False
250
251        TAGS: LE, Advertising, Concurrency
252        Priority: 2
253        """
254        test_result = True
255        filter_list = self.scn_ad.droid.bleGenFilterList()
256        self.scn_ad.droid.bleSetScanFilterServiceData(
257            "0000110A-0000-1000-8000-00805F9B34FB", [11, 17, 80])
258        self.adv_ad.droid.bleAddAdvertiseDataServiceData(
259            "0000110A-0000-1000-8000-00805F9B34FB", [11, 17, 80])
260        return self._verify_n_advertisements(self.max_advertisements)
261
262    @BluetoothBaseTest.bt_test_wrap
263    @test_tracker_info(uuid='9ef615ed-1705-44ae-ab5b-f7e8fb4bb770')
264    def test_max_advertisements_with_manufacturer_data_mask_and_include_device_name(
265            self):
266        """Test max advertisement variant.
267
268        Test that a single device can have the max advertisements concurrently
269        advertising. Include the device name and manufacturer data as a part of
270        the filter and advertisement data.
271
272        Steps:
273        1. Setup the scanning android device.
274        2. Setup the advertiser android device.
275        3. Include device name and manufacturer data in each advertisement.
276        4. Include device name and manufacturer data filter in the scanner.
277        5. Start scanning on the max_advertisements as defined in the script.
278        6. Verify that all advertisements are found.
279
280        Expected Result:
281        All advertisements should start without errors.
282
283        Returns:
284          Pass if True
285          Fail if False
286
287        TAGS: LE, Advertising, Concurrency
288        Priority: 2
289        """
290        self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
291        self.scn_ad.droid.bleSetScanFilterDeviceName(
292            self.adv_ad.droid.bluetoothGetLocalName())
293        self.scn_ad.droid.bleSetScanFilterManufacturerData(1, [1], [1])
294        self.adv_ad.droid.bleAddAdvertiseDataManufacturerId(1, [1])
295        return self._verify_n_advertisements(self.max_advertisements)
296
297    @BluetoothBaseTest.bt_test_wrap
298    @test_tracker_info(uuid='c2ca85fb-6663-431d-aa30-5286a85dbbe0')
299    def test_max_advertisements_with_service_uuids(self):
300        """Test max advertisement variant.
301
302        Test that a single device can have the max advertisements concurrently
303        advertising. Include the service uuid as a part of the filter and
304        advertisement data.
305
306        Steps:
307        1. Setup the scanning android device.
308        2. Setup the advertiser android device.
309        3. Include service uuid in each advertisement.
310        4. Include service uuid filter in the scanner.
311        5. Start scanning on the max_advertisements as defined in the script.
312        6. Verify that all advertisements are found.
313
314        Expected Result:
315        All advertisements should start without errors.
316
317        Returns:
318          Pass if True
319          Fail if False
320
321        TAGS: LE, Advertising, Concurrency
322        Priority: 1
323        """
324        self.scn_ad.droid.bleSetScanFilterServiceUuid(
325            "00000000-0000-1000-8000-00805f9b34fb")
326        self.adv_ad.droid.bleSetAdvertiseDataSetServiceUuids(
327            ["00000000-0000-1000-8000-00805f9b34fb"])
328        return self._verify_n_advertisements(self.max_advertisements)
329
330    @BluetoothBaseTest.bt_test_wrap
331    @test_tracker_info(uuid='756e026f-64d7-4a2f-935a-3790c0ac4503')
332    def test_max_advertisements_with_service_uuid_and_service_mask(self):
333        """Test max advertisements variant.
334
335        Test that a single device can have the max advertisements concurrently
336        advertising. Include the service mask as a part of the filter and
337        advertisement data.
338
339        Steps:
340        1. Setup the scanning android device.
341        2. Setup the advertiser android device.
342        3. Include service uuid in each advertisement.
343        4. Include service mask filter in the scanner.
344        5. Start scanning on the max_advertisements as defined in the script.
345        6. Verify that all advertisements are found.
346
347        Expected Result:
348        All advertisements should start without errors.
349
350        Returns:
351          Pass if True
352          Fail if False
353
354        TAGS: LE, Advertising, Concurrency
355        Priority: 2
356        """
357        self.scn_ad.droid.bleSetScanFilterServiceUuid(
358            "00000000-0000-1000-8000-00805f9b34fb",
359            "00000000-0000-1000-8000-00805f9b34fb")
360        self.adv_ad.droid.bleSetAdvertiseDataSetServiceUuids(
361            ["00000000-0000-1000-8000-00805f9b34fb"])
362        return self._verify_n_advertisements(self.max_advertisements)
363
364    @BluetoothBaseTest.bt_test_wrap
365    @test_tracker_info(uuid='79c4b6cd-9f07-49a9-829f-69b29ea8d322')
366    def test_max_advertisements_plus_one(self):
367        """Test max advertisements plus one.
368
369        Test that a single device can have the max advertisements concurrently
370        advertising but fail on starting the max advertisements plus one.
371        filter and advertisement data.
372
373        Steps:
374        1. Setup the scanning android device.
375        2. Setup the advertiser android device.
376        3. Start max_advertisements + 1.
377
378        Expected Result:
379        The last advertisement should fail.
380
381        Returns:
382          Pass if True
383          Fail if False
384
385        TAGS: LE, Advertising, Concurrency
386        Priority: 0
387        """
388        return not self._verify_n_advertisements(self.max_advertisements + 1)
389
390    @BluetoothBaseTest.bt_test_wrap
391    @test_tracker_info(uuid='0bd6e490-a501-4fe1-88e5-9b77970c0b95')
392    def test_start_two_advertisements_on_same_callback(self):
393        """Test invalid advertisement scenario.
394
395        Test that a single device cannot have two advertisements start on the
396        same callback.
397
398        Steps:
399        1. Setup the scanning android device.
400        2. Setup the advertiser android device.
401        3. Call start ble advertising on the same callback.
402
403        Expected Result:
404        The second call of start advertising on the same callback should fail.
405
406        Returns:
407          Pass if True
408          Fail if False
409
410        TAGS: LE, Advertising, Concurrency
411        Priority: 1
412        """
413        test_result = True
414        advertise_callback, advertise_data, advertise_settings = (
415            generate_ble_advertise_objects(self.adv_ad.droid))
416        self.adv_ad.droid.bleStartBleAdvertising(
417            advertise_callback, advertise_data, advertise_settings)
418        try:
419            self.adv_ad.ed.pop_event(
420                adv_succ.format(advertise_callback), self.default_timeout)
421        except Empty as error:
422            self.log.error("Test failed with Empty error: {}".format(error))
423            return False
424        except concurrent.futures._base.TimeoutError as error:
425            self.log.debug(
426                "Test failed, filtering callback onSuccess never occurred: {}"
427                .format(error))
428        try:
429            self.adv_ad.droid.bleStartBleAdvertising(
430                advertise_callback, advertise_data, advertise_settings)
431            self.adv_ad.ed.pop_event(
432                adv_succ.format(advertise_callback), self.default_timeout)
433            test_result = False
434        except Empty as error:
435            self.log.debug("Test passed with Empty error: {}".format(error))
436        except concurrent.futures._base.TimeoutError as error:
437            self.log.debug(
438                "Test passed, filtering callback onSuccess never occurred: {}"
439                .format(error))
440
441        return test_result
442
443    @BluetoothBaseTest.bt_test_wrap
444    @test_tracker_info(uuid='12632b31-22b9-4121-80b6-1263b9d90909')
445    def test_toggle_advertiser_bt_state(self):
446        """Test forcing stopping advertisements.
447
448        Test that a single device resets its callbacks when the bluetooth state is
449        reset. There should be no advertisements.
450
451        Steps:
452        1. Setup the scanning android device.
453        2. Setup the advertiser android device.
454        3. Call start ble advertising.
455        4. Toggle bluetooth on and off.
456        5. Scan for any advertisements.
457
458        Expected Result:
459        No advertisements should be found after toggling Bluetooth on the
460        advertising device.
461
462        Returns:
463          Pass if True
464          Fail if False
465
466        TAGS: LE, Advertising, Concurrency
467        Priority: 2
468        """
469        test_result = True
470        self.adv_ad.droid.bleSetAdvertiseDataIncludeDeviceName(True)
471        advertise_callback, advertise_data, advertise_settings = (
472            generate_ble_advertise_objects(self.adv_ad.droid))
473        self.adv_ad.droid.bleStartBleAdvertising(
474            advertise_callback, advertise_data, advertise_settings)
475        try:
476            self.adv_ad.ed.pop_event(
477                adv_succ.format(advertise_callback), self.default_timeout)
478        except Empty as error:
479            self.log.error("Test failed with Empty error: {}".format(error))
480            return False
481        except concurrent.futures._base.TimeoutError as error:
482            self.log.error(
483                "Test failed, filtering callback onSuccess never occurred: {}".
484                format(error))
485        self.scn_ad.droid.bleSetScanSettingsScanMode(
486            ble_scan_settings_modes['low_latency'])
487        self.scn_ad.droid.bleSetScanFilterDeviceName(
488            self.adv_ad.droid.bluetoothGetLocalName())
489        filter_list, scan_settings, scan_callback = generate_ble_scan_objects(
490            self.scn_ad.droid)
491        self.scn_ad.droid.bleBuildScanFilter(filter_list)
492        self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
493                                          scan_callback)
494        try:
495            self.scn_ad.ed.pop_event(
496                scan_result.format(scan_callback), self.default_timeout)
497        except Empty as error:
498            self.log.error("Test failed with: {}".format(error))
499            return False
500        self.scn_ad.droid.bleStopBleScan(scan_callback)
501        test_result = reset_bluetooth([self.android_devices[1]])
502        self.scn_ad.droid.bleStartBleScan(filter_list, scan_settings,
503                                          scan_callback)
504        if not test_result:
505            return False
506        try:
507            expected_event = scan_result.format(scan_callback)
508            event = self.scn_ad.ed.pop_event(expected_event,
509                                             self.default_timeout)
510            self.log.error("Event {} not expected. Found: {}".format(
511                expected_event, event))
512            return False
513        except Empty as error:
514            self.log.debug("Test passed with: {}".format(error))
515        self.scn_ad.droid.bleStopBleScan(scan_callback)
516        self.adv_ad.droid.bleStopBleAdvertising(advertise_callback)
517        return True
518
519    @BluetoothBaseTest.bt_test_wrap
520    @test_tracker_info(uuid='785c5c77-d5d4-4d0f-8b7b-3eb1f1646d2c')
521    def test_restart_advertise_callback_after_bt_toggle(self):
522        """Test starting an advertisement on a cleared out callback.
523
524        Test that a single device resets its callbacks when the bluetooth state
525        is reset.
526
527        Steps:
528        1. Setup the scanning android device.
529        2. Setup the advertiser android device.
530        3. Call start ble advertising.
531        4. Toggle bluetooth on and off.
532        5. Call start ble advertising on the same callback.
533
534        Expected Result:
535        Starting an advertisement on a callback id after toggling bluetooth
536        should fail.
537
538        Returns:
539          Pass if True
540          Fail if False
541
542        TAGS: LE, Advertising, Concurrency
543        Priority: 1
544        """
545        test_result = True
546        advertise_callback, advertise_data, advertise_settings = (
547            generate_ble_advertise_objects(self.adv_ad.droid))
548        self.adv_ad.droid.bleStartBleAdvertising(
549            advertise_callback, advertise_data, advertise_settings)
550        try:
551            self.adv_ad.ed.pop_event(
552                adv_succ.format(advertise_callback), self.default_timeout)
553        except Empty as error:
554            self.log.error("Test failed with Empty error: {}".format(error))
555            test_result = False
556        except concurrent.futures._base.TimeoutError as error:
557            self.log.debug(
558                "Test failed, filtering callback onSuccess never occurred: {}".
559                format(error))
560        test_result = reset_bluetooth([self.android_devices[1]])
561        if not test_result:
562            return test_result
563        self.adv_ad.droid.bleStartBleAdvertising(
564            advertise_callback, advertise_data, advertise_settings)
565        try:
566            self.adv_ad.ed.pop_event(
567                adv_succ.format(advertise_callback), self.default_timeout)
568        except Empty as error:
569            self.log.error("Test failed with Empty error: {}".format(error))
570            test_result = False
571        except concurrent.futures._base.TimeoutError as error:
572            self.log.debug(
573                "Test failed, filtering callback onSuccess never occurred: {}".
574                format(error))
575        return test_result
576
577    @BluetoothBaseTest.bt_test_wrap
578    @test_tracker_info(uuid='dd5529b7-6774-4580-8b29-d84568c15442')
579    def test_timeout(self):
580        """Test starting advertiser with timeout.
581
582        Test that when a timeout is used, the advertiser is cleaned properly,
583        and next one can be started.
584
585        Steps:
586        1. Setup the advertiser android device with 4 second timeout.
587        2. Call start ble advertising.
588        3. Wait 5 seconds, to make sure advertiser times out.
589        4. Repeat steps 1-4 four times.
590
591        Expected Result:
592        Starting the advertising should succeed each time.
593
594        Returns:
595          Pass if True
596          Fail if False
597
598        TAGS: LE, Advertising, Concurrency
599        Priority: 1
600        """
601        advertise_timeout_s = 4
602        num_iterations = 4
603        test_result = True
604
605        for i in range(0, num_iterations):
606            advertise_callback, advertise_data, advertise_settings = (
607                generate_ble_advertise_objects(self.adv_ad.droid))
608
609            self.adv_ad.droid.bleSetAdvertiseSettingsTimeout(
610                advertise_timeout_s * 1000)
611
612            self.adv_ad.droid.bleStartBleAdvertising(
613                advertise_callback, advertise_data, advertise_settings)
614            try:
615                self.adv_ad.ed.pop_event(
616                    adv_succ.format(advertise_callback), self.default_timeout)
617            except Empty as error:
618                self.log.error("Test failed with Empty error: {}".format(
619                    error))
620                test_result = False
621            except concurrent.futures._base.TimeoutError as error:
622                self.log.debug(
623                    "Test failed, filtering callback onSuccess never occurred: {}".
624                    format(error))
625
626            if not test_result:
627                return test_result
628
629            time.sleep(advertise_timeout_s + 1)
630
631        return test_result
632