1#!/usr/bin/env python3 2# 3# Copyright 2021 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of 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, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import logging 18import os 19import traceback 20from functools import wraps 21 22from blueberry.tests.gd.cert.closable import safeClose 23from blueberry.tests.gd.cert.context import get_current_context 24from blueberry.tests.gd_sl4a.lib.ble_lib import BleLib 25from blueberry.tests.gd_sl4a.lib.ble_lib import disable_bluetooth 26from blueberry.tests.gd_sl4a.lib.ble_lib import enable_bluetooth 27from blueberry.tests.sl4a_sl4a.lib.le_advertiser import LeAdvertiser 28from blueberry.tests.sl4a_sl4a.lib.le_scanner import LeScanner 29from blueberry.tests.sl4a_sl4a.lib.l2cap import L2cap 30from blueberry.tests.sl4a_sl4a.lib.security import Security 31from blueberry.utils.mobly_sl4a_utils import setup_sl4a 32from blueberry.utils.mobly_sl4a_utils import teardown_sl4a 33from grpc import RpcError 34from mobly import signals 35from mobly.base_test import BaseTestClass 36from mobly.controllers import android_device 37from mobly.controllers.android_device import MOBLY_CONTROLLER_CONFIG_NAME as ANDROID_DEVICE_CONFIG_NAME 38from mobly.controllers.android_device_lib.adb import AdbError 39 40 41class Sl4aSl4aBaseTestClass(BaseTestClass): 42 43 # DUT 44 dut_advertiser_ = None 45 dut_scanner_ = None 46 dut_security_ = None 47 dut_l2cap_ = None 48 49 # CERT 50 cert_advertiser_ = None 51 cert_scanner_ = None 52 cert_security_ = None 53 cert_l2cap_ = None 54 55 SUBPROCESS_WAIT_TIMEOUT_SECONDS = 10 56 57 def setup_class(self): 58 self.log_path_base = get_current_context().get_full_output_path() 59 self.verbose_mode = bool(self.user_params.get('verbose_mode', False)) 60 61 # Parse and construct Android device objects 62 self.android_devices = self.register_controller(android_device, required=True) 63 64 # Setup SL4A for dut, overriding default mobly port settings 65 self.dut = self.android_devices[0] 66 server_port = int(self.controller_configs[ANDROID_DEVICE_CONFIG_NAME][0]['server_port']) 67 forwarded_port = int(self.controller_configs[ANDROID_DEVICE_CONFIG_NAME][0]['forwarded_port']) 68 setup_sl4a(self.dut, server_port, forwarded_port) 69 70 # Setup SL4A for cert, overriding default mobly port settings 71 self.cert = self.android_devices[1] 72 server_port = int(self.controller_configs[ANDROID_DEVICE_CONFIG_NAME][1]['server_port']) 73 forwarded_port = int(self.controller_configs[ANDROID_DEVICE_CONFIG_NAME][1]['forwarded_port']) 74 setup_sl4a(self.cert, server_port, forwarded_port) 75 76 # Enable full btsnoop log 77 self.dut.adb.root() 78 self.dut.adb.shell("setprop persist.bluetooth.btsnooplogmode full") 79 getprop_result = self.dut.adb.getprop("persist.bluetooth.btsnooplogmode") 80 if getprop_result is None or ("full" not in getprop_result.lower()): 81 self.dut.log.warning( 82 "Failed to enable Bluetooth HCI Snoop Logging on DUT, mode is {}".format(getprop_result)) 83 self.cert.adb.root() 84 self.cert.adb.shell("setprop persist.bluetooth.btsnooplogmode full") 85 getprop_result = self.cert.adb.getprop("persist.bluetooth.btsnooplogmode") 86 if getprop_result is None or ("full" not in getprop_result.lower()): 87 self.cert.log.warning( 88 "Failed to enable Bluetooth HCI Snoop Logging on CERT, mode is {}".format(getprop_result)) 89 90 self.ble = BleLib(dut=self.dut) 91 92 def teardown_class(self): 93 teardown_sl4a(self.cert) 94 teardown_sl4a(self.dut) 95 super().teardown_class() 96 97 def setup_device_for_test(self, device): 98 device.ed.clear_all_events() 99 device.sl4a.setScreenTimeout(500) 100 device.sl4a.wakeUpNow() 101 102 # Always start tests with Bluetooth enabled and BLE disabled. 103 device.sl4a.bluetoothDisableBLE() 104 disable_bluetooth(device.sl4a, device.ed) 105 # Enable full verbose logging for Bluetooth 106 device.adb.shell("setprop log.tag.bluetooth VERBOSE") 107 # Then enable Bluetooth 108 enable_bluetooth(device.sl4a, device.ed) 109 device.sl4a.bluetoothDisableBLE() 110 111 def setup_test(self): 112 self.setup_device_for_test(self.dut) 113 self.setup_device_for_test(self.cert) 114 self.dut_advertiser_ = LeAdvertiser(self.dut) 115 self.dut_scanner_ = LeScanner(self.dut) 116 self.dut_security_ = Security(self.dut) 117 self.dut_l2cap_ = L2cap(self.dut) 118 self.cert_advertiser_ = LeAdvertiser(self.cert) 119 self.cert_scanner_ = LeScanner(self.cert) 120 self.cert_security_ = Security(self.cert) 121 self.cert_l2cap_ = L2cap(self.cert) 122 return True 123 124 def teardown_test(self): 125 # Go ahead and remove everything before turning off the stack 126 safeClose(self.dut_advertiser_) 127 safeClose(self.dut_scanner_) 128 safeClose(self.dut_security_) 129 safeClose(self.dut_l2cap_) 130 safeClose(self.cert_advertiser_) 131 safeClose(self.cert_scanner_) 132 safeClose(self.cert_security_) 133 safeClose(self.cert_l2cap_) 134 self.dut_advertiser_ = None 135 self.dut_scanner_ = None 136 self.dut_security_ = None 137 self.cert_advertiser_ = None 138 self.cert_l2cap_ = None 139 self.cert_scanner_ = None 140 self.cert_security_ = None 141 142 # Make sure BLE is disabled and Bluetooth is disabled after test 143 self.dut.sl4a.bluetoothDisableBLE() 144 disable_bluetooth(self.dut.sl4a, self.dut.ed) 145 self.cert.sl4a.bluetoothDisableBLE() 146 disable_bluetooth(self.cert.sl4a, self.cert.ed) 147 148 current_test_dir = get_current_context().get_full_output_path() 149 150 # Pull DUT logs 151 self.pull_logs(current_test_dir, self.dut) 152 153 # Pull CERT logs 154 self.pull_logs(current_test_dir, self.cert) 155 return True 156 157 def pull_logs(self, base_dir, device): 158 try: 159 device.adb.pull([ 160 "/data/misc/bluetooth/logs/btsnoop_hci.log", 161 os.path.join(base_dir, "DUT_%s_btsnoop_hci.log" % device.serial) 162 ]) 163 device.adb.pull([ 164 "/data/misc/bluedroid/bt_config.conf", 165 os.path.join(base_dir, "DUT_%s_bt_config.conf" % device.serial) 166 ]) 167 except AdbError as error: 168 logging.warning("Failed to pull logs from DUT: " + str(error)) 169 170 def __getattribute__(self, name): 171 attr = super().__getattribute__(name) 172 if not callable(attr) or not Sl4aSl4aBaseTestClass.__is_entry_function(name): 173 return attr 174 175 @wraps(attr) 176 def __wrapped(*args, **kwargs): 177 try: 178 return attr(*args, **kwargs) 179 except RpcError as e: 180 exception_info = "".join(traceback.format_exception(e.__class__, e, e.__traceback__)) 181 raise signals.TestFailure("RpcError during test\n\nRpcError:\n\n%s" % (exception_info)) 182 183 return __wrapped 184 185 __ENTRY_METHODS = {"setup_class", "teardown_class", "setup_test", "teardown_test"} 186 187 @staticmethod 188 def __is_entry_function(name): 189 return name.startswith("test_") or name in Sl4aSl4aBaseTestClass.__ENTRY_METHODS 190