1#!/usr/bin/env python3.4 2# 3# Copyright 2022 - 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 collections 18import logging 19import os 20import re 21import time 22from queue import Empty 23from acts.controllers.adb_lib.error import AdbError 24from acts.controllers.android_lib.tel import tel_utils 25 26PCC_PRESET_MAPPING = { 27 'N257': { 28 'low': 2054999, 29 'mid': 2079165, 30 'high': 2090832 31 }, 32 'N258': { 33 'low': 2017499, 34 'mid': 2043749, 35 'high': 2057499 36 }, 37 'N260': { 38 'low': 2229999, 39 'mid': 2254165, 40 'high': 2265832 41 }, 42 'N261': { 43 'low': 2071667 44 } 45} 46 47DUPLEX_MODE_TO_BAND_MAPPING = { 48 'LTE': { 49 'FDD': [ 50 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 51 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 65, 66, 67, 68, 69, 70, 52 71, 72, 73, 74, 75, 76, 85, 252, 255 53 ], 54 'TDD': [ 55 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46, 47, 48, 56 50, 51, 53 57 ] 58 }, 59 'NR5G': { 60 'FDD': [ 61 'N1', 'N2', 'N3', 'N5', 'N7', 'N8', 'N12', 'N13', 'N14', 'N18', 62 'N20', 'N25', 'N26', 'N28', 'N30', 'N65', 'N66', 'N70', 'N71', 63 'N74' 64 ], 65 'TDD': [ 66 'N34', 'N38', 'N39', 'N40', 'N41', 'N48', 'N50', 'N51', 'N53', 67 'N77', 'N78', 'N79', 'N90', 'N257', 'N258', 'N259', 'N260', 'N261' 68 ] 69 }, 70} 71 72SHORT_SLEEP = 1 73LONG_SLEEP = 10 74 75POWER_STATS_DUMPSYS_CMD = 'dumpsys android.hardware.power.stats.IPowerStats/default delta' 76 77def extract_test_id(testcase_params, id_fields): 78 test_id = collections.OrderedDict( 79 (param, testcase_params[param]) for param in id_fields) 80 return test_id 81 82def generate_endc_combo_config_from_string(endc_combo_str): 83 """Function to generate ENDC combo config from combo string 84 85 Args: 86 endc_combo_str: ENDC combo descriptor (e.g. B48A[4];A[1]+N5A[2];A[1]) 87 Returns: 88 endc_combo_config: dictionary with all ENDC combo settings 89 """ 90 endc_combo_config = collections.OrderedDict() 91 endc_combo_config['endc_combo_name'] = endc_combo_str 92 endc_combo_str = endc_combo_str.replace(' ', '') 93 endc_combo_list = endc_combo_str.split('+') 94 cell_config_list = list() 95 lte_cell_count = 0 96 nr_cell_count = 0 97 lte_scc_list = [] 98 nr_dl_carriers = [] 99 nr_ul_carriers = [] 100 lte_dl_carriers = [] 101 lte_ul_carriers = [] 102 103 cell_config_regex = re.compile( 104 r'(?P<cell_type>[B,N])(?P<band>[0-9]+)(?P<bandwidth_class>[A-Z])\[bw=(?P<dl_bandwidth>[0-9]+)\]' 105 r'(\[ch=)?(?P<channel>[0-9]+)?\]?' 106 r'\[ant=(?P<dl_mimo_config>[0-9]+),?(?P<transmission_mode>[TM0-9]+)?,?(?P<num_layers>[0-9]+)?,?(?P<num_codewords>[0-9]+)?\]?;?' 107 r'(?P<ul_bandwidth_class>[A-Z])?(\[ant=)?(?P<ul_mimo_config>[0-9])?(\])?' 108 ) 109 for cell_string in endc_combo_list: 110 cell_config = re.match(cell_config_regex, cell_string).groupdict() 111 if cell_config['cell_type'] == 'B': 112 # Configure LTE specific parameters 113 cell_config['cell_type'] = 'LTE' 114 lte_cell_count = lte_cell_count + 1 115 cell_config['cell_number'] = lte_cell_count 116 if cell_config['cell_number'] == 1: 117 cell_config['pcc'] = 1 118 endc_combo_config['lte_pcc'] = cell_config['cell_number'] 119 else: 120 cell_config['pcc'] = 0 121 lte_scc_list.append(cell_config['cell_number']) 122 cell_config['duplex_mode'] = 'FDD' if int( 123 cell_config['band'] 124 ) in DUPLEX_MODE_TO_BAND_MAPPING['LTE']['FDD'] else 'TDD' 125 cell_config['dl_mimo_config'] = 'D{nss}U{nss}'.format( 126 nss=cell_config['dl_mimo_config']) 127 cell_config['dl_subframe_allocation'] = [1] * 10 128 cell_config['tdd_frame_config'] = 5 129 cell_config['tdd_ssf_config']=8 130 cell_config['tdd_ssf_config'] = 8 131 lte_dl_carriers.append(cell_config['cell_number']) 132 else: 133 # Configure NR specific parameters 134 cell_config['cell_type'] = 'NR5G' 135 nr_cell_count = nr_cell_count + 1 136 cell_config['cell_number'] = nr_cell_count 137 nr_dl_carriers.append(cell_config['cell_number']) 138 #TODO: fix NSA/SA indicator 139 cell_config['nr_cell_type'] = 'NSA' 140 cell_config['band'] = 'N' + cell_config['band'] 141 cell_config['duplex_mode'] = 'FDD' if cell_config[ 142 'band'] in DUPLEX_MODE_TO_BAND_MAPPING['NR5G']['FDD'] else 'TDD' 143 cell_config['subcarrier_spacing'] = 'MU0' if cell_config[ 144 'duplex_mode'] == 'FDD' else 'MU1' 145 cell_config['dl_mimo_config'] = 'N{nss}X{nss}'.format( 146 nss=cell_config['dl_mimo_config']) 147 148 cell_config['dl_bandwidth_class'] = cell_config['bandwidth_class'] 149 cell_config['dl_bandwidth'] = 'BW' + cell_config['dl_bandwidth'] 150 cell_config[ 151 'ul_enabled'] = 1 if cell_config['ul_bandwidth_class'] else 0 152 if cell_config['ul_enabled']: 153 cell_config['ul_mimo_config'] = 'N{nss}X{nss}'.format( 154 nss=cell_config['ul_mimo_config']) 155 if cell_config['cell_type'] == 'LTE': 156 lte_ul_carriers.append(cell_config['cell_number']) 157 elif cell_config['cell_type'] == 'NR5G': 158 nr_ul_carriers.append(cell_config['cell_number']) 159 cell_config_list.append(cell_config) 160 endc_combo_config['lte_cell_count'] = lte_cell_count 161 endc_combo_config['nr_cell_count'] = nr_cell_count 162 endc_combo_config['nr_dl_carriers'] = nr_dl_carriers 163 endc_combo_config['nr_ul_carriers'] = nr_ul_carriers 164 endc_combo_config['cell_list'] = cell_config_list 165 endc_combo_config['lte_scc_list'] = lte_scc_list 166 endc_combo_config['lte_dl_carriers'] = lte_dl_carriers 167 endc_combo_config['lte_ul_carriers'] = lte_ul_carriers 168 return endc_combo_config 169 170 171def generate_endc_combo_config_from_csv_row(test_config): 172 """Function to generate ENDC combo config from CSV test config 173 174 Args: 175 test_config: dict containing ENDC combo config from CSV 176 Returns: 177 endc_combo_config: dictionary with all ENDC combo settings 178 """ 179 for key, value in test_config.items(): 180 if value == '': 181 test_config[key] = None 182 endc_combo_config = collections.OrderedDict() 183 lte_cell_count = 0 184 nr_cell_count = 0 185 lte_scc_list = [] 186 nr_dl_carriers = [] 187 nr_ul_carriers = [] 188 lte_dl_carriers = [] 189 lte_ul_carriers = [] 190 191 cell_config_list = [] 192 if 'lte_band' in test_config and test_config['lte_band']: 193 lte_cell = { 194 'cell_type': 'LTE', 195 'cell_number': 1, 196 'pcc': 1, 197 'band': test_config['lte_band'], 198 'dl_bandwidth': test_config['lte_bandwidth'], 199 'ul_enabled': 1, 200 'duplex_mode': test_config['lte_duplex_mode'], 201 'dl_mimo_config': 'D{nss}U{nss}'.format(nss=test_config['lte_dl_mimo_config']), 202 'ul_mimo_config': 'D{nss}U{nss}'.format(nss=test_config['lte_ul_mimo_config']), 203 'transmission_mode': test_config['lte_tm_mode'], 204 'num_codewords': test_config['lte_codewords'], 205 'num_layers': test_config['lte_layers'], 206 'dl_subframe_allocation': 207 list(test_config['lte_dl_subframe_allocation']) if test_config['lte_dl_subframe_allocation'] else [1]*10, 208 'tdd_frame_config': test_config['lte_tdd_frame_config'], 209 'tdd_ssf_config': test_config['lte_tdd_ssf_config'] 210 } 211 cell_config_list.append(lte_cell) 212 endc_combo_config['lte_pcc'] = 1 213 lte_cell_count = 1 214 lte_dl_carriers = [1] 215 lte_ul_carriers = [1] 216 217 if 'nr_band' in test_config and test_config['nr_band']: 218 nr_cell = { 219 'cell_type': 220 'NR5G', 221 'cell_number': 222 1, 223 'band': 224 test_config['nr_band'], 225 'nr_cell_type': 226 test_config['nr_cell_type'], 227 'duplex_mode': 228 test_config['nr_duplex_mode'], 229 'dl_mimo_config': 230 'N{nss}X{nss}'.format(nss=test_config['nr_dl_mimo_config']), 231 'dl_bandwidth_class': 232 'A', 233 'dl_bandwidth': 234 test_config['nr_bandwidth'], 235 'ul_enabled': 236 1, 237 'ul_bandwidth_class': 238 'A', 239 'ul_mimo_config': 240 'N{nss}X{nss}'.format(nss=test_config['nr_ul_mimo_config']), 241 'subcarrier_spacing': 242 'MU0' if test_config['nr_scs'] == '15' else 'MU1' 243 } 244 cell_config_list.append(nr_cell) 245 nr_cell_count = 1 246 nr_dl_carriers = [1] 247 nr_ul_carriers = [1] 248 249 endc_combo_config['lte_cell_count'] = lte_cell_count 250 endc_combo_config['nr_cell_count'] = nr_cell_count 251 endc_combo_config['nr_dl_carriers'] = nr_dl_carriers 252 endc_combo_config['nr_ul_carriers'] = nr_ul_carriers 253 endc_combo_config['cell_list'] = cell_config_list 254 endc_combo_config['lte_scc_list'] = lte_scc_list 255 endc_combo_config['lte_dl_carriers'] = lte_dl_carriers 256 endc_combo_config['lte_ul_carriers'] = lte_ul_carriers 257 return endc_combo_config 258 259 260class DeviceUtils(): 261 262 def __new__(self, dut, log): 263 if hasattr(dut, 264 'device_type') and dut.device_type == 'android_non_pixel': 265 return AndroidNonPixelDeviceUtils(dut, log) 266 else: 267 return PixelDeviceUtils(dut, log) 268 269 270class PixelDeviceUtils(): 271 272 def __init__(self, dut, log): 273 self.dut = dut 274 self.log = log 275 self.set_screen_timeout(15) 276 277 def stop_services(self): 278 """Gracefully stop sl4a before power measurement""" 279 self.dut.stop_services() 280 281 def start_services(self): 282 self.dut.start_services() 283 284 def start_pixel_logger(self): 285 """Function to start pixel logger with default log mask. 286 287 Args: 288 ad: android device on which to start logger 289 """ 290 291 try: 292 self.dut.adb.shell( 293 'rm -R /storage/emulated/0/Android/data/com.android.pixellogger/files/logs/logs/' 294 ) 295 except: 296 pass 297 self.dut.adb.shell( 298 'am startservice -a com.android.pixellogger.service.logging.LoggingService.ACTION_START_LOGGING' 299 ) 300 301 def stop_pixel_logger(self, log_path, tag=None): 302 """Function to stop pixel logger and retrieve logs 303 304 Args: 305 ad: android device on which to start logger 306 log_path: location of saved logs 307 """ 308 self.dut.adb.shell( 309 'am startservice -a com.android.pixellogger.service.logging.LoggingService.ACTION_STOP_LOGGING' 310 ) 311 logging.info('Waiting for Pixel log file') 312 file_name = None 313 file_size = 0 314 previous_file_size = 0 315 for idx in range(600): 316 try: 317 file = self.dut.adb.shell( 318 'ls -l /storage/emulated/0/Android/data/com.android.pixellogger/files/logs/logs/' 319 ).split(' ') 320 file_name = file[-1] 321 file_size = file[-4] 322 except: 323 file_name = None 324 file_size = 0 325 if file_name and file_size == previous_file_size: 326 logging.info('Log file found after {}s.'.format(idx)) 327 break 328 else: 329 previous_file_size = file_size 330 time.sleep(1) 331 try: 332 local_file_name = '{}_{}'.format(file_name, 333 tag) if tag else file_name 334 local_path = os.path.join(log_path, local_file_name) 335 self.dut.pull_files( 336 '/storage/emulated/0/Android/data/com.android.pixellogger/files/logs/logs/{}' 337 .format(file_name), log_path) 338 return local_path 339 except: 340 logging.error('Could not pull pixel logs.') 341 342 def log_system_power_metrics(self, verbose=1): 343 # Log temperature sensors 344 if verbose: 345 temp_sensors = self.dut.adb.shell( 346 'ls -1 /dev/thermal/tz-by-name/').splitlines() 347 else: 348 temp_sensors = ['BIG', 'battery', 'quiet_therm', 'usb_pwr_therm'] 349 temp_measurements = collections.OrderedDict() 350 for sensor in temp_sensors: 351 try: 352 temp_measurements[sensor] = self.dut.adb.shell( 353 'cat /dev/thermal/tz-by-name/{}/temp'.format(sensor)) 354 except: 355 temp_measurements[sensor] = float('nan') 356 logging.debug( 357 'Temperature sensor readings: {}'.format(temp_measurements)) 358 359 # Log mitigation items 360 if verbose: 361 mitigation_points = [ 362 "batoilo", 363 "ocp_cpu1", 364 "ocp_cpu2", 365 "ocp_gpu", 366 "ocp_tpu", 367 "smpl_warn", 368 "soft_ocp_cpu1", 369 "soft_ocp_cpu2", 370 "soft_ocp_gpu", 371 "soft_ocp_tpu", 372 "vdroop1", 373 "vdroop2", 374 ] 375 else: 376 mitigation_points = [ 377 "batoilo", 378 "smpl_warn", 379 "vdroop1", 380 "vdroop2", 381 ] 382 383 parameters_f = ['count', 'capacity', 'timestamp', 'voltage'] 384 parameters_v = ['count', 'cap', 'time', 'volt'] 385 mitigation_measurements = collections.OrderedDict() 386 for mp in mitigation_points: 387 mitigation_measurements[mp] = collections.OrderedDict() 388 for par_f, par_v in zip(parameters_f, parameters_v): 389 mitigation_measurements[mp][par_v] = self.dut.adb.shell( 390 'cat /sys/devices/virtual/pmic/mitigation/last_triggered_{}/{}_{}' 391 .format(par_f, mp, par_v)) 392 logging.debug( 393 'Mitigation readings: {}'.format(mitigation_measurements)) 394 395 # Log power meter items 396 power_meter_measurements = collections.OrderedDict() 397 for device in ['device0', 'device1']: 398 power_str = self.dut.adb.shell( 399 'cat /sys/bus/iio/devices/iio:{}/lpf_power'.format( 400 device)).splitlines() 401 power_meter_measurements[device] = collections.OrderedDict() 402 for line in power_str: 403 if line.startswith('CH'): 404 try: 405 line_split = line.split(', ') 406 power_meter_measurements[device][line_split[0]] = int( 407 line_split[1]) 408 except (IndexError, ValueError): 409 continue 410 elif line.startswith('t='): 411 try: 412 power_meter_measurements[device]['t_pmeter'] = int( 413 line[2:]) 414 except (IndexError, ValueError): 415 continue 416 else: 417 continue 418 logging.debug( 419 'Power Meter readings: {}'.format(power_meter_measurements)) 420 421 # Log battery items 422 if verbose: 423 battery_parameters = [ 424 "act_impedance", "capacity", "charge_counter", 425 "charge_full", "charge_full_design", "current_avg", 426 "current_now", "cycle_count", "health", "offmode_charger", 427 "present", "rc_switch_enable", "resistance", "status", 428 "temp", "voltage_avg", "voltage_now", "voltage_ocv" 429 ] 430 else: 431 battery_parameters = [ 432 "capacity", "current_avg", "current_now", "voltage_avg", 433 "voltage_now", "voltage_ocv" 434 ] 435 436 battery_meaurements = collections.OrderedDict() 437 for par in battery_parameters: 438 battery_meaurements['bat_{}'.format(par)] = self.dut.adb.shell( 439 'cat /sys/class/power_supply/maxfg/{}'.format(par)) 440 logging.debug('Battery readings: {}'.format(battery_meaurements)) 441 442 def log_odpm(self, file_path): 443 """Dumpsys ODPM data and save it.""" 444 try: 445 stats = self.dut.adb.shell(POWER_STATS_DUMPSYS_CMD) 446 with open(file_path, 'w') as f: 447 f.write(stats) 448 except AdbError as e: 449 self.log.warning('Error dumping and saving odpm') 450 451 def send_at_command(self, at_command): 452 at_cmd_output = self.dut.adb.shell( 453 'am instrument -w -e request {} -e response wait ' 454 '"com.google.mdstest/com.google.mdstest.instrument.ModemATCommandInstrumentation"' 455 .format(at_command)) 456 return at_cmd_output 457 458 def get_rx_measurements(self, cell_type): 459 cell_type_int = 7 if cell_type == 'LTE' else 8 460 try: 461 rx_meas = self.send_at_command( 462 'AT+GOOGGETRXMEAS\={}?'.format(cell_type_int)) 463 except: 464 rx_meas = '' 465 rsrp_regex = r"RSRP\[\d+\]\s+(-?\d+)" 466 rsrp_values = [float(x) for x in re.findall(rsrp_regex, rx_meas)] 467 rsrq_regex = r"RSRQ\[\d+\]\s+(-?\d+)" 468 rsrq_values = [float(x) for x in re.findall(rsrq_regex, rx_meas)] 469 rssi_regex = r"RSSI\[\d+\]\s+(-?\d+)" 470 rssi_values = [float(x) for x in re.findall(rssi_regex, rx_meas)] 471 sinr_regex = r"SINR\[\d+\]\s+(-?\d+)" 472 sinr_values = [float(x) for x in re.findall(sinr_regex, rx_meas)] 473 return { 474 'rsrp': rsrp_values, 475 'rsrq': rsrq_values, 476 'rssi': rssi_values, 477 'sinr': sinr_values 478 } 479 480 def get_fr2_tx_power(self): 481 try: 482 tx_power = self.send_at_command('AT+MMPDREAD=0,2,0') 483 except: 484 tx_power = '' 485 logging.info(tx_power) 486 487 def toggle_airplane_mode(self, 488 new_state=None, 489 strict_checking=True, 490 try_index=0): 491 """ Toggle the state of airplane mode. 492 493 Args: 494 log: log handler. 495 ad: android_device object. 496 new_state: Airplane mode state to set to. 497 If None, opposite of the current state. 498 strict_checking: Whether to turn on strict checking that checks all features. 499 try_index: index of apm toggle 500 501 Returns: 502 result: True if operation succeed. False if error happens. 503 """ 504 if hasattr( 505 self.dut, 'toggle_airplane_mode' 506 ) and 'at_command' in self.dut.toggle_airplane_mode['method']: 507 cfun_setting = 0 if new_state else 1 508 self.log.info( 509 'Toggling airplane mode {} by AT command.'.format(new_state)) 510 self.send_at_command('AT+CFUN={}'.format(cfun_setting)) 511 elif self.dut.skip_sl4a or try_index % 2 == 0: 512 self.log.info( 513 'Toggling airplane mode {} by adb.'.format(new_state)) 514 return tel_utils.toggle_airplane_mode_by_adb( 515 self.log, self.dut, new_state) 516 else: 517 self.log.info( 518 'Toggling airplane mode {} by msim.'.format(new_state)) 519 return self.toggle_airplane_mode_msim( 520 new_state, strict_checking=strict_checking) 521 522 def toggle_airplane_mode_msim(self, new_state=None, strict_checking=True): 523 """ Toggle the state of airplane mode. 524 525 Args: 526 log: log handler. 527 ad: android_device object. 528 new_state: Airplane mode state to set to. 529 If None, opposite of the current state. 530 strict_checking: Whether to turn on strict checking that checks all features. 531 532 Returns: 533 result: True if operation succeed. False if error happens. 534 """ 535 536 cur_state = self.dut.droid.connectivityCheckAirplaneMode() 537 if cur_state == new_state: 538 self.dut.log.info("Airplane mode already in %s", new_state) 539 return True 540 elif new_state is None: 541 new_state = not cur_state 542 self.dut.log.info("Toggle APM mode, from current tate %s to %s", 543 cur_state, new_state) 544 sub_id_list = [] 545 active_sub_info = self.dut.droid.subscriptionGetAllSubInfoList() 546 if active_sub_info: 547 for info in active_sub_info: 548 sub_id_list.append(info['subscriptionId']) 549 550 self.dut.ed.clear_all_events() 551 time.sleep(0.1) 552 service_state_list = [] 553 if new_state: 554 service_state_list.append(tel_utils.SERVICE_STATE_POWER_OFF) 555 self.dut.log.info("Turn on airplane mode") 556 557 else: 558 # If either one of these 3 events show up, it should be OK. 559 # Normal SIM, phone in service 560 service_state_list.append(tel_utils.SERVICE_STATE_IN_SERVICE) 561 # NO SIM, or Dead SIM, or no Roaming coverage. 562 service_state_list.append(tel_utils.SERVICE_STATE_OUT_OF_SERVICE) 563 service_state_list.append(tel_utils.SERVICE_STATE_EMERGENCY_ONLY) 564 self.dut.log.info("Turn off airplane mode") 565 566 for sub_id in sub_id_list: 567 self.dut.droid.telephonyStartTrackingServiceStateChangeForSubscription( 568 sub_id) 569 570 timeout_time = time.time() + LONG_SLEEP 571 self.dut.droid.connectivityToggleAirplaneMode(new_state) 572 573 try: 574 try: 575 event = self.dut.ed.wait_for_event( 576 tel_utils.EVENT_SERVICE_STATE_CHANGED, 577 tel_utils.is_event_match_for_list, 578 timeout=LONG_SLEEP, 579 field=tel_utils.ServiceStateContainer.SERVICE_STATE, 580 value_list=service_state_list) 581 self.dut.log.info("Got event %s", event) 582 except Empty: 583 self.dut.log.warning( 584 "Did not get expected service state change to %s", 585 service_state_list) 586 finally: 587 for sub_id in sub_id_list: 588 self.dut.droid.telephonyStopTrackingServiceStateChangeForSubscription( 589 sub_id) 590 except Exception as e: 591 self.dut.log.error(e) 592 593 # APM on (new_state=True) will turn off bluetooth but may not turn it on 594 try: 595 if new_state and not tel_utils._wait_for_bluetooth_in_state( 596 self.log, self.dut, False, timeout_time - time.time()): 597 self.dut.log.error( 598 "Failed waiting for bluetooth during airplane mode toggle") 599 if strict_checking: return False 600 except Exception as e: 601 self.dut.log.error("Failed to check bluetooth state due to %s", e) 602 if strict_checking: 603 raise 604 605 # APM on (new_state=True) will turn off wifi but may not turn it on 606 if new_state and not tel_utils._wait_for_wifi_in_state( 607 self.log, self.dut, False, timeout_time - time.time()): 608 self.dut.log.error( 609 "Failed waiting for wifi during airplane mode toggle on") 610 if strict_checking: return False 611 612 if self.dut.droid.connectivityCheckAirplaneMode() != new_state: 613 self.dut.log.error("Set airplane mode to %s failed", new_state) 614 return False 615 return True 616 617 def set_screen_timeout(self, timeout=5): 618 self.dut.adb.shell('settings put system screen_off_timeout {}'.format( 619 timeout * 1000)) 620 def get_screen_state(self): 621 screen_state_output = self.dut.adb.shell( 622 "dumpsys display | grep 'mScreenState'") 623 if 'ON' in screen_state_output: 624 return 1 625 else: 626 return 0 627 628 def set_screen_state(self, state): 629 curr_state = self.get_screen_state() 630 if state == curr_state: 631 self.log.debug('Screen state already {}'.format(state)) 632 elif state == True: 633 self.dut.adb.shell('input keyevent KEYCODE_WAKEUP') 634 elif state == False: 635 self.dut.adb.shell('input keyevent KEYCODE_SLEEP') 636 637 def go_to_sleep(self): 638 if self.dut.skip_sl4a: 639 self.set_screen_state(0) 640 else: 641 self.dut.droid.goToSleepNow() 642 643class AndroidNonPixelDeviceUtils(): 644 645 def __init__(self, dut, log): 646 self.dut = dut 647 self.log = log 648 self.set_screen_timeout() 649 if getattr(dut, "stop_logcat", 0): 650 self.log.info('Stopping ADB logcat.') 651 dut.stop_adb_logcat() 652 653 def start_services(self): 654 self.log.debug('stop_services not supported on non_pixel devices') 655 656 def stop_services(self): 657 self.log.debug('stop_services not supported on non_pixel devices') 658 659 def start_pixel_logger(self): 660 self.log.debug('start_pixel_logger not supported on non_pixel devices') 661 662 def stop_pixel_logger(self, log_path, tag=None): 663 self.log.debug('stop_pixel_logger not supported on non_pixel devices') 664 665 def log_system_power_metrics(self, verbose=1): 666 self.log.debug( 667 'log_system_power_metrics not supported on non_pixel devices') 668 669 def log_odpm(self, file_path): 670 self.log.debug('log_odpm not supported on non_pixel devices') 671 672 def send_at_command(self, at_command): 673 self.log.debug('send_at_command not supported on non_pixel devices') 674 675 def get_rx_measurements(self, cell_type): 676 self.log.debug( 677 'get_rx_measurements not supported on non_pixel devices') 678 679 def get_tx_measurements(self, cell_type): 680 self.log.debug( 681 'get_tx_measurements not supported on non_pixel devices') 682 683 def toggle_airplane_mode(self, 684 new_state=None, 685 strict_checking=True, 686 try_index=0): 687 cur_state = bool( 688 int(self.dut.adb.shell("settings get global airplane_mode_on"))) 689 if new_state == cur_state: 690 self.log.info( 691 'Airplane mode already in {} state.'.format(cur_state)) 692 else: 693 self.tap_airplane_mode() 694 695 def get_screen_state(self): 696 screen_state_output = self.dut.adb.shell( 697 "dumpsys display | grep 'mScreenState'") 698 if 'ON' in screen_state_output: 699 return 1 700 else: 701 return 0 702 703 def set_screen_state(self, state): 704 curr_state = self.get_screen_state() 705 if state == curr_state: 706 self.log.debug('Screen state already {}'.format(state)) 707 elif state == True: 708 self.dut.adb.shell('input keyevent KEYCODE_WAKEUP') 709 elif state == False: 710 self.dut.adb.shell('input keyevent KEYCODE_SLEEP') 711 712 def go_to_sleep(self): 713 self.set_screen_state(0) 714 715 def set_screen_timeout(self, timeout=5): 716 self.dut.adb.shell('settings put system screen_off_timeout {}'.format( 717 timeout * 1000)) 718 719 def tap_airplane_mode(self): 720 self.set_screen_state(1) 721 for command in self.dut.toggle_airplane_mode['screen_routine']: 722 self.dut.adb.shell(command) 723 time.sleep(SHORT_SLEEP) 724 self.set_screen_state(0) 725