1#!/usr/bin/env python3 2# 3# Copyright 2020 - 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 os 18import time 19import glob 20import errno 21from collections import namedtuple 22from pandas import DataFrame 23from acts import utils 24from acts import signals 25from acts.base_test import BaseTestClass 26from acts.controllers.gnss_lib import GnssSimulator 27from acts.context import get_current_context 28from acts_contrib.test_utils.gnss import dut_log_test_utils as diaglog 29from acts_contrib.test_utils.gnss import gnss_test_utils as gutils 30from acts_contrib.test_utils.gnss import gnss_testlog_utils as glogutils 31from acts_contrib.test_utils.gnss.gnss_defines import DEVICE_GPSLOG_FOLDER 32from acts_contrib.test_utils.gnss.gnss_defines import GPS_PKG_NAME 33from acts_contrib.test_utils.gnss.gnss_defines import BCM_GPS_XML_PATH 34 35 36class LabTtffTestBase(BaseTestClass): 37 """ LAB TTFF Tests Base Class""" 38 GTW_GPSTOOL_APP = 'gtw_gpstool_apk' 39 GNSS_SIMULATOR_KEY = 'gnss_simulator' 40 GNSS_SIMULATOR_IP_KEY = 'gnss_simulator_ip' 41 GNSS_SIMULATOR_PORT_KEY = 'gnss_simulator_port' 42 GNSS_SIMULATOR_PORT_CTRL_KEY = 'gnss_simulator_port_ctrl' 43 GNSS_SIMULATOR_SCENARIO_KEY = 'gnss_simulator_scenario' 44 GNSS_SIMULATOR_POWER_LEVEL_KEY = 'gnss_simulator_power_level' 45 CUSTOM_FILES_KEY = 'custom_files' 46 CSTTFF_CRITERIA = 'cs_criteria' 47 HSTTFF_CRITERIA = 'hs_criteria' 48 WSTTFF_CRITERIA = 'ws_criteria' 49 CSTTFF_PECRITERIA = 'cs_ttff_pecriteria' 50 HSTTFF_PECRITERIA = 'hs_ttff_pecriteria' 51 WSTTFF_PECRITERIA = 'ws_ttff_pecriteria' 52 TTFF_ITERATION = 'ttff_iteration' 53 SIMULATOR_LOCATION = 'simulator_location' 54 DIAG_OPTION = 'diag_option' 55 56 def __init__(self, controllers): 57 """ Initializes class attributes. """ 58 59 super().__init__(controllers) 60 61 self.dut = None 62 self.gnss_simulator = None 63 self.rockbottom_script = None 64 self.gnss_log_path = self.log_path 65 self.gps_xml_bk_path = BCM_GPS_XML_PATH + '.bk' 66 67 def setup_class(self): 68 super().setup_class() 69 70 req_params = [ 71 self.GNSS_SIMULATOR_KEY, self.GNSS_SIMULATOR_IP_KEY, 72 self.GNSS_SIMULATOR_PORT_KEY, self.GNSS_SIMULATOR_SCENARIO_KEY, 73 self.GNSS_SIMULATOR_POWER_LEVEL_KEY, self.CSTTFF_CRITERIA, 74 self.HSTTFF_CRITERIA, self.WSTTFF_CRITERIA, self.TTFF_ITERATION, 75 self.SIMULATOR_LOCATION, self.DIAG_OPTION 76 ] 77 78 self.unpack_userparams(req_param_names=req_params) 79 self.dut = self.android_devices[0] 80 self.gnss_simulator_scenario = self.user_params[ 81 self.GNSS_SIMULATOR_SCENARIO_KEY] 82 self.gnss_simulator_power_level = self.user_params[ 83 self.GNSS_SIMULATOR_POWER_LEVEL_KEY] 84 self.gtw_gpstool_app = self.user_params[self.GTW_GPSTOOL_APP] 85 custom_files = self.user_params.get(self.CUSTOM_FILES_KEY, []) 86 self.cs_ttff_criteria = self.user_params.get(self.CSTTFF_CRITERIA, []) 87 self.hs_ttff_criteria = self.user_params.get(self.HSTTFF_CRITERIA, []) 88 self.ws_ttff_criteria = self.user_params.get(self.WSTTFF_CRITERIA, []) 89 self.cs_ttff_pecriteria = self.user_params.get(self.CSTTFF_PECRITERIA, 90 []) 91 self.hs_ttff_pecriteria = self.user_params.get(self.HSTTFF_PECRITERIA, 92 []) 93 self.ws_ttff_pecriteria = self.user_params.get(self.WSTTFF_PECRITERIA, 94 []) 95 self.ttff_iteration = self.user_params.get(self.TTFF_ITERATION, []) 96 self.simulator_location = self.user_params.get(self.SIMULATOR_LOCATION, 97 []) 98 self.diag_option = self.user_params.get(self.DIAG_OPTION, []) 99 100 # Create gnss_simulator instance 101 gnss_simulator_key = self.user_params[self.GNSS_SIMULATOR_KEY] 102 gnss_simulator_ip = self.user_params[self.GNSS_SIMULATOR_IP_KEY] 103 gnss_simulator_port = self.user_params[self.GNSS_SIMULATOR_PORT_KEY] 104 if gnss_simulator_key == 'gss7000': 105 gnss_simulator_port_ctrl = self.user_params[ 106 self.GNSS_SIMULATOR_PORT_CTRL_KEY] 107 else: 108 gnss_simulator_port_ctrl = None 109 self.gnss_simulator = GnssSimulator.AbstractGnssSimulator( 110 gnss_simulator_key, gnss_simulator_ip, gnss_simulator_port, 111 gnss_simulator_port_ctrl) 112 113 test_type = namedtuple('Type', ['command', 'criteria']) 114 self.test_types = { 115 'cs': test_type('Cold Start', self.cs_ttff_criteria), 116 'ws': test_type('Warm Start', self.ws_ttff_criteria), 117 'hs': test_type('Hot Start', self.hs_ttff_criteria) 118 } 119 120 # Unpack the rockbottom script file if its available. 121 for file in custom_files: 122 if 'rockbottom_' + self.dut.model in file: 123 self.rockbottom_script = file 124 break 125 126 def setup_test(self): 127 128 self.clear_gps_log() 129 self.gnss_simulator.stop_scenario() 130 self.gnss_simulator.close() 131 if self.rockbottom_script: 132 self.log.info('Running rockbottom script for this device ' + 133 self.dut.model) 134 self.dut_rockbottom() 135 else: 136 self.log.info('Not running rockbottom for this device ' + 137 self.dut.model) 138 139 utils.set_location_service(self.dut, True) 140 gutils.reinstall_package_apk(self.dut, GPS_PKG_NAME, 141 self.gtw_gpstool_app) 142 143 # For BCM DUTs, delete gldata.sto and set IgnoreRomAlm="true" based on b/196936791#comment20 144 if self.diag_option == "BCM": 145 gutils.remount_device(self.dut) 146 # Backup gps.xml 147 copy_cmd = "cp {} {}".format(BCM_GPS_XML_PATH, self.gps_xml_bk_path) 148 self.dut.adb.shell(copy_cmd) 149 gutils.delete_bcm_nvmem_sto_file(self.dut) 150 gutils.bcm_gps_ignore_rom_alm(self.dut) 151 # Reboot DUT to apply the setting 152 gutils.reboot(self.dut) 153 self.gnss_simulator.connect() 154 155 def dut_rockbottom(self): 156 """ 157 Set the dut to rockbottom state 158 159 """ 160 # The rockbottom script might include a device reboot, so it is 161 # necessary to stop SL4A during its execution. 162 self.dut.stop_services() 163 self.log.info('Executing rockbottom script for ' + self.dut.model) 164 os.chmod(self.rockbottom_script, 0o777) 165 os.system('{} {}'.format(self.rockbottom_script, self.dut.serial)) 166 # Make sure the DUT is in root mode after coming back 167 self.dut.root_adb() 168 # Restart SL4A 169 self.dut.start_services() 170 171 def teardown_test(self): 172 """Teardown settings for the test class""" 173 super().teardown_test() 174 # Restore the gps.xml everytime after the test. 175 if self.diag_option == "BCM": 176 # Restore gps.xml 177 rm_cmd = "rm -rf {}".format(BCM_GPS_XML_PATH) 178 restore_cmd = "mv {} {}".format(self.gps_xml_bk_path, 179 BCM_GPS_XML_PATH) 180 self.dut.adb.shell(rm_cmd) 181 self.dut.adb.shell(restore_cmd) 182 183 def teardown_class(self): 184 """ Executed after completing all selected test cases.""" 185 self.clear_gps_log() 186 if self.gnss_simulator: 187 self.gnss_simulator.stop_scenario() 188 self.gnss_simulator.close() 189 190 def start_and_set_gnss_simulator_power(self): 191 """ 192 Start GNSS simulator secnario and set power level. 193 194 """ 195 196 self.gnss_simulator.start_scenario(self.gnss_simulator_scenario) 197 time.sleep(25) 198 self.gnss_simulator.set_power(self.gnss_simulator_power_level) 199 200 def get_and_verify_ttff(self, mode): 201 """Retrieve ttff with designate mode. 202 203 Args: 204 mode: A string for identify gnss test mode. 205 """ 206 if mode not in self.test_types: 207 raise signals.TestError('Unrecognized mode %s' % mode) 208 test_type = self.test_types.get(mode) 209 210 if mode != 'cs': 211 wait_time = 900 212 else: 213 wait_time = 300 214 215 gutils.process_gnss_by_gtw_gpstool(self.dut, 216 self.test_types['cs'].criteria) 217 begin_time = gutils.get_current_epoch_time() 218 gutils.start_ttff_by_gtw_gpstool(self.dut, 219 ttff_mode=mode, 220 iteration=self.ttff_iteration, 221 raninterval=True, 222 hot_warm_sleep=wait_time) 223 # Since Wear takes little longer to update the TTFF info. 224 # Workround to solve the wearable timing issue 225 if gutils.is_device_wearable(self.dut): 226 time.sleep(20) 227 228 ttff_data = gutils.process_ttff_by_gtw_gpstool(self.dut, begin_time, 229 self.simulator_location) 230 231 # Create folder for GTW GPStool's log 232 gps_log_path = os.path.join(self.gnss_log_path, 'GPSLogs') 233 os.makedirs(gps_log_path, exist_ok=True) 234 235 self.dut.adb.pull("{} {}".format(DEVICE_GPSLOG_FOLDER, gps_log_path)) 236 237 gps_api_log = glob.glob(gps_log_path + '/*/GNSS_*.txt') 238 ttff_loop_log = glob.glob(gps_log_path + 239 '/*/GPS_{}_*.txt'.format(mode.upper())) 240 241 if not gps_api_log and ttff_loop_log: 242 raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), 243 gps_log_path) 244 245 df = DataFrame(glogutils.parse_gpstool_ttfflog_to_df(gps_api_log[0])) 246 247 ttff_dict = {} 248 for i in ttff_data: 249 d = ttff_data[i]._asdict() 250 ttff_dict[i] = dict(d) 251 252 ttff_time = [] 253 ttff_pe = [] 254 ttff_haccu = [] 255 for i in ttff_dict.keys(): 256 ttff_time.append(ttff_dict[i]['ttff_sec']) 257 ttff_pe.append(ttff_dict[i]['ttff_pe']) 258 ttff_haccu.append(ttff_dict[i]['ttff_haccu']) 259 df['ttff_sec'] = ttff_time 260 df['ttff_pe'] = ttff_pe 261 df['ttff_haccu'] = ttff_haccu 262 df.to_json(gps_log_path + '/gps_log.json', orient='table') 263 result = gutils.check_ttff_data(self.dut, 264 ttff_data, 265 ttff_mode=test_type.command, 266 criteria=test_type.criteria) 267 if not result: 268 raise signals.TestFailure('%s TTFF fails to reach ' 269 'designated criteria' % test_type.command) 270 return ttff_data 271 272 def verify_pe(self, mode): 273 """ 274 Verify ttff Position Error with designate mode. 275 276 Args: 277 mode: A string for identify gnss test mode. 278 """ 279 280 ffpe_type = namedtuple('Type', ['command', 'pecriteria']) 281 ffpe_types = { 282 'cs': ffpe_type('Cold Start', self.cs_ttff_pecriteria), 283 'ws': ffpe_type('Warm Start', self.ws_ttff_pecriteria), 284 'hs': ffpe_type('Hot Start', self.hs_ttff_pecriteria) 285 } 286 287 if mode not in ffpe_types: 288 raise signals.TestError('Unrecognized mode %s' % mode) 289 test_type = ffpe_types.get(mode) 290 291 ttff_data = self.get_and_verify_ttff(mode) 292 result = gutils.check_ttff_pe(self.dut, 293 ttff_data, 294 ttff_mode=test_type.command, 295 pe_criteria=test_type.pecriteria) 296 if not result: 297 raise signals.TestFailure('%s TTFF fails to reach ' 298 'designated criteria' % test_type.command) 299 return ttff_data 300 301 def clear_gps_log(self): 302 """ 303 Delete the existing GPS GTW Log from DUT. 304 305 """ 306 self.dut.adb.shell("rm -rf {}".format(DEVICE_GPSLOG_FOLDER)) 307 308 def gnss_ttff_ffpe(self, mode, sub_context_path=''): 309 """ 310 Base ttff and ffpe function 311 Args: 312 mode: Set the TTFF mode for testing. Definitions are as below. 313 cs(cold start), ws(warm start), hs(hot start) 314 sub_context_path: Set specifc log pathfor ttff_ffpe 315 """ 316 # Create log file path 317 full_output_path = get_current_context().get_full_output_path() 318 self.gnss_log_path = os.path.join(full_output_path, sub_context_path) 319 os.makedirs(self.gnss_log_path, exist_ok=True) 320 self.log.debug('Create log path: {}'.format(self.gnss_log_path)) 321 322 # Start and set GNSS simulator 323 self.start_and_set_gnss_simulator_power() 324 325 # Start GNSS chip log 326 if self.diag_option == "QCOM": 327 diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile) 328 else: 329 gutils.start_pixel_logger(self.dut) 330 331 # Start verifying TTFF and FFPE 332 self.verify_pe(mode) 333 334 # Set gnss_vendor_log_path based on GNSS solution vendor 335 gnss_vendor_log_path = os.path.join(self.gnss_log_path, 336 self.diag_option) 337 os.makedirs(gnss_vendor_log_path, exist_ok=True) 338 339 # Stop GNSS chip log and pull the logs to local file system 340 if self.diag_option == "QCOM": 341 diaglog.stop_background_diagmdlog(self.dut, 342 gnss_vendor_log_path, 343 keep_logs=False) 344 else: 345 gutils.stop_pixel_logger(self.dut) 346 self.log.info('Getting Pixel BCM Log!') 347 diaglog.get_pixellogger_bcm_log(self.dut, 348 gnss_vendor_log_path, 349 keep_logs=False) 350