• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#   Copyright 2020 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17from collections import defaultdict
18import datetime
19import os
20import re
21import time
22import functools
23import fnmatch
24from statistics import mean
25
26from acts import asserts
27from acts import signals
28from acts.base_test import BaseTestClass
29from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
30from acts.utils import get_current_epoch_time
31from acts.utils import unzip_maintain_permissions
32from acts_contrib.test_utils.wifi.wifi_test_utils import wifi_toggle_state
33from acts_contrib.test_utils.tel.tel_bootloader_utils import flash_radio
34from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
35from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_connected_by_adb
36from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
37from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
38from acts_contrib.test_utils.gnss.gnss_test_utils import get_baseband_and_gms_version
39from acts_contrib.test_utils.gnss.gnss_test_utils import set_attenuator_gnss_signal
40from acts_contrib.test_utils.gnss.gnss_test_utils import _init_device
41from acts_contrib.test_utils.gnss.gnss_test_utils import check_location_service
42from acts_contrib.test_utils.gnss.gnss_test_utils import clear_logd_gnss_qxdm_log
43from acts_contrib.test_utils.gnss.gnss_test_utils import set_mobile_data
44from acts_contrib.test_utils.gnss.gnss_test_utils import set_wifi_and_bt_scanning
45from acts_contrib.test_utils.gnss.gnss_test_utils import get_gnss_qxdm_log
46from acts_contrib.test_utils.gnss.gnss_test_utils import remount_device
47from acts_contrib.test_utils.gnss.gnss_test_utils import reboot
48from acts_contrib.test_utils.gnss.gnss_test_utils import check_network_location
49from acts_contrib.test_utils.gnss.gnss_test_utils import launch_google_map
50from acts_contrib.test_utils.gnss.gnss_test_utils import check_location_api
51from acts_contrib.test_utils.gnss.gnss_test_utils import set_battery_saver_mode
52from acts_contrib.test_utils.gnss.gnss_test_utils import start_gnss_by_gtw_gpstool
53from acts_contrib.test_utils.gnss.gnss_test_utils import process_gnss_by_gtw_gpstool
54from acts_contrib.test_utils.gnss.gnss_test_utils import connect_to_wifi_network
55from acts_contrib.test_utils.gnss.gnss_test_utils import gnss_tracking_via_gtw_gpstool
56from acts_contrib.test_utils.gnss.gnss_test_utils import parse_gtw_gpstool_log
57from acts_contrib.test_utils.gnss.gnss_test_utils import start_toggle_gnss_by_gtw_gpstool
58from acts_contrib.test_utils.gnss.gnss_test_utils import grant_location_permission
59from acts_contrib.test_utils.gnss.gnss_test_utils import is_mobile_data_on
60from acts_contrib.test_utils.gnss.gnss_test_utils import is_wearable_btwifi
61from acts_contrib.test_utils.gnss.gnss_test_utils import is_device_wearable
62from acts_contrib.test_utils.gnss.gnss_test_utils import log_current_epoch_time
63from acts_contrib.test_utils.gnss.testtracker_util import log_testtracker_uuid
64from acts_contrib.test_utils.tel.tel_logging_utils import stop_adb_tcpdump
65from acts_contrib.test_utils.tel.tel_logging_utils import get_tcpdump_log
66
67
68_PPS_KICKIN_WAITING_TIME_IN_SECOND = 30
69
70class GnssFunctionTest(BaseTestClass):
71    """ GNSS Function Tests"""
72    def setup_class(self):
73        super().setup_class()
74        self.ad = self.android_devices[0]
75        req_params = ["pixel_lab_network",
76                      "standalone_ws_criteria", "standalone_hs_criteria",
77                      "supl_cs_criteria",
78                      "supl_hs_criteria",
79                      "standalone_cs_criteria",
80                      "wearable_reboot_hs_criteria",
81                      "first_satellite_criteria",
82                      "default_gnss_signal_attenuation",
83                      "weak_gnss_signal_attenuation",
84                      "gnss_init_error_list",
85                      "gnss_init_error_allowlist", "pixel_lab_location",
86                      "qdsp6m_path", "ttff_test_cycle",
87                      "collect_logs", "dpo_threshold",
88                      "brcm_error_log_allowlist", "onchip_interval", "adr_ratio_threshold",
89                      "set_attenuator", "weak_signal_criteria", "weak_signal_cs_criteria"]
90        self.unpack_userparams(req_param_names=req_params)
91        # create hashmap for SSID
92        self.ssid_map = {}
93        for network in self.pixel_lab_network:
94            SSID = network["SSID"]
95            self.ssid_map[SSID] = network
96        self.ttff_mode = {"cs": "Cold Start",
97                          "ws": "Warm Start",
98                          "hs": "Hot Start",
99                          "csa": "CSWith Assist"}
100        if self.collect_logs and gutils.check_chipset_vendor_by_qualcomm(self.ad):
101            self.flash_new_radio_or_mbn()
102            self.push_gnss_cfg()
103        self.init_device()
104
105    def init_device(self):
106        gutils._init_device(self.ad)
107        gutils.enable_supl_mode(self.ad)
108        gutils.enable_vendor_orbit_assistance_data(self.ad)
109        gutils.disable_ramdump(self.ad)
110        gutils.enable_compact_and_particle_fusion_log(self.ad)
111
112    def setup_test(self):
113        log_current_epoch_time(self.ad, "test_start_time")
114        log_testtracker_uuid(self.ad, self.current_test_name)
115        get_baseband_and_gms_version(self.ad)
116        if self.collect_logs:
117            clear_logd_gnss_qxdm_log(self.ad)
118        if self.set_attenuator:
119            set_attenuator_gnss_signal(self.ad, self.attenuators,
120                                       self.default_gnss_signal_attenuation)
121        # TODO (b/202101058:chenstanley): Need to double check how to disable wifi successfully in wearable projects.
122        if is_wearable_btwifi(self.ad):
123            wifi_toggle_state(self.ad, True)
124            connect_to_wifi_network(
125                self.ad, self.ssid_map[self.pixel_lab_network[0]["SSID"]])
126        else:
127            wifi_toggle_state(self.ad, False)
128            set_mobile_data(self.ad, True)
129
130        if not verify_internet_connection(self.ad.log, self.ad, retries=3,
131                                          expected_state=True):
132            raise signals.TestFailure("Fail to connect to LTE network.")
133
134    def teardown_test(self):
135        if self.collect_logs:
136            gutils.stop_pixel_logger(self.ad)
137            stop_adb_tcpdump(self.ad)
138        if self.set_attenuator:
139            set_attenuator_gnss_signal(self.ad, self.attenuators,
140                                       self.default_gnss_signal_attenuation)
141        # TODO(chenstanley): sim structure issue
142        if not is_device_wearable(self.ad):
143            if check_call_state_connected_by_adb(self.ad):
144                hangup_call(self.ad.log, self.ad)
145        if self.ad.droid.connectivityCheckAirplaneMode():
146            self.ad.log.info("Force airplane mode off")
147            toggle_airplane_mode(self.ad.log, self.ad, new_state=False)
148        if int(self.ad.adb.shell(
149            "settings get global wifi_scan_always_enabled")) != 1:
150            set_wifi_and_bt_scanning(self.ad, True)
151        log_current_epoch_time(self.ad, "test_end_time")
152
153    def keep_logs(self):
154        # for debug cs is faster than ws issue
155        test_name = self.test_name
156        self.ad.take_bug_report(test_name, self.begin_time)
157        get_gnss_qxdm_log(self.ad, self.qdsp6m_path)
158        get_tcpdump_log(self.ad, test_name, self.begin_time)
159
160    def on_fail(self, test_name, begin_time):
161        if self.collect_logs:
162            self.ad.take_bug_report(test_name, begin_time)
163            get_gnss_qxdm_log(self.ad, self.qdsp6m_path)
164            get_tcpdump_log(self.ad, test_name, begin_time)
165
166    def push_gnss_cfg(self):
167        """Push required GNSS cfg file to DUT for PixelLogger to use as
168        default GNSS logging mask."""
169        gnss_cfg_path = "/vendor/etc/mdlog"
170        gnss_cfg_file = self.user_params.get("gnss_cfg")
171        if isinstance(gnss_cfg_file, list):
172            gnss_cfg_file = gnss_cfg_file[0]
173        os.system("chmod -R 777 %s" % gnss_cfg_file)
174        self.ad.log.info("GNSS Required CFG = %s" % gnss_cfg_file)
175        self.ad.log.info("Push %s to %s" % (gnss_cfg_file, gnss_cfg_path))
176        self.ad.push_system_file(gnss_cfg_file, gnss_cfg_path)
177
178    def flash_new_radio_or_mbn(self):
179        paths = {}
180        path = self.user_params.get("radio_image")
181        if isinstance(path, list):
182            path = path[0]
183        if not path or "dev/null" in path:
184            self.ad.log.info("Radio image path is not defined in Test flag.")
185            return False
186        for path_key in os.listdir(path):
187            if fnmatch.fnmatch(path_key, "*.img"):
188                paths["radio_image"] = os.path.join(path, path_key)
189                os.system("chmod -R 777 %s" % paths["radio_image"])
190                self.ad.log.info("radio_image = %s" % paths["radio_image"])
191            if fnmatch.fnmatch(path_key, "*.zip"):
192                zip_path = os.path.join(path, path_key)
193                self.ad.log.info("Unzip %s", zip_path)
194                dest_path = os.path.join(path, "mbn")
195                unzip_maintain_permissions(zip_path, dest_path)
196                paths["mbn_path"] = dest_path
197                os.system("chmod -R 777 %s" % paths["mbn_path"])
198                self.ad.log.info("mbn_path = %s" % paths["mbn_path"])
199                self.ad.log.info(os.listdir(paths["mbn_path"]))
200        if not paths.get("radio_image"):
201            self.ad.log.info("No radio image is provided on X20. "
202                             "Skip flashing radio step.")
203            return False
204        else:
205            get_baseband_and_gms_version(self.ad, "Before flash radio")
206            flash_radio(self.ad, paths["radio_image"])
207            get_baseband_and_gms_version(self.ad, "After flash radio")
208        if not paths.get("mbn_path"):
209            self.ad.log.info("No need to push mbn files")
210            return False
211        else:
212            try:
213                mcfg_ver = self.ad.adb.shell(
214                    "cat /vendor/rfs/msm/mpss/readonly/vendor/mbn/mcfg.version")
215                if mcfg_ver:
216                    self.ad.log.info("Before push mcfg, mcfg.version = %s",
217                                     mcfg_ver)
218                else:
219                    self.ad.log.info("There is no mcfg.version before push, "
220                                     "unmatching device")
221                    return False
222            except Exception as e:
223                self.ad.log.info("There is no mcfg.version before push, "
224                                 "unmatching device %s" % e)
225                return False
226            get_baseband_and_gms_version(self.ad, "Before push mcfg")
227            try:
228                remount_device(self.ad)
229                cmd = "%s %s" % (paths["mbn_path"]+"/.",
230                                 "/vendor/rfs/msm/mpss/readonly/vendor/mbn/")
231                out = self.ad.adb.push(cmd)
232                self.ad.log.info(out)
233                reboot(self.ad)
234            except Exception as e:
235                self.ad.log.error("Push mbn files error %s", e)
236                return False
237            get_baseband_and_gms_version(self.ad, "After push mcfg")
238            try:
239                new_mcfg_ver = self.ad.adb.shell(
240                    "cat /vendor/rfs/msm/mpss/readonly/vendor/mbn/mcfg.version")
241                if new_mcfg_ver:
242                    self.ad.log.info("New mcfg.version = %s", new_mcfg_ver)
243                    if new_mcfg_ver == mcfg_ver:
244                        self.ad.log.error("mcfg.version is the same before and "
245                                          "after push")
246                        return True
247                else:
248                    self.ad.log.error("Unable to get new mcfg.version")
249                    return False
250            except Exception as e:
251                self.ad.log.error("cat mcfg.version with error %s", e)
252                return False
253
254    def standalone_ttff_airplane_mode_on(self, mode, criteria):
255        """Verify Standalone GNSS TTFF functionality while airplane mode is on.
256
257        Args:
258            mode: "cs", "ws" or "hs"
259            criteria: Criteria for the test.
260        """
261        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
262        self.ad.log.info("Turn airplane mode on")
263        toggle_airplane_mode(self.ad.log, self.ad, new_state=True)
264        """
265        The change for arguments here is for b/277667310
266        Randomized interval is used for breaking CS GLNS only fix sequence.
267        """
268        gutils.run_ttff_via_gtw_gpstool(
269            self.ad,
270            mode,
271            criteria,
272            self.ttff_test_cycle,
273            self.pixel_lab_location,
274            raninterval=True,
275            mininterval=15,
276            maxinterval=20,)
277
278    """ Test Cases """
279
280    def test_cs_first_fixed_system_server_restart(self):
281        """Verify cs first fixed after system server restart.
282
283        Steps:
284            1. Get location fixed within supl_cs_criteria.
285            2. Restarts android runtime.
286            3. Get location fixed within supl_cs_criteria.
287
288        Expected Results:
289            Location fixed within supl_cs_criteria.
290        """
291        overall_test_result = []
292        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
293        for test_loop in range(1, 6):
294            gutils.process_gnss_by_gtw_gpstool(self.ad, self.supl_cs_criteria)
295            gutils.start_gnss_by_gtw_gpstool(self.ad, False)
296            self.ad.restart_runtime()
297            self.ad.unlock_screen(password=None)
298            test_result = gutils.process_gnss_by_gtw_gpstool(self.ad, self.supl_cs_criteria)
299            gutils.start_gnss_by_gtw_gpstool(self.ad, False)
300            self.ad.log.info("Iteration %d => %s" % (test_loop, test_result))
301            overall_test_result.append(test_result)
302
303        asserts.assert_true(all(overall_test_result),
304                            "SUPL fail after system server restart.")
305
306    def test_recovery_and_location_time_after_gnss_services_restart(self):
307        """Verify gpsd recover time after gpsd being killed.
308
309        Steps:
310            1. Start GPS tracking
311            2. Restart GPS daemons by killing PID.
312            3. Waiting for GPS service to restart
313            4. Waiting for the first fixed
314            4. Re-run steps 1~4 for 5 times.
315
316        Expected Results:
317            1. The time GPSd services take to restart must be within 3 seconds.
318            2. Location fix time must be within supl_hs_criteria
319        """
320        if gutils.check_chipset_vendor_by_qualcomm(self.ad):
321            raise signals.TestSkip("Skip the test due to Qualcomm chipset")
322        test_times = 5
323        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
324        satellite_times = defaultdict(list)
325        location_fix_times = defaultdict(list)
326
327        kill_functions = (
328            gutils.get_gps_process_and_kill_function_by_vendor(self.ad))
329        for time in range(1, test_times+1):
330            self.ad.log.info("Performing test times %d", time)
331            first_fixed_time = process_gnss_by_gtw_gpstool(
332                self.ad,
333                criteria=self.supl_hs_criteria,
334                clear_data=False)
335
336            begin_time = int(first_fixed_time.timestamp() * 1000)
337            self.ad.log.info("Start tracking")
338            gutils.wait_n_mins_for_gnss_tracking(self.ad,
339                                                 begin_time,
340                                                 testtime=0.5,
341                                                 ignore_hal_crash=False)
342
343
344            for num, (process, kill_function) in enumerate(kill_functions.items()):
345                kill_start_time = kill_function()
346                first_gpsd_update_time = (gutils.get_gpsd_update_time(
347                    self.ad,
348                    kill_start_time))
349                self.ad.log.info("Resume tracking ... ")
350                gutils.wait_n_mins_for_gnss_tracking(self.ad,
351                                                     begin_time,
352                                                     testtime=num+1,
353                                                     ignore_hal_crash=True)
354
355                location_fix_time = (gutils.
356                                     get_location_fix_time_via_gpstool_log(
357                                         self.ad, first_gpsd_update_time))
358
359                satellite_times[process].append(first_gpsd_update_time - kill_start_time)
360                location_fix_times[process].append(location_fix_time - first_gpsd_update_time)
361                # gpsd recovery time : Time between gpsd killed to first satellite update.
362                self.ad.log.info("%s recovery time : %d ms",
363                                 process, (first_gpsd_update_time - kill_start_time))
364                # TTFF Hot Start : Time between first satellite update to first location fix.
365                self.ad.log.info("TTFF Hot Start %d ms",
366                                 (location_fix_time - first_gpsd_update_time))
367            start_gnss_by_gtw_gpstool(self.ad, state=False)
368
369        for num, process in enumerate(kill_functions):
370            prop_basename = gutils.UPLOAD_TO_SPONGE_PREFIX + f"{process}_recovery_time_"
371            self.ad.log.info(prop_basename + "AVG %d",
372                             mean(satellite_times[process]))
373            self.ad.log.info(prop_basename + "MAX %d",
374                             max(satellite_times[process]))
375            prop_basename = gutils.UPLOAD_TO_SPONGE_PREFIX + f"{process}_ttff_hs_"
376            self.ad.log.info(prop_basename + "AVG %d",
377                             mean(location_fix_times[process]))
378            self.ad.log.info(prop_basename + "MAX %d",
379                             max(location_fix_times[process]))
380            asserts.assert_true(mean(satellite_times[process])/1000 <=
381                                self.first_satellite_criteria,
382                                f"{process} takes more than {self.first_satellite_criteria}"
383                                "seconds in average to recover")
384            asserts.assert_true(mean(location_fix_times[process])/1000 <=
385                                self.supl_hs_criteria,
386                                f"Location fix time is more than {self.supl_hs_criteria}"
387                                "seconds in average")
388
389    def test_gnss_one_hour_tracking(self):
390        """Verify GNSS tracking performance of signal strength and position
391        error.
392
393        Steps:
394            1. Launch GTW_GPSTool.
395            2. GNSS tracking for 60 minutes.
396
397        Expected Results:
398            DUT could finish 60 minutes test and output track data.
399        """
400        test_time = 60
401        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
402        gnss_tracking_via_gtw_gpstool(self.ad, self.standalone_cs_criteria,
403                                      api_type="gnss", testtime=test_time)
404        location_data = parse_gtw_gpstool_log(self.ad, self.pixel_lab_location, api_type="gnss")
405        gutils.validate_location_fix_rate(self.ad, location_data, run_time=test_time,
406                                          fix_rate_criteria=0.99)
407        gutils.verify_gps_time_should_be_close_to_device_time(self.ad, location_data)
408
409    def test_duty_cycle_function(self):
410        """Verify duty cycle Functionality.
411
412        Steps:
413            1. Launch GTW_GPSTool.
414            2. Enable GnssMeasurement.
415            3. GNSS tracking for 5 minutes.
416            4. Calculate the count diff of "HardwareClockDiscontinuityCount"
417
418        Expected Results:
419            Duty cycle should be engaged in 5 minutes GNSS tracking.
420        """
421        tracking_minutes = 5
422        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
423        dpo_begin_time = get_current_epoch_time()
424        gnss_tracking_via_gtw_gpstool(self.ad,
425                                      self.standalone_cs_criteria,
426                                      api_type="gnss",
427                                      testtime=tracking_minutes,
428                                      meas_flag=True)
429        if gutils.check_chipset_vendor_by_qualcomm(self.ad):
430            gutils.check_dpo_rate_via_gnss_meas(self.ad,
431                                                dpo_begin_time,
432                                                self.dpo_threshold)
433        else:
434            gutils.check_dpo_rate_via_brcm_log(self.ad,
435                                               self.dpo_threshold,
436                                               self.brcm_error_log_allowlist)
437
438    def test_gnss_init_error(self):
439        """Check if there is any GNSS initialization error after reboot.
440
441        Steps:
442            1. Reboot DUT.
443            2. Check logcat if the following error pattern shows up.
444              "E LocSvc.*", ".*avc.*denied.*u:r:location:s0",
445              ".*avc.*denied.*u:r:hal_gnss_qti:s0"
446
447        Expected Results:
448            There should be no GNSS initialization error after reboot.
449        """
450        error_mismatch = True
451        for attr in self.gnss_init_error_list:
452            error = self.ad.adb.shell("logcat -d | grep -E '%s'" % attr)
453            if error:
454                for allowlist in self.gnss_init_error_allowlist:
455                    if allowlist in error:
456                        error = re.sub(".*"+allowlist+".*\n?", "", error)
457                        self.ad.log.info("\"%s\" is in allow-list and removed "
458                                         "from error." % allowlist)
459                if error:
460                    error_mismatch = False
461                    self.ad.log.error("\n%s" % error)
462            else:
463                self.ad.log.info("NO \"%s\" initialization error found." % attr)
464        asserts.assert_true(error_mismatch, "Error message found after GNSS "
465                                            "init")
466
467    def test_sap_valid_modes(self):
468        """Verify SAP Valid Modes.
469
470        Steps:
471            1. Root DUT.
472            2. Check SAP Valid Modes.
473
474        Expected Results:
475            SAP=PREMIUM
476        """
477        if not gutils.check_chipset_vendor_by_qualcomm(self.ad):
478            raise signals.TestSkip("Not Qualcomm chipset. Skip the test.")
479        sap_state = str(self.ad.adb.shell("cat vendor/etc/izat.conf | grep "
480                                          "SAP="))
481        self.ad.log.info("SAP Valid Modes - %s" % sap_state)
482        asserts.assert_true("SAP=PREMIUM" in sap_state,
483                            "Wrong SAP Valid Modes is set")
484
485    def test_network_location_provider_cell(self):
486        """Verify LocationManagerService API reports cell Network Location.
487
488        Steps:
489            1. WiFi scanning and Bluetooth scanning in Location Setting are OFF.
490            2. Launch GTW_GPSTool.
491            3. Verify whether test devices could report cell Network Location.
492            4. Repeat Step 2. to Step 3. for 5 times.
493
494        Expected Results:
495            Test devices could report cell Network Location.
496        """
497        test_result_all = []
498        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
499        set_wifi_and_bt_scanning(self.ad, False)
500        for i in range(1, 6):
501            test_result = check_network_location(
502                self.ad, retries=3, location_type="cell")
503            test_result_all.append(test_result)
504            self.ad.log.info("Iteration %d => %s" % (i, test_result))
505        set_wifi_and_bt_scanning(self.ad, True)
506        asserts.assert_true(all(test_result_all),
507                            "Fail to get networkLocationType=cell")
508
509    def test_network_location_provider_wifi(self):
510        """Verify LocationManagerService API reports wifi Network Location.
511
512        Steps:
513            1. WiFi scanning and Bluetooth scanning in Location Setting are ON.
514            2. Launch GTW_GPSTool.
515            3. Verify whether test devices could report wifi Network Location.
516            4. Repeat Step 2. to Step 3. for 5 times.
517
518        Expected Results:
519            Test devices could report wifi Network Location.
520        """
521        test_result_all = []
522        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
523        set_wifi_and_bt_scanning(self.ad, True)
524        for i in range(1, 6):
525            test_result = check_network_location(
526                self.ad, retries=3, location_type="wifi")
527            test_result_all.append(test_result)
528            self.ad.log.info("Iteration %d => %s" % (i, test_result))
529        asserts.assert_true(all(test_result_all),
530                            "Fail to get networkLocationType=wifi")
531
532    def test_gmap_location_report_battery_saver(self):
533        """Verify GnssLocationProvider API reports location to Google Map
534           when Battery Saver is enabled.
535
536        Steps:
537            1. GPS and NLP are on.
538            2. Enable Battery Saver.
539            3. Launch Google Map.
540            4. Verify whether test devices could report location.
541            5. Repeat Step 3. to Step 4. for 5 times.
542            6. Disable Battery Saver.
543
544        Expected Results:
545            Test devices could report location to Google Map.
546        """
547        test_result_all = []
548        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
549        set_battery_saver_mode(self.ad, True)
550        for i in range(1, 6):
551            grant_location_permission(self.ad, True)
552            launch_google_map(self.ad)
553            test_result = check_location_api(self.ad, retries=3)
554            self.ad.send_keycode("HOME")
555            test_result_all.append(test_result)
556            self.ad.log.info("Iteration %d => %s" % (i, test_result))
557        set_battery_saver_mode(self.ad, False)
558        asserts.assert_true(all(test_result_all), "Fail to get location update")
559
560    def test_gnss_ttff_cs_airplane_mode_on(self):
561        """Verify Standalone GNSS functionality of TTFF Cold Start while
562        airplane mode is on.
563
564        Steps:
565            1. Turn on airplane mode.
566            2. TTFF Cold Start for 10 iteration.
567
568        Expected Results:
569            All Standalone TTFF Cold Start results should be within
570            standalone_cs_criteria.
571        """
572        self.standalone_ttff_airplane_mode_on("cs", self.standalone_cs_criteria)
573
574    def test_gnss_ttff_ws_airplane_mode_on(self):
575        """Verify Standalone GNSS functionality of TTFF Warm Start while
576        airplane mode is on.
577
578        Steps:
579            1. Turn on airplane mode.
580            2. TTFF Warm Start for 10 iteration.
581
582        Expected Results:
583            All Standalone TTFF Warm Start results should be within
584            standalone_ws_criteria.
585        """
586        self.standalone_ttff_airplane_mode_on("ws", self.standalone_ws_criteria)
587
588    def test_gnss_ttff_hs_airplane_mode_on(self):
589        """Verify Standalone GNSS functionality of TTFF Hot Start while
590        airplane mode is on.
591
592        Steps:
593            1. Turn on airplane mode.
594            2. TTFF Hot Start for 10 iteration.
595
596        Expected Results:
597            All Standalone TTFF Hot Start results should be within
598            standalone_hs_criteria.
599        """
600        self.standalone_ttff_airplane_mode_on("hs", self.standalone_hs_criteria)
601
602    def test_cs_ttff_in_weak_gnss_signal(self):
603        """Verify TTFF cold start under weak GNSS signal.
604
605        Steps:
606            1. Set attenuation value to weak GNSS signal.
607            2. TTFF Cold Start for 10 iteration.
608
609        Expected Results:
610            TTFF CS results should be within weak_signal_cs_criteria.
611        """
612        gutils.set_attenuator_gnss_signal(self.ad, self.attenuators,
613                                          self.weak_gnss_signal_attenuation)
614        gutils.run_ttff(self.ad, mode="cs", criteria=self.weak_signal_cs_criteria,
615                        test_cycle=self.ttff_test_cycle, base_lat_long=self.pixel_lab_location,
616                        collect_logs=self.collect_logs)
617
618    def test_ws_ttff_in_weak_gnss_signal(self):
619        """Verify TTFF warm start under weak GNSS signal.
620
621        Steps:
622            2. Set attenuation value to weak GNSS signal.
623            3. TTFF Warm Start for 10 iteration.
624
625        Expected Results:
626            TTFF WS result should be within weak_signal_criteria.
627        """
628        gutils.set_attenuator_gnss_signal(self.ad, self.attenuators,
629                                          self.weak_gnss_signal_attenuation)
630        gutils.run_ttff(self.ad, mode="ws", criteria=self.weak_signal_criteria,
631                        test_cycle=self.ttff_test_cycle, base_lat_long=self.pixel_lab_location,
632                        collect_logs=self.collect_logs)
633
634    def test_hs_ttff_in_weak_gnss_signal(self):
635        """Verify TTFF hot start under weak GNSS signal.
636
637        Steps:
638            2. Set attenuation value to weak GNSS signal.
639            3. TTFF Hot Start for 10 iteration.
640
641        Expected Results:
642            TTFF HS result should be within weak_signal_criteria.
643        """
644        gutils.set_attenuator_gnss_signal(self.ad, self.attenuators,
645                                          self.weak_gnss_signal_attenuation)
646        gutils.run_ttff(self.ad, mode="hs", criteria=self.weak_signal_criteria,
647                        test_cycle=self.ttff_test_cycle, base_lat_long=self.pixel_lab_location,
648                        collect_logs=self.collect_logs)
649
650    def test_quick_toggle_gnss_state(self):
651        """Verify GNSS can still work properly after quick toggle GNSS off
652        to on.
653
654        Steps:
655            1. Launch GTW_GPSTool.
656            2. Go to "Advance setting"
657            3. Set Cycle = 10 & Time-out = 60
658            4. Go to "Toggle GPS" tab
659            5. Execute "Start"
660
661        Expected Results:
662            No single Timeout is seen in 10 iterations.
663        """
664        gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
665        start_toggle_gnss_by_gtw_gpstool(
666            self.ad, iteration=self.ttff_test_cycle)
667
668    def test_gnss_init_after_reboot(self):
669        """Verify SUPL and XTRA/LTO functionality after reboot.
670
671        Steps:
672            1. Get location fixed within supl_cs_criteria.
673            2. Reboot DUT.
674            3. Get location fixed within supl_hs_criteria.
675            4. Repeat Step 2. to Step 3. for 10 times.
676
677        Expected Results:
678            Location fixed within supl_hs_criteria.
679        """
680        overall_test_result = []
681        # As b/252971345 requests, we need the log before reboot for debugging.
682        gutils.start_pixel_logger(self.ad)
683        process_gnss_by_gtw_gpstool(self.ad, self.supl_cs_criteria)
684        start_gnss_by_gtw_gpstool(self.ad, False)
685        gutils.stop_pixel_logger(self.ad)
686        for test_loop in range(1, 11):
687            reboot(self.ad)
688            gutils.start_qxdm_and_tcpdump_log(self.ad, self.collect_logs)
689            if is_device_wearable(self.ad):
690                test_result = process_gnss_by_gtw_gpstool(
691                    self.ad, self.wearable_reboot_hs_criteria, clear_data=False)
692            else:
693                test_result = process_gnss_by_gtw_gpstool(
694                    self.ad, self.supl_hs_criteria, clear_data=False)
695            start_gnss_by_gtw_gpstool(self.ad, False)
696            self.ad.log.info("Iteration %d => %s" % (test_loop, test_result))
697            overall_test_result.append(test_result)
698            gutils.stop_pixel_logger(self.ad)
699            stop_adb_tcpdump(self.ad)
700        pass_rate = overall_test_result.count(True)/len(overall_test_result)
701        self.ad.log.info("TestResult Pass_rate %s" % format(pass_rate, ".0%"))
702        asserts.assert_true(all(overall_test_result),
703                            "GNSS init fail after reboot.")
704
705    def test_host_gnssstatus_validation(self):
706        """Verify GnssStatus integrity during host tracking for 1 minute.
707
708        Steps:
709            1. Launch GTW_GPSTool.
710            2. GNSS tracking for 1 minute with 1 second frequency.
711            3. Validate all the GnssStatus raw data.(SV, SVID, Elev, Azim)
712
713        Expected Results:
714            GnssStatus obj should return no failures
715        """
716        gnss_tracking_via_gtw_gpstool(self.ad, self.standalone_cs_criteria,
717                                      api_type="gnss", testtime=1)
718        parse_gtw_gpstool_log(self.ad, self.pixel_lab_location, api_type="gnss",
719                              validate_gnssstatus=True)
720
721    def test_onchip_gnssstatus_validation(self):
722        """Verify GnssStatus integrity during onchip tracking for 1 minute.
723
724        Steps:
725            1. Launch GTW_GPSTool.
726            2. GNSS tracking for 1 minute with 6 second frequency.
727            3. Validate all the GnssStatus raw data.(SV, SVID, Elev, Azim)
728
729        Expected Results:
730            GnssStatus obj should return no failures
731        """
732        if gutils.check_chipset_vendor_by_qualcomm(self.ad):
733            raise signals.TestSkip("Not BRCM chipset. Skip the test.")
734        gnss_tracking_via_gtw_gpstool(self.ad, self.standalone_cs_criteria,
735                                      api_type="gnss", testtime=1, freq=self.onchip_interval)
736        parse_gtw_gpstool_log(self.ad, self.pixel_lab_location, api_type="gnss",
737                              validate_gnssstatus=True)
738
739    def test_location_update_after_resuming_from_deep_suspend(self):
740        """Verify the GPS location reported after resume from deep doze mode
741        1. Enable GPS location report for 1 min to make sure the GPS is working
742        2. Force DUT into deep doze mode for 60s
743        3. Enable GPS location report for 5 mins
744        4. Check the report frequency
745        5. Check the location fix rate
746        """
747
748        gps_enable_minutes = 1
749        gnss_tracking_via_gtw_gpstool(self.ad, criteria=self.supl_cs_criteria, api_type="gnss",
750                                      testtime=gps_enable_minutes)
751        result = parse_gtw_gpstool_log(self.ad, self.pixel_lab_location, api_type="gnss")
752        self.ad.log.debug("Location report details before deep doze")
753        self.ad.log.debug(result)
754        gutils.validate_location_fix_rate(self.ad, result, run_time=gps_enable_minutes,
755                                          fix_rate_criteria=0.95)
756
757        gutils.enter_deep_doze_mode(self.ad, lasting_time_in_seconds=60)
758
759        gps_enable_minutes = 5
760        gnss_tracking_via_gtw_gpstool(self.ad, criteria=self.supl_cs_criteria, api_type="gnss",
761                                      testtime=gps_enable_minutes)
762        result = parse_gtw_gpstool_log(self.ad, self.pixel_lab_location, api_type="gnss")
763        self.ad.log.debug("Location report details after deep doze")
764        self.ad.log.debug(result)
765
766        location_report_time = list(result.keys())
767        gutils.check_location_report_interval(self.ad, location_report_time,
768                                              gps_enable_minutes * 60, tolerance=0.01)
769        gutils.validate_location_fix_rate(self.ad, result, run_time=gps_enable_minutes,
770                                          fix_rate_criteria=0.99)
771
772    def test_location_mode_in_battery_saver_with_screen_off(self):
773        """Ensure location request with foreground permission can work
774        in battery saver mode (screen off)
775
776        1. unplug power
777        2. enter battery saver mode
778        3. start tracking for 2 mins with screen off
779        4. repest step 3 for 3 times
780        """
781        try:
782            gutils.set_battery_saver_mode(self.ad, state=True)
783            test_time = 2
784            for i in range(1, 4):
785                self.ad.log.info("Tracking attempt %s" % str(i))
786                gnss_tracking_via_gtw_gpstool(
787                    self.ad, criteria=self.supl_cs_criteria, api_type="gnss", testtime=test_time,
788                    is_screen_off=True)
789                result = parse_gtw_gpstool_log(self.ad, self.pixel_lab_location, api_type="gnss")
790                gutils.validate_location_fix_rate(self.ad, result, run_time=test_time,
791                                                  fix_rate_criteria=0.99)
792        finally:
793            gutils.set_battery_saver_mode(self.ad, state=False)
794
795    def test_measure_adr_rate_after_10_mins_tracking(self):
796        """Verify ADR rate
797
798        1. Enable "Force full gnss measurement"
799        2. Start tracking with GnssMeasurement enabled for 10 mins
800        3. Check ADR usable rate / valid rate
801        4. Disable "Force full gnss measurement"
802        """
803        adr_threshold = self.adr_ratio_threshold.get(self.ad.model)
804        if not adr_threshold:
805            self.ad.log.warn((f"Can't get '{self.ad.model}' threshold from config "
806                              f"{self.adr_ratio_threshold}, use default threshold 0.5"))
807            adr_threshold = 0.5
808        with gutils.full_gnss_measurement(self.ad):
809            gnss_tracking_via_gtw_gpstool(self.ad, criteria=self.supl_cs_criteria, api_type="gnss",
810                                          testtime=10, meas_flag=True)
811            gutils.validate_adr_rate(self.ad, pass_criteria=float(adr_threshold))
812
813
814    def test_hal_crashing_should_resume_tracking(self):
815        """Make sure location request can be resumed after HAL restart.
816
817        1. Start GPS tool and get First Fixed
818        2. Wait for 1 min for tracking
819        3. Restart HAL service
820        4. Wait for 1 min for tracking
821        5. Check fix rate
822        """
823
824        first_fixed_time = process_gnss_by_gtw_gpstool(self.ad, criteria=self.supl_cs_criteria)
825        begin_time = int(first_fixed_time.timestamp() * 1000)
826
827        self.ad.log.info("Start 2 mins tracking")
828
829        gutils.wait_n_mins_for_gnss_tracking(self.ad, begin_time, testtime=1,
830                                             ignore_hal_crash=False)
831        gutils.restart_hal_service(self.ad)
832        # The test case is designed to run the tracking for 2 mins, so we assign testime to 2 to
833        # indicate the total run time is 2 mins (starting from begin_time).
834        gutils.wait_n_mins_for_gnss_tracking(self.ad, begin_time, testtime=2, ignore_hal_crash=True)
835
836        start_gnss_by_gtw_gpstool(self.ad, state=False)
837
838        result = parse_gtw_gpstool_log(self.ad, self.pixel_lab_location)
839        gutils.validate_location_fix_rate(self.ad, result, run_time=2,
840                                          fix_rate_criteria=0.95)
841
842
843    def test_power_save_mode_should_apply_latest_measurement_setting(self):
844        """Ensure power save mode will apply the GNSS measurement setting.
845
846        1. Turn off full GNSS measurement.
847        2. Run tracking for 2 mins
848        3. Check the power save mode status
849        4. Turn on full GNSS measurement and re-register measurement callback
850        6. Run tracking for 30s
851        7. Check the power save mode status
852        8. Turn off full GNSS measurement and re-register measurement callback
853        9. Run tracking for 2 mins
854        10. Check the power save mode status
855        """
856        def wait_for_power_state_changes(wait_time):
857            gutils.re_register_measurement_callback(self.ad)
858            tracking_begin_time = get_current_epoch_time()
859            gutils.wait_n_mins_for_gnss_tracking(self.ad, tracking_begin_time, testtime=wait_time)
860            return tracking_begin_time
861
862        if self.ad.model.lower() == "sunfish":
863            raise signals.TestSkip(
864                "According to b/241049795, it's HW issue and won't be fixed.")
865
866        gutils.start_pixel_logger(self.ad)
867        with gutils.run_gnss_tracking(self.ad, criteria=self.supl_cs_criteria, meas_flag=True):
868            start_time = wait_for_power_state_changes(wait_time=2)
869            gutils.check_power_save_mode_status(
870                self.ad, full_power=False, begin_time=start_time,
871                brcm_error_allowlist=self.brcm_error_log_allowlist)
872
873            with gutils.full_gnss_measurement(self.ad):
874                start_time = wait_for_power_state_changes(wait_time=0.5)
875                gutils.check_power_save_mode_status(
876                    self.ad, full_power=True, begin_time=start_time,
877                    brcm_error_allowlist=self.brcm_error_log_allowlist)
878
879            start_time = wait_for_power_state_changes(wait_time=2)
880            gutils.check_power_save_mode_status(
881                self.ad, full_power=False, begin_time=start_time,
882                brcm_error_allowlist=self.brcm_error_log_allowlist)
883
884        gutils.stop_pixel_logger(self.ad)
885
886    def test_the_diff_of_gps_clock_and_elapsed_realtime_should_be_stable(self):
887        gutils.start_pixel_logger(self.ad)
888        with gutils.full_gnss_measurement(self.ad):
889            first_fixed_time = gnss_tracking_via_gtw_gpstool(
890                self.ad, criteria=self.supl_cs_criteria, api_type="gnss",
891                testtime=5, meas_flag=True)
892        gutils.stop_pixel_logger(self.ad)
893        start_time = first_fixed_time + datetime.timedelta(
894            seconds=time.timezone + _PPS_KICKIN_WAITING_TIME_IN_SECOND)
895        self.ad.log.debug("Start time is %s" % start_time)
896        gutils.validate_diff_of_gps_clock_elapsed_realtime(self.ad, start_time)
897