blob: 9f3ccfd9ffc6eb47317a8a2e33c4def4ae0fe05c [file] [log] [blame]
"""Make sure the user build configuration is working as expected.
Although we can assume the features should be the same between user and user_debug build,
the configuration difference between this two build are not tested.
In this test suite, we modify the gps configuration to be the same as user build
and check if the setting is working.
For more details, please refer to : go/p22_user_build_verification
"""
import os
import shutil
import tempfile
import time
from acts import asserts
from acts import signals
from acts.base_test import BaseTestClass
from acts.controllers.adb_lib.error import AdbCommandError
from acts.libs.proc.job import TimeoutError
from acts.test_decorators import test_tracker_info
from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
class GpsConfig:
def __init__(self, ad, name) -> None:
self.ad = ad
self.name = name
self.folder = "/vendor/etc/gnss"
self.full_path = os.path.join(self.folder, self.name)
self.logenabled = "LogEnabled"
self._log_enable = "true"
self._log_disable = "false"
def _change_file_content(self, pattern, target):
"""Modify file via sed command
command will be sed -i 's/<pattern>/<target>/g' <file_path>
Args:
pattern: a string will be used as search pattern
target: string that will overwrite the matched result
"""
self.ad.adb.remount()
command = f"sed -i s/{pattern}/{target}/g {self.full_path}"
self.ad.adb.shell(command)
def _get_setting_value(self, key):
"""Get setting value from config file
command is grep <key> self.full_path
Args:
key: a string will be used as search pattern
Returns:
string: grep result ("" for no grep result)
"""
command = f"grep {key} {self.full_path}"
result = self.ad.adb.shell(command)
return result
def _adjust_log_enable_setting(self, key, enable):
"""Enable / Disable in self.full_path by setting key = true / false
Args:
key: The target will be changed
enable: True to enable / False to disable
"""
src = self._log_disable if enable else self._log_enable
target = self._log_enable if enable else self._log_disable
pattern = f"{key}={src}"
target = f"{key}={target}"
self._change_file_content(pattern, target)
result = self._get_setting_value(key)
self.ad.log.debug("%s setting: %s", self.name, result)
def _check_file_exist(self, file_pattern):
"""use command ls to check if file/dir exists
command ls <file_pattern>
Args:
file_pattern: A string represents the file or dir
Returns:
bool: True -> file exists / False -> file doesn't exist
"""
command = f"ls {file_pattern}"
try:
self.ad.adb.shell(command)
result = True
except AdbCommandError as e:
result = False
return result
def enable_diagnostic_log(self):
"""Set LogEnabled=true in config file
In gps.xml it will be LogEnabled=\"true\"
"""
self.ad.log.info("Enable diagnostic log in %s", self.name)
self._adjust_log_enable_setting(key=self.logenabled, enable=True)
def disable_diagnostic_log(self):
"""Set LogEnabled=false in config file
In gps.xml it will be LogEnabled=\"false\"
"""
self.ad.log.info("Disable diagnostic log in %s", self.name)
self._adjust_log_enable_setting(key=self.logenabled, enable=False)
class ScdConf(GpsConfig):
def __init__(self, ad) -> None:
super().__init__(ad, "scd.conf")
class GpsXml(GpsConfig):
def __init__(self, ad) -> None:
super().__init__(ad, "gps.xml")
self.supllogenable = "SuplLogEnable"
self.supl_log = "/data/vendor/gps/suplflow.txt"
self._log_enable = "\\\"true\\\""
self._log_disable = "\\\"false\\\""
def enable_supl_log(self):
"""Set SuplLogEnable=\"true\" in gps.xml"""
self.ad.log.info("Enable SUPL logs")
self._adjust_log_enable_setting(key=self.supllogenable, enable=True)
def disable_supl_log(self):
"""Set SuplLogEnable=\"false\" in gps.xml"""
self.ad.log.info("Disable SUPL log")
self._adjust_log_enable_setting(key=self.supllogenable, enable=False)
def remove_supl_logs(self):
"""Remove /data/vendor/gps/suplflow.txt"""
self.ad.log.info("Remove SUPL logs")
command = f"rm -f {self.supl_log}"
self.ad.adb.shell(command)
def is_supl_log_file_exist(self):
"""Check if /data/vendor/gps/suplflow.txt exist
Returns:
bool: True -> supl log exists / False -> supl log doesn't exist
"""
result = self._check_file_exist(self.supl_log)
self.ad.log.debug("Supl file exists?: %s", result)
return result
class LhdConf(GpsConfig):
def __init__(self, ad) -> None:
super().__init__(ad, "lhd.conf")
self.lhefailsafe = "LheFailSafe"
self.lheconsole = "LheConsole"
self.lheconsole_hub = self.get_lheconsole_value()
self.esw_crash_dump_pattern = self.get_esw_crash_dump_pattern()
self.ad.log.info(f"here is {self.esw_crash_dump_pattern}")
def _adjust_lhe_setting(self, key, enable):
"""Set lhe setting.
Enable - uncomment out the setting
Dissable - comment out the setting
Args:
key: A string will be used as search pattern
enable: bool True to enable / False to disable
"""
pattern = f"#\ {key}" if enable else key
target = key if enable else f"#\ {key}"
self._change_file_content(pattern, target)
def enable_lhefailsafe(self):
"""Uncomment out LheFailSafe"""
self.ad.log.info("Enable %s", self.lhefailsafe)
self._adjust_lhe_setting(key=self.lhefailsafe, enable=True)
def disable_lhefailsafe(self):
"""Comment out LheFailSafe"""
self.ad.log.info("Disable %s", self.lhefailsafe)
self._adjust_lhe_setting(key=self.lhefailsafe, enable=False)
def enable_lheconsole(self):
"""Uncomment out LheConsole"""
self.ad.log.info("Enable %s", self.lheconsole)
self._adjust_lhe_setting(key=self.lheconsole, enable=True)
def disable_lheconsole(self):
"""Comment out LheConsole"""
self.ad.log.info("Disable %s", self.lheconsole)
self._adjust_lhe_setting(key=self.lheconsole, enable=False)
def get_lhefailsafe_value(self):
"""Get the LheFailSafe value
Returns:
string: the LheFailSafe value in config
Raises:
ValueError: No LheFailSafe value
"""
result = self._get_setting_value(self.lhefailsafe)
if not result:
raise ValueError(("%s should exists in %s", self.lhefailsafe, self.name))
result = result.split("=")[1]
self.ad.log.debug("%s is %s", self.lhefailsafe, result)
return result
def get_lheconsole_value(self):
"""Get the LheConsole value
Returns:
string: the LheConsole value in config
Raises:
ValueError: No LheConsole value
"""
result = self._get_setting_value(self.lheconsole)
if not result:
raise ValueError(("%s should exists in %s", self.lheconsole, self.name))
result = result.split("=")[1]
self.ad.log.debug("%s is %s", self.lheconsole, result)
return result
def get_esw_crash_dump_pattern(self):
"""Get the esw crash dump file pattern
The value is set in LheFailSafe, but we need to add wildcard.
Returns:
string: esw crash dump pattern
Raises:
ValueError: No LheFailSafe value
"""
value = self.get_lhefailsafe_value()
value = value.replace(".txt", "*.txt")
self.ad.log.debug("Dump file pattern is %s", value)
return value
def remove_esw_crash_dump_file(self):
"""Remove crash dump file"""
self.ad.log.info("Remove esw crash file")
command = f"rm -f {self.esw_crash_dump_pattern}"
self.ad.adb.shell(command)
def trigger_firmware_crash(self):
"""Send command to LheConsole to trigger firmware crash"""
self.ad.log.info("Trigger firmware crash")
command = f"echo Lhe:write=0xFFFFFFFF,4 > {self.lheconsole_hub}.toAsic"
self.ad.adb.shell(command, timeout=10)
def is_esw_crash_dump_file_exist(self):
"""Check if esw_crash_dump_pattern exists
Will try 3 times, 1 second interval for each attempt
Returns:
bool: True -> file exists / False -> file doesn't exist
"""
for attempt in range(1, 4):
result = self._check_file_exist(self.esw_crash_dump_pattern)
self.ad.log.debug("(Attempt %s)esw dump file exists?: %s", attempt, result)
if result:
return result
time.sleep(1)
return False
class GnssUserBuildBroadcomConfigurationTest(BaseTestClass):
""" GNSS user build configuration Tests on Broadcom device."""
def setup_class(self):
super().setup_class()
self.ad = self.android_devices[0]
if not gutils.check_chipset_vendor_by_qualcomm(self.ad):
gutils._init_device(self.ad)
self.gps_config_path = tempfile.mkdtemp()
self.gps_xml = GpsXml(self.ad)
self.lhd_conf = LhdConf(self.ad)
self.scd_conf = ScdConf(self.ad)
self.enable_testing_setting()
self.backup_gps_config()
def teardown_class(self):
if hasattr(self, "gps_config_path") and os.path.isdir(self.gps_config_path):
shutil.rmtree(self.gps_config_path)
def setup_test(self):
if gutils.check_chipset_vendor_by_qualcomm(self.ad):
raise signals.TestSkip("Device is Qualcomm, skip the test")
gutils.clear_logd_gnss_qxdm_log(self.ad)
def teardown_test(self):
if not gutils.check_chipset_vendor_by_qualcomm(self.ad):
self.revert_gps_config()
self.ad.reboot()
def on_fail(self, test_name, begin_time):
self.ad.take_bug_report(test_name, begin_time)
gutils.get_gnss_qxdm_log(self.ad)
def enable_testing_setting(self):
"""Enable setting to the testing target
Before backing up config, enable all the testing target
To ensure the teardown_test can bring the device back to the desired state
"""
self.set_gps_logenabled(enable=True)
self.gps_xml.enable_supl_log()
self.lhd_conf.enable_lheconsole()
self.lhd_conf.enable_lhefailsafe()
def backup_gps_config(self):
"""Copy the gps config
config file will be copied: gps.xml / lhd.conf / scd.conf
"""
for conf in [self.gps_xml, self.scd_conf, self.lhd_conf]:
self.ad.log.debug("Backup %s", conf.full_path)
self.ad.adb.pull(conf.full_path, self.gps_config_path)
def revert_gps_config(self):
"""Revert the gps config from the one we backup in the setup_class
config file will be reverted: gps.xml / lhd.conf / scd.conf
"""
self.ad.adb.remount()
for conf in [self.gps_xml, self.scd_conf, self.lhd_conf]:
file_path = os.path.join(self.gps_config_path, conf.name)
self.ad.log.debug("Revert %s", conf.full_path)
self.ad.adb.push(file_path, conf.full_path)
def run_gps_and_capture_log(self):
"""Enable GPS via gps tool for 15s and capture pixel log"""
gutils.start_pixel_logger(self.ad)
gutils.start_gnss_by_gtw_gpstool(self.ad, state=True)
time.sleep(15)
gutils.start_gnss_by_gtw_gpstool(self.ad, state=False)
gutils.stop_pixel_logger(self.ad)
def set_gps_logenabled(self, enable):
"""Set LogEnabled in gps.xml / lhd.conf / scd.conf
Args:
enable: True to enable / False to disable
"""
if enable:
self.gps_xml.enable_diagnostic_log()
self.scd_conf.enable_diagnostic_log()
self.lhd_conf.enable_diagnostic_log()
else:
self.gps_xml.disable_diagnostic_log()
self.scd_conf.disable_diagnostic_log()
self.lhd_conf.disable_diagnostic_log()
@test_tracker_info(uuid="1dd68d9c-38b0-4fbc-8635-1228c72872ff")
def test_gps_logenabled_setting(self):
"""Verify the LogEnabled setting in gps.xml / scd.conf / lhd.conf
Steps:
1. default setting is on in user_debug build
2. enable gps for 15s
3. assert gps log pattern "slog :" in pixel logger
4. disable LogEnabled in all the gps conf
5. enable gps for 15s
6. assert gps log pattern "slog :" in pixel logger
"""
self.run_gps_and_capture_log()
result, _ = gutils.parse_brcm_nmea_log(self.ad, "slog :", [])
asserts.assert_true(bool(result), "LogEnabled is set to true, but no gps log was found")
self.set_gps_logenabled(enable=False)
gutils.clear_logd_gnss_qxdm_log(self.ad)
self.run_gps_and_capture_log()
result, _ = gutils.parse_brcm_nmea_log(self.ad, "slog :", [])
asserts.assert_false(bool(result), ("LogEnabled is set to False but still found %d slog",
len(result)))
@test_tracker_info(uuid="152a12e0-7957-47e0-9ea7-14725254fd1d")
def test_gps_supllogenable_setting(self):
"""Verify SuplLogEnable in gps.xml
Steps:
1. default setting is on in user_debug build
2. remove existing supl log
3. enable gps for 15s
4. supl log should exist
5. disable SuplLogEnable in gps.xml
6. remove existing supl log
7. enable gps for 15s
8. supl log should not exist
"""
def is_supl_log_exist_after_supl_request():
self.gps_xml.remove_supl_logs()
self.run_gps_and_capture_log()
return self.gps_xml.is_supl_log_file_exist()
result = is_supl_log_exist_after_supl_request()
asserts.assert_true(result, "SuplLogEnable is enable, should find supl log file")
self.gps_xml.disable_supl_log()
self.ad.reboot()
result = is_supl_log_exist_after_supl_request()
asserts.assert_false(result, "SuplLogEnable is disable, should not find supl log file")
@test_tracker_info(uuid="892d0037-8c0c-45b6-bd0f-9e4073d37232")
def test_lhe_setting(self):
"""Verify lhefailsafe / lheconsole setting in lhd.conf
Steps:
1. both setting is enabled
2. trigger firmware crash and check if dump file exist
3. disable lhefailsafe
4. trigger firmware crash and check if dump file exist
5. disable lheconsle
6. trigger firmware crash and check if command timeout
"""
def is_dump_file_exist_after_firmware_crash():
self.lhd_conf.remove_esw_crash_dump_file()
self.lhd_conf.trigger_firmware_crash()
return self.lhd_conf.is_esw_crash_dump_file_exist()
result = is_dump_file_exist_after_firmware_crash()
asserts.assert_true(result, "LheFailSafe is enabled, but no crash file was found")
self.lhd_conf.disable_lhefailsafe()
self.ad.reboot()
result = is_dump_file_exist_after_firmware_crash()
asserts.assert_false(result, "LheFailSafe is disabled, but still found crash file")
self.lhd_conf.disable_lheconsole()
self.ad.reboot()
with asserts.assert_raises(TimeoutError):
self.lhd_conf.trigger_firmware_crash()