1#!/usr/bin/env python3 2# 3# Copyright 2020 - Google 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 time 18import re 19import os 20import math 21import shutil 22import fnmatch 23import posixpath 24import tempfile 25from collections import namedtuple 26 27from acts import utils 28from acts import signals 29from acts.libs.proc import job 30from acts.controllers.android_device import list_adb_devices 31from acts.controllers.android_device import list_fastboot_devices 32from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH 33from acts.controllers.android_device import SL4A_APK_NAME 34from acts.test_utils.wifi import wifi_test_utils as wutils 35from acts.test_utils.tel import tel_test_utils as tutils 36from acts.utils import get_current_epoch_time 37from acts.utils import epoch_to_human_time 38 39WifiEnums = wutils.WifiEnums 40PULL_TIMEOUT = 300 41GNSSSTATUS_LOG_PATH = ( 42 "/storage/emulated/0/Android/data/com.android.gpstool/files/") 43QXDM_MASKS = ["GPS.cfg", "GPS-general.cfg", "default.cfg"] 44TTFF_REPORT = namedtuple( 45 "TTFF_REPORT", "utc_time ttff_loop ttff_sec ttff_pe ttff_ant_cn " 46 "ttff_base_cn") 47TRACK_REPORT = namedtuple( 48 "TRACK_REPORT", "l5flag pe ant_top4cn ant_cn base_top4cn base_cn") 49LOCAL_PROP_FILE_CONTENTS = """\ 50log.tag.LocationManagerService=VERBOSE 51log.tag.GnssLocationProvider=VERBOSE 52log.tag.GnssMeasurementsProvider=VERBOSE 53log.tag.GpsNetInitiatedHandler=VERBOSE 54log.tag.GnssNetworkConnectivityHandler=VERBOSE 55log.tag.ConnectivityService=VERBOSE 56log.tag.ConnectivityManager=VERBOSE 57log.tag.GnssVisibilityControl=VERBOSE 58log.tag.NtpTimeHelper=VERBOSE 59log.tag.NtpTrustedTime=VERBOSE""" 60TEST_PACKAGE_NAME = "com.google.android.apps.maps" 61LOCATION_PERMISSIONS = [ 62 "android.permission.ACCESS_FINE_LOCATION", 63 "android.permission.ACCESS_COARSE_LOCATION" 64] 65GNSSTOOL_PACKAGE_NAME = "com.android.gpstool" 66GNSSTOOL_PERMISSIONS = [ 67 "android.permission.ACCESS_FINE_LOCATION", 68 "android.permission.READ_EXTERNAL_STORAGE", 69 "android.permission.ACCESS_COARSE_LOCATION", 70 "android.permission.CALL_PHONE", 71 "android.permission.WRITE_CONTACTS", 72 "android.permission.CAMERA", 73 "android.permission.WRITE_EXTERNAL_STORAGE", 74 "android.permission.READ_CONTACTS", 75 "android.permission.ACCESS_BACKGROUND_LOCATION" 76] 77 78 79class GnssTestUtilsError(Exception): 80 pass 81 82 83def remount_device(ad): 84 """Remount device file system to read and write. 85 86 Args: 87 ad: An AndroidDevice object. 88 """ 89 for retries in range(5): 90 ad.root_adb() 91 if ad.adb.getprop("ro.boot.veritymode") == "enforcing": 92 disable_verity_result = ad.adb.disable_verity() 93 reboot(ad) 94 remount_result = ad.adb.remount() 95 ad.log.info("Attempt %d - %s" % (retries + 1, remount_result)) 96 if "remount succeeded" in remount_result: 97 break 98 99 100def reboot(ad): 101 """Reboot device and check if mobile data is available. 102 103 Args: 104 ad: An AndroidDevice object. 105 """ 106 ad.log.info("Reboot device to make changes take effect.") 107 ad.reboot() 108 ad.unlock_screen(password=None) 109 if not int(ad.adb.shell("settings get global mobile_data")) == 1: 110 set_mobile_data(ad, True) 111 utils.sync_device_time(ad) 112 113 114def enable_gnss_verbose_logging(ad): 115 """Enable GNSS VERBOSE Logging and persistent logcat. 116 117 Args: 118 ad: An AndroidDevice object. 119 """ 120 remount_device(ad) 121 ad.log.info("Enable GNSS VERBOSE Logging and persistent logcat.") 122 ad.adb.shell("echo -e '\nDEBUG_LEVEL = 5' >> /vendor/etc/gps.conf") 123 ad.adb.shell("echo %r >> /data/local.prop" % LOCAL_PROP_FILE_CONTENTS) 124 ad.adb.shell("chmod 644 /data/local.prop") 125 ad.adb.shell("setprop persist.logd.logpersistd.size 20000") 126 ad.adb.shell("setprop persist.logd.size 16777216") 127 ad.adb.shell("setprop persist.vendor.radio.adb_log_on 1") 128 ad.adb.shell("setprop persist.logd.logpersistd logcatd") 129 ad.adb.shell("setprop log.tag.copresGcore VERBOSE") 130 ad.adb.shell("sync") 131 132 133def get_am_flags(value): 134 """Returns the (value, type) flags for a given python value.""" 135 if type(value) is bool: 136 return str(value).lower(), 'boolean' 137 elif type(value) is str: 138 return value, 'string' 139 raise ValueError("%s should be either 'boolean' or 'string'" % value) 140 141 142def enable_compact_and_particle_fusion_log(ad): 143 """Enable CompactLog, FLP particle fusion log and disable gms 144 location-based quake monitoring. 145 146 Args: 147 ad: An AndroidDevice object. 148 """ 149 ad.root_adb() 150 ad.log.info("Enable FLP flags and Disable GMS location-based quake " 151 "monitoring.") 152 overrides = { 153 'compact_log_enabled': True, 154 'flp_use_particle_fusion': True, 155 'flp_particle_fusion_extended_bug_report': True, 156 'flp_event_log_size': '86400', 157 'proks_config': '28', 158 'flp_particle_fusion_bug_report_window_sec': '86400', 159 'flp_particle_fusion_bug_report_max_buffer_size': '86400', 160 'seismic_data_collection': False, 161 'Ealert__enable': False, 162 } 163 for flag, python_value in overrides.items(): 164 value, type = get_am_flags(python_value) 165 cmd = ("am broadcast -a com.google.android.gms.phenotype.FLAG_OVERRIDE " 166 "--es package com.google.android.location --es user \* " 167 "--esa flags %s --esa values %s --esa types %s " 168 "com.google.android.gms" % (flag, value, type)) 169 ad.adb.shell(cmd) 170 ad.adb.shell("am force-stop com.google.android.gms") 171 ad.adb.shell("am broadcast -a com.google.android.gms.INITIALIZE") 172 173 174def disable_xtra_throttle(ad): 175 """Disable XTRA throttle will have no limit to download XTRA data. 176 177 Args: 178 ad: An AndroidDevice object. 179 """ 180 remount_device(ad) 181 ad.log.info("Disable XTRA Throttle.") 182 ad.adb.shell("echo -e '\nXTRA_TEST_ENABLED=1' >> /vendor/etc/gps.conf") 183 ad.adb.shell("echo -e '\nXTRA_THROTTLE_ENABLED=0' >> /vendor/etc/gps.conf") 184 185 186def enable_supl_mode(ad): 187 """Enable SUPL back on for next test item. 188 189 Args: 190 ad: An AndroidDevice object. 191 """ 192 remount_device(ad) 193 ad.log.info("Enable SUPL mode.") 194 ad.adb.shell("echo -e '\nSUPL_MODE=1' >> /etc/gps_debug.conf") 195 196 197def disable_supl_mode(ad): 198 """Kill SUPL to test XTRA only test item. 199 200 Args: 201 ad: An AndroidDevice object. 202 """ 203 remount_device(ad) 204 ad.log.info("Disable SUPL mode.") 205 ad.adb.shell("echo -e '\nSUPL_MODE=0' >> /etc/gps_debug.conf") 206 reboot(ad) 207 208 209def kill_xtra_daemon(ad): 210 """Kill XTRA daemon to test SUPL only test item. 211 212 Args: 213 ad: An AndroidDevice object. 214 """ 215 ad.root_adb() 216 ad.log.info("Disable XTRA-daemon until next reboot.") 217 ad.adb.shell("killall xtra-daemon") 218 219 220def disable_private_dns_mode(ad): 221 """Due to b/118365122, it's better to disable private DNS mode while 222 testing. 8.8.8.8 private dns sever is unstable now, sometimes server 223 will not response dns query suddenly. 224 225 Args: 226 ad: An AndroidDevice object. 227 """ 228 tutils.get_operator_name(ad.log, ad, subId=None) 229 if ad.adb.shell("settings get global private_dns_mode") != "off": 230 ad.log.info("Disable Private DNS mode.") 231 ad.adb.shell("settings put global private_dns_mode off") 232 233 234def _init_device(ad): 235 """Init GNSS test devices. 236 237 Args: 238 ad: An AndroidDevice object. 239 """ 240 enable_gnss_verbose_logging(ad) 241 enable_compact_and_particle_fusion_log(ad) 242 disable_xtra_throttle(ad) 243 enable_supl_mode(ad) 244 ad.adb.shell("settings put system screen_off_timeout 1800000") 245 wutils.wifi_toggle_state(ad, False) 246 ad.log.info("Setting Bluetooth state to False") 247 ad.droid.bluetoothToggleState(False) 248 set_gnss_qxdm_mask(ad, QXDM_MASKS) 249 check_location_service(ad) 250 set_wifi_and_bt_scanning(ad, True) 251 disable_private_dns_mode(ad) 252 reboot(ad) 253 init_gtw_gpstool(ad) 254 255 256def connect_to_wifi_network(ad, network): 257 """Connection logic for open and psk wifi networks. 258 259 Args: 260 ad: An AndroidDevice object. 261 network: Dictionary with network info. 262 """ 263 SSID = network[WifiEnums.SSID_KEY] 264 ad.ed.clear_all_events() 265 wutils.reset_wifi(ad) 266 wutils.start_wifi_connection_scan_and_ensure_network_found(ad, SSID) 267 wutils.wifi_connect(ad, network, num_of_tries=5) 268 269 270def set_wifi_and_bt_scanning(ad, state=True): 271 """Set Wi-Fi and Bluetooth scanning on/off in Settings -> Location 272 273 Args: 274 ad: An AndroidDevice object. 275 state: True to turn on "Wi-Fi and Bluetooth scanning". 276 False to turn off "Wi-Fi and Bluetooth scanning". 277 """ 278 ad.root_adb() 279 if state: 280 ad.adb.shell("settings put global wifi_scan_always_enabled 1") 281 ad.adb.shell("settings put global ble_scan_always_enabled 1") 282 ad.log.info("Wi-Fi and Bluetooth scanning are enabled") 283 else: 284 ad.adb.shell("settings put global wifi_scan_always_enabled 0") 285 ad.adb.shell("settings put global ble_scan_always_enabled 0") 286 ad.log.info("Wi-Fi and Bluetooth scanning are disabled") 287 288 289def check_location_service(ad): 290 """Set location service on. 291 Verify if location service is available. 292 293 Args: 294 ad: An AndroidDevice object. 295 """ 296 remount_device(ad) 297 utils.set_location_service(ad, True) 298 location_mode = int(ad.adb.shell("settings get secure location_mode")) 299 ad.log.info("Current Location Mode >> %d" % location_mode) 300 if location_mode != 3: 301 raise signals.TestError("Failed to turn Location on") 302 303 304def clear_logd_gnss_qxdm_log(ad): 305 """Clear /data/misc/logd, 306 /storage/emulated/0/Android/data/com.android.gpstool/files and 307 /data/vendor/radio/diag_logs/logs from previous test item then reboot. 308 309 Args: 310 ad: An AndroidDevice object. 311 """ 312 remount_device(ad) 313 ad.log.info("Clear Logd, GNSS and QXDM Log from previous test item.") 314 ad.adb.shell("rm -rf /data/misc/logd", ignore_status=True) 315 ad.adb.shell('find %s -name "*.txt" -type f -delete' % GNSSSTATUS_LOG_PATH) 316 output_path = posixpath.join(DEFAULT_QXDM_LOG_PATH, "logs") 317 ad.adb.shell("rm -rf %s" % output_path, ignore_status=True) 318 reboot(ad) 319 320 321def get_gnss_qxdm_log(ad, qdb_path): 322 """Get /storage/emulated/0/Android/data/com.android.gpstool/files and 323 /data/vendor/radio/diag_logs/logs for test item. 324 325 Args: 326 ad: An AndroidDevice object. 327 qdb_path: The path of qdsp6m.qdb on different projects. 328 """ 329 log_path = ad.device_log_path 330 os.makedirs(log_path, exist_ok=True) 331 gnss_log_name = "gnssstatus_log_%s_%s" % (ad.model, ad.serial) 332 gnss_log_path = posixpath.join(log_path, gnss_log_name) 333 os.makedirs(gnss_log_path, exist_ok=True) 334 ad.log.info("Pull GnssStatus Log to %s" % gnss_log_path) 335 ad.adb.pull("%s %s" % (GNSSSTATUS_LOG_PATH+".", gnss_log_path), 336 timeout=PULL_TIMEOUT, ignore_status=True) 337 shutil.make_archive(gnss_log_path, "zip", gnss_log_path) 338 shutil.rmtree(gnss_log_path) 339 output_path = posixpath.join(DEFAULT_QXDM_LOG_PATH, "logs/.") 340 file_count = ad.adb.shell( 341 "find %s -type f -iname *.qmdl | wc -l" % output_path) 342 if not int(file_count) == 0: 343 qxdm_log_name = "QXDM_%s_%s" % (ad.model, ad.serial) 344 qxdm_log_path = posixpath.join(log_path, qxdm_log_name) 345 os.makedirs(qxdm_log_path, exist_ok=True) 346 ad.log.info("Pull QXDM Log %s to %s" % (output_path, qxdm_log_path)) 347 ad.adb.pull("%s %s" % (output_path, qxdm_log_path), 348 timeout=PULL_TIMEOUT, ignore_status=True) 349 for path in qdb_path: 350 output = ad.adb.pull("%s %s" % (path, qxdm_log_path), 351 timeout=PULL_TIMEOUT, ignore_status=True) 352 if "No such file or directory" in output: 353 continue 354 break 355 shutil.make_archive(qxdm_log_path, "zip", qxdm_log_path) 356 shutil.rmtree(qxdm_log_path) 357 else: 358 ad.log.error("QXDM file count is %d. There is no QXDM log on device." 359 % int(file_count)) 360 361 362def set_mobile_data(ad, state): 363 """Set mobile data on or off and check mobile data state. 364 365 Args: 366 ad: An AndroidDevice object. 367 state: True to enable mobile data. False to disable mobile data. 368 """ 369 ad.root_adb() 370 if state: 371 ad.log.info("Enable mobile data.") 372 ad.adb.shell("svc data enable") 373 else: 374 ad.log.info("Disable mobile data.") 375 ad.adb.shell("svc data disable") 376 time.sleep(5) 377 out = int(ad.adb.shell("settings get global mobile_data")) 378 if state and out == 1: 379 ad.log.info("Mobile data is enabled and set to %d" % out) 380 elif not state and out == 0: 381 ad.log.info("Mobile data is disabled and set to %d" % out) 382 else: 383 ad.log.error("Mobile data is at unknown state and set to %d" % out) 384 385 386def gnss_trigger_modem_ssr_by_adb(ad, dwelltime=60): 387 """Trigger modem SSR crash by adb and verify if modem crash and recover 388 successfully. 389 390 Args: 391 ad: An AndroidDevice object. 392 dwelltime: Waiting time for modem reset. Default is 60 seconds. 393 394 Returns: 395 True if success. 396 False if failed. 397 """ 398 begin_time = get_current_epoch_time() 399 ad.root_adb() 400 cmds = ("echo restart > /sys/kernel/debug/msm_subsys/modem", 401 r"echo 'at+cfun=1,1\r' > /dev/at_mdm0") 402 for cmd in cmds: 403 ad.log.info("Triggering modem SSR crash by %s" % cmd) 404 output = ad.adb.shell(cmd, ignore_status=True) 405 if "No such file or directory" in output: 406 continue 407 break 408 time.sleep(dwelltime) 409 ad.send_keycode("HOME") 410 logcat_results = ad.search_logcat("SSRObserver", begin_time) 411 if logcat_results: 412 for ssr in logcat_results: 413 if "mSubsystem='modem', mCrashReason" in ssr["log_message"]: 414 ad.log.debug(ssr["log_message"]) 415 ad.log.info("Triggering modem SSR crash successfully.") 416 return True 417 raise signals.TestError("Failed to trigger modem SSR crash") 418 raise signals.TestError("No SSRObserver found in logcat") 419 420 421def gnss_trigger_modem_ssr_by_mds(ad, dwelltime=60): 422 """Trigger modem SSR crash by mds tool and verify if modem crash and recover 423 successfully. 424 425 Args: 426 ad: An AndroidDevice object. 427 dwelltime: Waiting time for modem reset. Default is 60 seconds. 428 """ 429 mds_check = ad.adb.shell("pm path com.google.mdstest") 430 if not mds_check: 431 raise signals.TestError("MDS Tool is not properly installed.") 432 ad.root_adb() 433 cmd = ('am instrument -w -e request "4b 25 03 00" ' 434 '"com.google.mdstest/com.google.mdstest.instrument' 435 '.ModemCommandInstrumentation"') 436 ad.log.info("Triggering modem SSR crash by MDS") 437 output = ad.adb.shell(cmd, ignore_status=True) 438 ad.log.debug(output) 439 time.sleep(dwelltime) 440 ad.send_keycode("HOME") 441 if "SUCCESS" in output: 442 ad.log.info("Triggering modem SSR crash by MDS successfully.") 443 else: 444 raise signals.TestError( 445 "Failed to trigger modem SSR crash by MDS. \n%s" % output) 446 447 448def check_xtra_download(ad, begin_time): 449 """Verify XTRA download success log message in logcat. 450 451 Args: 452 ad: An AndroidDevice object. 453 begin_time: test begin time 454 455 Returns: 456 True: xtra_download if XTRA downloaded and injected successfully 457 otherwise return False. 458 """ 459 ad.send_keycode("HOME") 460 logcat_results = ad.search_logcat("XTRA download success. " 461 "inject data into modem", begin_time) 462 if logcat_results: 463 ad.log.debug("%s" % logcat_results[-1]["log_message"]) 464 ad.log.info("XTRA downloaded and injected successfully.") 465 return True 466 ad.log.error("XTRA downloaded FAIL.") 467 return False 468 469 470def pull_package_apk(ad, package_name): 471 """Pull apk of given package_name from device. 472 473 Args: 474 ad: An AndroidDevice object. 475 package_name: Package name of apk to pull. 476 477 Returns: 478 The temp path of pulled apk. 479 """ 480 out = ad.adb.shell("pm path %s" % package_name) 481 result = re.search(r"package:(.*)", out) 482 if not result: 483 tutils.abort_all_tests(ad.log, "Couldn't find apk of %s" % package_name) 484 else: 485 apk_source = result.group(1) 486 ad.log.info("Get apk of %s from %s" % (package_name, apk_source)) 487 apk_path = tempfile.mkdtemp() 488 ad.pull_files([apk_source], apk_path) 489 return apk_path 490 491 492def reinstall_package_apk(ad, package_name, apk_path): 493 """Reinstall apk of given package_name. 494 495 Args: 496 ad: An AndroidDevice object. 497 package_name: Package name of apk. 498 apk_path: The temp path of pulled apk. 499 """ 500 for path_key in os.listdir(apk_path): 501 if fnmatch.fnmatch(path_key, "*.apk"): 502 apk_path = os.path.join(apk_path, path_key) 503 break 504 else: 505 raise signals.TestError("No apk is found in %s" % apk_path) 506 ad.log.info("Re-install %s with path: %s" % (package_name, apk_path)) 507 ad.adb.shell("settings put global verifier_verify_adb_installs 0") 508 ad.adb.install("-r -d -g --user 0 %s" % apk_path) 509 package_check = ad.adb.shell("pm path %s" % package_name) 510 if not package_check: 511 tutils.abort_all_tests( 512 ad.log, "%s is not properly re-installed." % package_name) 513 ad.log.info("%s is re-installed successfully." % package_name) 514 515 516def init_gtw_gpstool(ad): 517 """Init GTW_GPSTool apk. 518 519 Args: 520 ad: An AndroidDevice object. 521 """ 522 remount_device(ad) 523 gpstool_path = pull_package_apk(ad, "com.android.gpstool") 524 reinstall_package_apk(ad, "com.android.gpstool", gpstool_path) 525 526 527def fastboot_factory_reset(ad): 528 """Factory reset the device in fastboot mode. 529 Pull sl4a apk from device. Terminate all sl4a sessions, 530 Reboot the device to bootloader, 531 factory reset the device by fastboot. 532 Reboot the device. wait for device to complete booting 533 Re-install and start an sl4a session. 534 535 Args: 536 ad: An AndroidDevice object. 537 538 Returns: 539 True if factory reset process complete. 540 """ 541 status = True 542 skip_setup_wizard = True 543 sl4a_path = pull_package_apk(ad, SL4A_APK_NAME) 544 gpstool_path = pull_package_apk(ad, "com.android.gpstool") 545 mds_path = pull_package_apk(ad, "com.google.mdstest") 546 tutils.stop_qxdm_logger(ad) 547 ad.stop_services() 548 attempts = 3 549 for i in range(1, attempts + 1): 550 try: 551 if ad.serial in list_adb_devices(): 552 ad.log.info("Reboot to bootloader") 553 ad.adb.reboot("bootloader", ignore_status=True) 554 time.sleep(10) 555 if ad.serial in list_fastboot_devices(): 556 ad.log.info("Factory reset in fastboot") 557 ad.fastboot._w(timeout=300, ignore_status=True) 558 time.sleep(30) 559 ad.log.info("Reboot in fastboot") 560 ad.fastboot.reboot() 561 ad.wait_for_boot_completion() 562 ad.root_adb() 563 if ad.skip_sl4a: 564 break 565 if ad.is_sl4a_installed(): 566 break 567 reinstall_package_apk(ad, SL4A_APK_NAME, sl4a_path) 568 reinstall_package_apk(ad, "com.android.gpstool", gpstool_path) 569 reinstall_package_apk(ad, "com.google.mdstest", mds_path) 570 time.sleep(10) 571 break 572 except Exception as e: 573 ad.log.error(e) 574 if i == attempts: 575 tutils.abort_all_tests(ad.log, str(e)) 576 time.sleep(5) 577 try: 578 ad.start_adb_logcat() 579 except Exception as e: 580 ad.log.error(e) 581 if skip_setup_wizard: 582 ad.exit_setup_wizard() 583 if ad.skip_sl4a: 584 return status 585 tutils.bring_up_sl4a(ad) 586 return status 587 588 589def clear_aiding_data_by_gtw_gpstool(ad): 590 """Launch GTW GPSTool and Clear all GNSS aiding data. 591 Wait 5 seconds for GTW GPStool to clear all GNSS aiding 592 data properly. 593 594 Args: 595 ad: An AndroidDevice object. 596 """ 597 ad.log.info("Launch GTW GPSTool and Clear all GNSS aiding data") 598 ad.adb.shell("am start -S -n com.android.gpstool/.GPSTool --es mode clear") 599 time.sleep(10) 600 601 602def start_gnss_by_gtw_gpstool(ad, state, type="gnss", bgdisplay=False): 603 """Start or stop GNSS on GTW_GPSTool. 604 605 Args: 606 ad: An AndroidDevice object. 607 state: True to start GNSS. False to Stop GNSS. 608 type: Different API for location fix. Use gnss/flp/nmea 609 bgdisplay: true to run GTW when Display off. 610 false to not run GTW when Display off. 611 """ 612 if state and not bgdisplay: 613 ad.adb.shell("am start -S -n com.android.gpstool/.GPSTool " 614 "--es mode gps --es type %s" % type) 615 elif state and bgdisplay: 616 ad.adb.shell("am start -S -n com.android.gpstool/.GPSTool --es mode " 617 "gps --es type {} --ez BG {}".format(type, bgdisplay)) 618 if not state: 619 ad.log.info("Stop %s on GTW_GPSTool." % type) 620 ad.adb.shell("am broadcast -a com.android.gpstool.stop_gps_action") 621 time.sleep(3) 622 623 624def process_gnss_by_gtw_gpstool(ad, criteria, type="gnss", clear_data=True): 625 """Launch GTW GPSTool and Clear all GNSS aiding data 626 Start GNSS tracking on GTW_GPSTool. 627 628 Args: 629 ad: An AndroidDevice object. 630 criteria: Criteria for current test item. 631 type: Different API for location fix. Use gnss/flp/nmea 632 clear_data: True to clear GNSS aiding data. False is not to. Defalt 633 set to True. 634 635 Returns: 636 True: First fix TTFF are within criteria. 637 False: First fix TTFF exceed criteria. 638 """ 639 retries = 3 640 for i in range(retries): 641 if not ad.is_adb_logcat_on: 642 ad.start_adb_logcat() 643 check_adblog_functionality(ad) 644 check_location_runtime_permissions( 645 ad, GNSSTOOL_PACKAGE_NAME, GNSSTOOL_PERMISSIONS) 646 begin_time = get_current_epoch_time() 647 if clear_data: 648 clear_aiding_data_by_gtw_gpstool(ad) 649 ad.log.info("Start %s on GTW_GPSTool - attempt %d" % (type.upper(), 650 i+1)) 651 start_gnss_by_gtw_gpstool(ad, True, type) 652 for _ in range(10 + criteria): 653 logcat_results = ad.search_logcat("First fixed", begin_time) 654 if logcat_results: 655 ad.log.debug(logcat_results[-1]["log_message"]) 656 first_fixed = int(logcat_results[-1]["log_message"].split()[-1]) 657 ad.log.info("%s First fixed = %.3f seconds" % 658 (type.upper(), first_fixed/1000)) 659 if (first_fixed/1000) <= criteria: 660 return True 661 start_gnss_by_gtw_gpstool(ad, False, type) 662 raise signals.TestFailure("Fail to get %s location fixed " 663 "within %d seconds criteria." 664 % (type.upper(), criteria)) 665 time.sleep(1) 666 check_currrent_focus_app(ad) 667 start_gnss_by_gtw_gpstool(ad, False, type) 668 raise signals.TestFailure("Fail to get %s location fixed within %d " 669 "attempts." % (type.upper(), retries)) 670 671def start_ttff_by_gtw_gpstool(ad, ttff_mode, iteration, aid_data=False): 672 """Identify which TTFF mode for different test items. 673 674 Args: 675 ad: An AndroidDevice object. 676 ttff_mode: TTFF Test mode for current test item. 677 iteration: Iteration of TTFF cycles. 678 aid_data: Boolean for identify aid_data existed or not 679 """ 680 begin_time = get_current_epoch_time() 681 if (ttff_mode == "hs" or ttff_mode == "ws") and not aid_data: 682 ad.log.info("Wait 5 minutes to start TTFF %s..." % ttff_mode.upper()) 683 time.sleep(300) 684 if ttff_mode == "cs": 685 ad.log.info("Start TTFF Cold Start...") 686 time.sleep(3) 687 for i in range(1, 4): 688 ad.adb.shell("am broadcast -a com.android.gpstool.ttff_action " 689 "--es ttff %s --es cycle %d" % (ttff_mode, iteration)) 690 time.sleep(1) 691 if ad.search_logcat("act=com.android.gpstool.start_test_action", 692 begin_time): 693 ad.log.info("Send TTFF start_test_action successfully.") 694 break 695 else: 696 check_currrent_focus_app(ad) 697 raise signals.TestError("Fail to send TTFF start_test_action.") 698 699 700def gnss_tracking_via_gtw_gpstool(ad, criteria, type="gnss", testtime=60): 701 """Start GNSS/FLP tracking tests for input testtime on GTW_GPSTool. 702 703 Args: 704 ad: An AndroidDevice object. 705 criteria: Criteria for current TTFF. 706 type: Different API for location fix. Use gnss/flp/nmea 707 testtime: Tracking test time for minutes. Default set to 60 minutes. 708 """ 709 process_gnss_by_gtw_gpstool(ad, criteria, type) 710 ad.log.info("Start %s tracking test for %d minutes" % (type.upper(), 711 testtime)) 712 begin_time = get_current_epoch_time() 713 while get_current_epoch_time() - begin_time < testtime * 60 * 1000 : 714 if not ad.is_adb_logcat_on: 715 ad.start_adb_logcat() 716 crash_result = ad.search_logcat("Force finishing activity " 717 "com.android.gpstool/.GPSTool", 718 begin_time) 719 if crash_result: 720 raise signals.TestError("GPSTool crashed. Abort test.") 721 ad.log.info("Successfully tested for %d minutes" % testtime) 722 start_gnss_by_gtw_gpstool(ad, False, type) 723 724 725def parse_gtw_gpstool_log(ad, true_position, type="gnss"): 726 """Process GNSS/FLP API logs from GTW GPSTool and output track_data to 727 test_run_info for ACTS plugin to parse and display on MobileHarness as 728 Property. 729 730 Args: 731 ad: An AndroidDevice object. 732 true_position: Coordinate as [latitude, longitude] to calculate 733 position error. 734 type: Different API for location fix. Use gnss/flp/nmea 735 """ 736 test_logfile = {} 737 track_data = {} 738 ant_top4_cn = 0 739 ant_cn = 0 740 base_top4_cn = 0 741 base_cn = 0 742 l5flag = "false" 743 file_count = int(ad.adb.shell("find %s -type f -iname *.txt | wc -l" 744 % GNSSSTATUS_LOG_PATH)) 745 if file_count != 1: 746 ad.log.error("%d API logs exist." % file_count) 747 dir = ad.adb.shell("ls %s" % GNSSSTATUS_LOG_PATH).split() 748 for path_key in dir: 749 if fnmatch.fnmatch(path_key, "*.txt"): 750 logpath = posixpath.join(GNSSSTATUS_LOG_PATH, path_key) 751 out = ad.adb.shell("wc -c %s" % logpath) 752 file_size = int(out.split(" ")[0]) 753 if file_size < 2000: 754 ad.log.info("Skip log %s due to log size %d bytes" % 755 (path_key, file_size)) 756 continue 757 test_logfile = logpath 758 if not test_logfile: 759 raise signals.TestError("Failed to get test log file in device.") 760 lines = ad.adb.shell("cat %s" % test_logfile).split("\n") 761 for line in lines: 762 if "Antenna_History Avg Top4" in line: 763 ant_top4_cn = float(line.split(":")[-1].strip()) 764 elif "Antenna_History Avg" in line: 765 ant_cn = float(line.split(":")[-1].strip()) 766 elif "Baseband_History Avg Top4" in line: 767 base_top4_cn = float(line.split(":")[-1].strip()) 768 elif "Baseband_History Avg" in line: 769 base_cn = float(line.split(":")[-1].strip()) 770 elif "L5 used in fix" in line: 771 l5flag = line.split(":")[-1].strip() 772 elif "Latitude" in line: 773 track_lat = float(line.split(":")[-1].strip()) 774 elif "Longitude" in line: 775 track_long = float(line.split(":")[-1].strip()) 776 elif "Time" in line: 777 track_utc = line.split("Time:")[-1].strip() 778 if track_utc in track_data.keys(): 779 continue 780 pe = calculate_position_error(ad, track_lat, track_long, 781 true_position) 782 track_data[track_utc] = TRACK_REPORT(l5flag=l5flag, 783 pe=pe, 784 ant_top4cn=ant_top4_cn, 785 ant_cn=ant_cn, 786 base_top4cn=base_top4_cn, 787 base_cn=base_cn) 788 ad.log.debug(track_data) 789 prop_basename = "TestResult %s_tracking_" % type.upper() 790 time_list = sorted(track_data.keys()) 791 l5flag_list = [track_data[key].l5flag for key in time_list] 792 pe_list = [float(track_data[key].pe) for key in time_list] 793 ant_top4cn_list = [float(track_data[key].ant_top4cn) for key in time_list] 794 ant_cn_list = [float(track_data[key].ant_cn) for key in time_list] 795 base_top4cn_list = [float(track_data[key].base_top4cn) for key in time_list] 796 base_cn_list = [float(track_data[key].base_cn) for key in time_list] 797 ad.log.info(prop_basename+"StartTime %s" % time_list[0].replace(" ", "-")) 798 ad.log.info(prop_basename+"EndTime %s" % time_list[-1].replace(" ", "-")) 799 ad.log.info(prop_basename+"TotalFixPoints %d" % len(time_list)) 800 ad.log.info(prop_basename+"L5FixRate "+'{percent:.2%}'.format( 801 percent=l5flag_list.count("true")/len(l5flag_list))) 802 ad.log.info(prop_basename+"AvgDis %.1f" % (sum(pe_list)/len(pe_list))) 803 ad.log.info(prop_basename+"MaxDis %.1f" % max(pe_list)) 804 ad.log.info(prop_basename+"Ant_AvgTop4Signal %.1f" % ant_top4cn_list[-1]) 805 ad.log.info(prop_basename+"Ant_AvgSignal %.1f" % ant_cn_list[-1]) 806 ad.log.info(prop_basename+"Base_AvgTop4Signal %.1f" % base_top4cn_list[-1]) 807 ad.log.info(prop_basename+"Base_AvgSignal %.1f" % base_cn_list[-1]) 808 809 810def process_ttff_by_gtw_gpstool(ad, begin_time, true_position, type="gnss"): 811 """Process TTFF and record results in ttff_data. 812 813 Args: 814 ad: An AndroidDevice object. 815 begin_time: test begin time. 816 true_position: Coordinate as [latitude, longitude] to calculate 817 position error. 818 type: Different API for location fix. Use gnss/flp/nmea 819 820 Returns: 821 ttff_data: A dict of all TTFF data. 822 """ 823 ttff_data = {} 824 ttff_loop_time = get_current_epoch_time() 825 while True: 826 if get_current_epoch_time() - ttff_loop_time >= 120000: 827 raise signals.TestError("Fail to search specific GPSService " 828 "message in logcat. Abort test.") 829 if not ad.is_adb_logcat_on: 830 ad.start_adb_logcat() 831 logcat_results = ad.search_logcat("write TTFF log", ttff_loop_time) 832 if logcat_results: 833 ttff_loop_time = get_current_epoch_time() 834 ttff_log = logcat_results[-1]["log_message"].split() 835 ttff_loop = int(ttff_log[8].split(":")[-1]) 836 ttff_sec = float(ttff_log[11]) 837 if ttff_sec != 0.0: 838 ttff_ant_cn = float(ttff_log[18].strip("]")) 839 ttff_base_cn = float(ttff_log[25].strip("]")) 840 if type == "gnss": 841 gnss_results = ad.search_logcat("GPSService: Check item", 842 begin_time) 843 if gnss_results: 844 ad.log.debug(gnss_results[-1]["log_message"]) 845 gnss_location_log = \ 846 gnss_results[-1]["log_message"].split() 847 ttff_lat = float( 848 gnss_location_log[8].split("=")[-1].strip(",")) 849 ttff_lon = float( 850 gnss_location_log[9].split("=")[-1].strip(",")) 851 loc_time = int( 852 gnss_location_log[10].split("=")[-1].strip(",")) 853 utc_time = epoch_to_human_time(loc_time) 854 elif type == "flp": 855 flp_results = ad.search_logcat("GPSService: FLP Location", 856 begin_time) 857 if flp_results: 858 ad.log.debug(flp_results[-1]["log_message"]) 859 flp_location_log = flp_results[-1][ 860 "log_message"].split() 861 ttff_lat = float(flp_location_log[8].split(",")[0]) 862 ttff_lon = float(flp_location_log[8].split(",")[1]) 863 utc_time = epoch_to_human_time(get_current_epoch_time()) 864 else: 865 ttff_ant_cn = float(ttff_log[19].strip("]")) 866 ttff_base_cn = float(ttff_log[26].strip("]")) 867 ttff_lat = 0 868 ttff_lon = 0 869 utc_time = epoch_to_human_time(get_current_epoch_time()) 870 ad.log.debug("TTFF Loop %d - (Lat, Lon) = (%s, %s)" % (ttff_loop, 871 ttff_lat, 872 ttff_lon)) 873 ttff_pe = calculate_position_error(ad, ttff_lat, ttff_lon, 874 true_position) 875 ttff_data[ttff_loop] = TTFF_REPORT(utc_time=utc_time, 876 ttff_loop=ttff_loop, 877 ttff_sec=ttff_sec, 878 ttff_pe=ttff_pe, 879 ttff_ant_cn=ttff_ant_cn, 880 ttff_base_cn=ttff_base_cn) 881 ad.log.info("UTC Time = %s, Loop %d = %.1f seconds, " 882 "Position Error = %.1f meters, " 883 "Antenna Average Signal = %.1f dbHz, " 884 "Baseband Average Signal = %.1f dbHz" % (utc_time, 885 ttff_loop, 886 ttff_sec, 887 ttff_pe, 888 ttff_ant_cn, 889 ttff_base_cn)) 890 stop_gps_results = ad.search_logcat("stop gps test", begin_time) 891 if stop_gps_results: 892 ad.send_keycode("HOME") 893 break 894 crash_result = ad.search_logcat("Force finishing activity " 895 "com.android.gpstool/.GPSTool", 896 begin_time) 897 if crash_result: 898 raise signals.TestError("GPSTool crashed. Abort test.") 899 # wait 10 seconds to avoid logs not writing into logcat yet 900 time.sleep(10) 901 return ttff_data 902 903 904def check_ttff_data(ad, ttff_data, ttff_mode, criteria): 905 """Verify all TTFF results from ttff_data. 906 907 Args: 908 ad: An AndroidDevice object. 909 ttff_data: TTFF data of secs, position error and signal strength. 910 ttff_mode: TTFF Test mode for current test item. 911 criteria: Criteria for current test item. 912 913 Returns: 914 True: All TTFF results are within criteria. 915 False: One or more TTFF results exceed criteria or Timeout. 916 """ 917 ad.log.info("%d iterations of TTFF %s tests finished." 918 % (len(ttff_data.keys()), ttff_mode)) 919 ad.log.info("%s PASS criteria is %d seconds" % (ttff_mode, criteria)) 920 ad.log.debug("%s TTFF data: %s" % (ttff_mode, ttff_data)) 921 ttff_property_key_and_value(ad, ttff_data, ttff_mode) 922 if len(ttff_data.keys()) == 0: 923 ad.log.error("GTW_GPSTool didn't process TTFF properly.") 924 return False 925 elif any(float(ttff_data[key].ttff_sec) == 0.0 for key in ttff_data.keys()): 926 ad.log.error("One or more TTFF %s Timeout" % ttff_mode) 927 return False 928 elif any(float(ttff_data[key].ttff_sec) >= criteria for key in 929 ttff_data.keys()): 930 ad.log.error("One or more TTFF %s are over test criteria %d seconds" 931 % (ttff_mode, criteria)) 932 return False 933 ad.log.info("All TTFF %s are within test criteria %d seconds." 934 % (ttff_mode, criteria)) 935 return True 936 937 938def ttff_property_key_and_value(ad, ttff_data, ttff_mode): 939 """Output ttff_data to test_run_info for ACTS plugin to parse and display 940 on MobileHarness as Property. 941 942 Args: 943 ad: An AndroidDevice object. 944 ttff_data: TTFF data of secs, position error and signal strength. 945 ttff_mode: TTFF Test mode for current test item. 946 """ 947 prop_basename = "TestResult "+ttff_mode.replace(" ", "_")+"_TTFF_" 948 sec_list = [float(ttff_data[key].ttff_sec) for key in ttff_data.keys()] 949 pe_list = [float(ttff_data[key].ttff_pe) for key in ttff_data.keys()] 950 ant_cn_list = [float(ttff_data[key].ttff_ant_cn) for key in 951 ttff_data.keys()] 952 base_cn_list = [float(ttff_data[key].ttff_base_cn) for key in 953 ttff_data.keys()] 954 timeoutcount = sec_list.count(0.0) 955 if len(sec_list) == timeoutcount: 956 avgttff = 9527 957 else: 958 avgttff = sum(sec_list)/(len(sec_list) - timeoutcount) 959 if timeoutcount != 0: 960 maxttff = 9527 961 else: 962 maxttff = max(sec_list) 963 avgdis = sum(pe_list)/len(pe_list) 964 maxdis = max(pe_list) 965 ant_avgcn = sum(ant_cn_list)/len(ant_cn_list) 966 base_avgcn = sum(base_cn_list)/len(base_cn_list) 967 ad.log.info(prop_basename+"AvgTime %.1f" % avgttff) 968 ad.log.info(prop_basename+"MaxTime %.1f" % maxttff) 969 ad.log.info(prop_basename+"TimeoutCount %d" % timeoutcount) 970 ad.log.info(prop_basename+"AvgDis %.1f" % avgdis) 971 ad.log.info(prop_basename+"MaxDis %.1f" % maxdis) 972 ad.log.info(prop_basename+"Ant_AvgSignal %.1f" % ant_avgcn) 973 ad.log.info(prop_basename+"Base_AvgSignal %.1f" % base_avgcn) 974 975 976def calculate_position_error(ad, latitude, longitude, true_position): 977 """Use haversine formula to calculate position error base on true location 978 coordinate. 979 980 Args: 981 ad: An AndroidDevice object. 982 latitude: latitude of location fixed in the present. 983 longitude: longitude of location fixed in the present. 984 true_position: [latitude, longitude] of true location coordinate. 985 986 Returns: 987 position_error of location fixed in the present. 988 """ 989 radius = 6371009 990 dlat = math.radians(latitude - true_position[0]) 991 dlon = math.radians(longitude - true_position[1]) 992 a = math.sin(dlat/2) * math.sin(dlat/2) + \ 993 math.cos(math.radians(true_position[0])) * \ 994 math.cos(math.radians(latitude)) * math.sin(dlon/2) * math.sin(dlon/2) 995 c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) 996 return radius * c 997 998 999def launch_google_map(ad): 1000 """Launch Google Map via intent. 1001 1002 Args: 1003 ad: An AndroidDevice object. 1004 """ 1005 ad.log.info("Launch Google Map.") 1006 try: 1007 ad.adb.shell("am start -S -n com.google.android.apps.maps/" 1008 "com.google.android.maps.MapsActivity") 1009 ad.send_keycode("BACK") 1010 ad.force_stop_apk("com.google.android.apps.maps") 1011 ad.adb.shell("am start -S -n com.google.android.apps.maps/" 1012 "com.google.android.maps.MapsActivity") 1013 except Exception as e: 1014 ad.log.error(e) 1015 raise signals.TestError("Failed to launch google map.") 1016 check_currrent_focus_app(ad) 1017 1018 1019def check_currrent_focus_app(ad): 1020 """Check to see current focused window and app. 1021 1022 Args: 1023 ad: An AndroidDevice object. 1024 """ 1025 time.sleep(1) 1026 current = ad.adb.shell( 1027 "dumpsys window | grep -E 'mCurrentFocus|mFocusedApp'") 1028 ad.log.debug("\n"+current) 1029 1030 1031def check_location_api(ad, retries): 1032 """Verify if GnssLocationProvider API reports location. 1033 1034 Args: 1035 ad: An AndroidDevice object. 1036 retries: Retry time. 1037 1038 Returns: 1039 True: GnssLocationProvider API reports location. 1040 otherwise return False. 1041 """ 1042 for i in range(retries): 1043 begin_time = get_current_epoch_time() 1044 ad.log.info("Try to get location report from GnssLocationProvider API " 1045 "- attempt %d" % (i+1)) 1046 while get_current_epoch_time() - begin_time <= 30000: 1047 logcat_results = ad.search_logcat("REPORT_LOCATION", begin_time) 1048 if logcat_results: 1049 ad.log.info("%s" % logcat_results[-1]["log_message"]) 1050 ad.log.info("GnssLocationProvider reports location " 1051 "successfully.") 1052 return True 1053 if not ad.is_adb_logcat_on: 1054 ad.start_adb_logcat() 1055 ad.log.error("GnssLocationProvider is unable to report location.") 1056 return False 1057 1058def check_network_location(ad, retries, location_type, criteria=30): 1059 """Verify if NLP reports location after requesting via GPSTool. 1060 1061 Args: 1062 ad: An AndroidDevice object. 1063 retries: Retry time. 1064 location_type: cell or wifi. 1065 criteria: expected nlp return time, default 30 seconds 1066 1067 Returns: 1068 True: NLP reports location. 1069 otherwise return False. 1070 """ 1071 criteria = criteria * 1000 1072 search_pattern = ("GPSTool : networkLocationType = %s" % location_type) 1073 for i in range(retries): 1074 begin_time = get_current_epoch_time() 1075 ad.log.info("Try to get NLP status - attempt %d" % (i+1)) 1076 ad.adb.shell( 1077 "am start -S -n com.android.gpstool/.GPSTool --es mode nlp") 1078 while get_current_epoch_time() - begin_time <= criteria: 1079 # Search pattern in 1 second interval 1080 time.sleep(1) 1081 result = ad.search_logcat(search_pattern, begin_time) 1082 if result: 1083 ad.log.info("Pattern Found: %s." % result[-1]["log_message"]) 1084 ad.send_keycode("BACK") 1085 return True 1086 if not ad.is_adb_logcat_on: 1087 ad.start_adb_logcat() 1088 ad.send_keycode("BACK") 1089 ad.log.error("Unable to report network location \"%s\"." % location_type) 1090 return False 1091 1092 1093def set_attenuator_gnss_signal(ad, attenuator, atten_value): 1094 """Set attenuation value for different GNSS signal. 1095 1096 Args: 1097 ad: An AndroidDevice object. 1098 attenuator: The attenuator object. 1099 atten_value: attenuation value 1100 """ 1101 try: 1102 ad.log.info( 1103 "Set attenuation value to \"%d\" for GNSS signal." % atten_value) 1104 attenuator[0].set_atten(atten_value) 1105 except Exception as e: 1106 ad.log.error(e) 1107 1108 1109def set_battery_saver_mode(ad, state): 1110 """Enable or diable battery saver mode via adb. 1111 1112 Args: 1113 ad: An AndroidDevice object. 1114 state: True is enable Battery Saver mode. False is disable. 1115 """ 1116 ad.root_adb() 1117 if state: 1118 ad.log.info("Enable Battery Saver mode.") 1119 ad.adb.shell("cmd battery unplug") 1120 ad.adb.shell("settings put global low_power 1") 1121 else: 1122 ad.log.info("Disable Battery Saver mode.") 1123 ad.adb.shell("settings put global low_power 0") 1124 ad.adb.shell("cmd battery reset") 1125 1126 1127def set_gnss_qxdm_mask(ad, masks): 1128 """Find defined gnss qxdm mask and set as default logging mask. 1129 1130 Args: 1131 ad: An AndroidDevice object. 1132 masks: Defined gnss qxdm mask. 1133 """ 1134 try: 1135 for mask in masks: 1136 if not tutils.find_qxdm_log_mask(ad, mask): 1137 continue 1138 tutils.set_qxdm_logger_command(ad, mask) 1139 break 1140 except Exception as e: 1141 ad.log.error(e) 1142 raise signals.TestError("Failed to set any QXDM masks.") 1143 1144 1145def start_youtube_video(ad, url=None, retries=0): 1146 """Start youtube video and verify if audio is in music state. 1147 1148 Args: 1149 ad: An AndroidDevice object. 1150 url: Youtube video url. 1151 retries: Retry times if audio is not in music state. 1152 1153 Returns: 1154 True if youtube video is playing normally. 1155 False if youtube video is not playing properly. 1156 """ 1157 for i in range(retries): 1158 ad.log.info("Open an youtube video - attempt %d" % (i+1)) 1159 ad.adb.shell("am start -a android.intent.action.VIEW -d \"%s\"" % url) 1160 time.sleep(2) 1161 out = ad.adb.shell( 1162 "dumpsys activity | grep NewVersionAvailableActivity") 1163 if out: 1164 ad.log.info("Skip Youtube New Version Update.") 1165 ad.send_keycode("BACK") 1166 if tutils.wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1): 1167 ad.log.info("Started a video in youtube, audio is in MUSIC state") 1168 return True 1169 ad.log.info("Force-Stop youtube and reopen youtube again.") 1170 ad.force_stop_apk("com.google.android.youtube") 1171 check_currrent_focus_app(ad) 1172 raise signals.TestError("Started a video in youtube, " 1173 "but audio is not in MUSIC state") 1174 1175 1176def get_baseband_and_gms_version(ad, extra_msg=""): 1177 """Get current radio baseband and GMSCore version of AndroidDevice object. 1178 1179 Args: 1180 ad: An AndroidDevice object. 1181 """ 1182 try: 1183 build_version = ad.adb.getprop("ro.build.id") 1184 baseband_version = ad.adb.getprop("gsm.version.baseband") 1185 gms_version = ad.adb.shell( 1186 "dumpsys package com.google.android.gms | grep versionName" 1187 ).split("\n")[0].split("=")[1] 1188 mpss_version = ad.adb.shell("cat /sys/devices/soc0/images | grep MPSS " 1189 "| cut -d ':' -f 3") 1190 if not extra_msg: 1191 ad.log.info("TestResult Build_Version %s" % build_version) 1192 ad.log.info("TestResult Baseband_Version %s" % baseband_version) 1193 ad.log.info( 1194 "TestResult GMS_Version %s" % gms_version.replace(" ", "")) 1195 ad.log.info("TestResult MPSS_Version %s" % mpss_version) 1196 else: 1197 ad.log.info( 1198 "%s, Baseband_Version = %s" % (extra_msg, baseband_version)) 1199 except Exception as e: 1200 ad.log.error(e) 1201 1202 1203def start_toggle_gnss_by_gtw_gpstool(ad, iteration): 1204 """Send toggle gnss off/on start_test_action 1205 1206 Args: 1207 ad: An AndroidDevice object. 1208 iteration: Iteration of toggle gnss off/on cycles. 1209 """ 1210 msg_list = [] 1211 begin_time = get_current_epoch_time() 1212 try: 1213 for i in range(1, 4): 1214 ad.adb.shell("am start -S -n com.android.gpstool/.GPSTool " 1215 "--es mode toggle --es cycle %d" % iteration) 1216 time.sleep(1) 1217 if ad.search_logcat("cmp=com.android.gpstool/.ToggleGPS", 1218 begin_time): 1219 ad.log.info("Send ToggleGPS start_test_action successfully.") 1220 break 1221 else: 1222 check_currrent_focus_app(ad) 1223 raise signals.TestError("Fail to send ToggleGPS " 1224 "start_test_action within 3 attempts.") 1225 time.sleep(2) 1226 test_start = ad.search_logcat("GPSTool_ToggleGPS: startService", 1227 begin_time) 1228 if test_start: 1229 ad.log.info(test_start[-1]["log_message"].split(":")[-1].strip()) 1230 else: 1231 raise signals.TestError("Fail to start toggle GPS off/on test.") 1232 # Every iteration is expected to finish within 4 minutes. 1233 while get_current_epoch_time() - begin_time <= iteration * 240000: 1234 crash_end = ad.search_logcat("Force finishing activity " 1235 "com.android.gpstool/.GPSTool", 1236 begin_time) 1237 if crash_end: 1238 raise signals.TestError("GPSTool crashed. Abort test.") 1239 toggle_results = ad.search_logcat("GPSTool : msg", begin_time) 1240 if toggle_results: 1241 for toggle_result in toggle_results: 1242 msg = toggle_result["log_message"] 1243 if not msg in msg_list: 1244 ad.log.info(msg.split(":")[-1].strip()) 1245 msg_list.append(msg) 1246 if "timeout" in msg: 1247 raise signals.TestFailure("Fail to get location fixed " 1248 "within 60 seconds.") 1249 if "Test end" in msg: 1250 raise signals.TestPass("Completed quick toggle GNSS " 1251 "off/on test.") 1252 raise signals.TestFailure("Fail to finish toggle GPS off/on test " 1253 "within %d minutes" % (iteration * 4)) 1254 finally: 1255 ad.send_keycode("HOME") 1256 1257 1258def grant_location_permission(ad, option): 1259 """Grant or revoke location related permission. 1260 1261 Args: 1262 ad: An AndroidDevice object. 1263 option: Boolean to grant or revoke location related permissions. 1264 """ 1265 action = "grant" if option else "revoke" 1266 for permission in LOCATION_PERMISSIONS: 1267 ad.log.info( 1268 "%s permission:%s on %s" % (action, permission, TEST_PACKAGE_NAME)) 1269 ad.adb.shell("pm %s %s %s" % (action, TEST_PACKAGE_NAME, permission)) 1270 1271 1272def check_location_runtime_permissions(ad, package, permissions): 1273 """Check if runtime permissions are granted on selected package. 1274 1275 Args: 1276 ad: An AndroidDevice object. 1277 package: Apk package name to check. 1278 permissions: A list of permissions to be granted. 1279 """ 1280 for _ in range(3): 1281 location_runtime_permission = ad.adb.shell( 1282 "dumpsys package %s | grep ACCESS_FINE_LOCATION" % package) 1283 if "true" not in location_runtime_permission: 1284 ad.log.info("ACCESS_FINE_LOCATION is NOT granted on %s" % package) 1285 for permission in permissions: 1286 ad.log.debug("Grant %s on %s" % (permission, package)) 1287 ad.adb.shell("pm grant %s %s" % (package, permission)) 1288 else: 1289 ad.log.info("ACCESS_FINE_LOCATION is granted on %s" % package) 1290 break 1291 else: 1292 raise signals.TestError( 1293 "Fail to grant ACCESS_FINE_LOCATION on %s" % package) 1294 1295 1296def install_mdstest_app(ad, mdsapp): 1297 """ 1298 Install MDS test app in DUT 1299 1300 Args: 1301 ad: An Android Device Object 1302 mdsapp: Installation path of MDSTest app 1303 """ 1304 if not ad.is_apk_installed("com.google.mdstest"): 1305 ad.adb.install("-r %s" % mdsapp, timeout=300, ignore_status=True) 1306 1307 1308def write_modemconfig(ad, mdsapp, nvitem_dict, modemparfile): 1309 """ 1310 Modify the NV items using modem_tool.par 1311 Note: modem_tool.par 1312 1313 Args: 1314 ad: An Android Device Object 1315 mdsapp: Installation path of MDSTest app 1316 nvitem_dict: dictionary of NV items and values. 1317 modemparfile: modem_tool.par path. 1318 """ 1319 ad.log.info("Verify MDSTest app installed in DUT") 1320 install_mdstest_app(ad, mdsapp) 1321 os.system("chmod 777 %s" % modemparfile) 1322 for key, value in nvitem_dict.items(): 1323 if key.isdigit(): 1324 op_name = "WriteEFS" 1325 else: 1326 op_name = "WriteNV" 1327 ad.log.info("Modifying the NV{!r} using {}".format(key, op_name)) 1328 job.run("{} --op {} --item {} --data '{}'". 1329 format(modemparfile, op_name, key, value)) 1330 time.sleep(2) 1331 1332 1333def verify_modemconfig(ad, nvitem_dict, modemparfile): 1334 """ 1335 Verify the NV items using modem_tool.par 1336 Note: modem_tool.par 1337 1338 Args: 1339 ad: An Android Device Object 1340 nvitem_dict: dictionary of NV items and values 1341 modemparfile: modem_tool.par path. 1342 """ 1343 os.system("chmod 777 %s" % modemparfile) 1344 for key, value in nvitem_dict.items(): 1345 if key.isdigit(): 1346 op_name = "ReadEFS" 1347 else: 1348 op_name = "ReadNV" 1349 # Sleeptime to avoid Modem communication error 1350 time.sleep(5) 1351 result = job.run( 1352 "{} --op {} --item {}".format(modemparfile, op_name, key)) 1353 output = str(result.stdout) 1354 ad.log.info("Actual Value for NV{!r} is {!r}".format(key, output)) 1355 if not value.casefold() in output: 1356 ad.log.error("NV Value is wrong {!r} in {!r}".format(value, result)) 1357 raise ValueError( 1358 "could not find {!r} in {!r}".format(value, result)) 1359 1360 1361def check_ttff_pe(ad, ttff_data, ttff_mode, pecriteria): 1362 """Verify all TTFF results from ttff_data. 1363 1364 Args: 1365 ad: An AndroidDevice object. 1366 ttff_data: TTFF data of secs, position error and signal strength. 1367 ttff_mode: TTFF Test mode for current test item. 1368 criteria: Criteria for current test item. 1369 1370 """ 1371 ad.log.info("%d iterations of TTFF %s tests finished.", 1372 (len(ttff_data.keys()), ttff_mode)) 1373 ad.log.info("%s PASS criteria is %f meters", (ttff_mode, pecriteria)) 1374 ad.log.debug("%s TTFF data: %s", (ttff_mode, ttff_data)) 1375 1376 if len(ttff_data.keys()) == 0: 1377 ad.log.error("GTW_GPSTool didn't process TTFF properly.") 1378 raise signals.TestFailure("GTW_GPSTool didn't process TTFF properly.") 1379 1380 elif any(float(ttff_data[key].ttff_pe) >= pecriteria for key in 1381 ttff_data.keys()): 1382 ad.log.error("One or more TTFF %s are over test criteria %f meters", 1383 (ttff_mode, pecriteria)) 1384 raise signals.TestFailure("GTW_GPSTool didn't process TTFF properly.") 1385 ad.log.info("All TTFF %s are within test criteria %f meters.", 1386 (ttff_mode, pecriteria)) 1387 1388 1389def check_adblog_functionality(ad): 1390 """Restart adb logcat if system can't write logs into file after checking 1391 adblog file size. 1392 1393 Args: 1394 ad: An AndroidDevice object. 1395 """ 1396 logcat_path = os.path.join(ad.device_log_path, "adblog_%s_debug.txt" % 1397 ad.serial) 1398 if not os.path.exists(logcat_path): 1399 raise signals.TestError("Logcat file %s does not exist." % logcat_path) 1400 original_log_size = os.path.getsize(logcat_path) 1401 ad.log.debug("Original adblog size is %d" % original_log_size) 1402 time.sleep(.5) 1403 current_log_size = os.path.getsize(logcat_path) 1404 ad.log.debug("Current adblog size is %d" % current_log_size) 1405 if current_log_size == original_log_size: 1406 ad.log.warn("System can't write logs into file. Restart adb " 1407 "logcat process now.") 1408 ad.stop_adb_logcat() 1409 ad.start_adb_logcat() 1410