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