• 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
17import os
18import time
19import glob
20import errno
21from collections import namedtuple
22from pandas import DataFrame
23from acts import utils
24from acts import signals
25from acts.base_test import BaseTestClass
26from acts.controllers.gnss_lib import GnssSimulator
27from acts.context import get_current_context
28from acts_contrib.test_utils.gnss import dut_log_test_utils as diaglog
29from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
30from acts_contrib.test_utils.gnss import gnss_testlog_utils as glogutils
31from acts_contrib.test_utils.gnss.gnss_defines import DEVICE_GPSLOG_FOLDER
32from acts_contrib.test_utils.gnss.gnss_defines import GPS_PKG_NAME
33from acts_contrib.test_utils.gnss.gnss_defines import BCM_GPS_XML_PATH
34
35
36class LabTtffTestBase(BaseTestClass):
37    """ LAB TTFF Tests Base Class"""
38    GTW_GPSTOOL_APP = 'gtw_gpstool_apk'
39    GNSS_SIMULATOR_KEY = 'gnss_simulator'
40    GNSS_SIMULATOR_IP_KEY = 'gnss_simulator_ip'
41    GNSS_SIMULATOR_PORT_KEY = 'gnss_simulator_port'
42    GNSS_SIMULATOR_PORT_CTRL_KEY = 'gnss_simulator_port_ctrl'
43    GNSS_SIMULATOR_SCENARIO_KEY = 'gnss_simulator_scenario'
44    GNSS_SIMULATOR_POWER_LEVEL_KEY = 'gnss_simulator_power_level'
45    CUSTOM_FILES_KEY = 'custom_files'
46    CSTTFF_CRITERIA = 'cs_criteria'
47    HSTTFF_CRITERIA = 'hs_criteria'
48    WSTTFF_CRITERIA = 'ws_criteria'
49    CSTTFF_PECRITERIA = 'cs_ttff_pecriteria'
50    HSTTFF_PECRITERIA = 'hs_ttff_pecriteria'
51    WSTTFF_PECRITERIA = 'ws_ttff_pecriteria'
52    TTFF_ITERATION = 'ttff_iteration'
53    SIMULATOR_LOCATION = 'simulator_location'
54    DIAG_OPTION = 'diag_option'
55
56    def __init__(self, controllers):
57        """ Initializes class attributes. """
58
59        super().__init__(controllers)
60
61        self.dut = None
62        self.gnss_simulator = None
63        self.rockbottom_script = None
64        self.gnss_log_path = self.log_path
65        self.gps_xml_bk_path = BCM_GPS_XML_PATH + '.bk'
66
67    def setup_class(self):
68        super().setup_class()
69
70        req_params = [
71            self.GNSS_SIMULATOR_KEY, self.GNSS_SIMULATOR_IP_KEY,
72            self.GNSS_SIMULATOR_PORT_KEY, self.GNSS_SIMULATOR_SCENARIO_KEY,
73            self.GNSS_SIMULATOR_POWER_LEVEL_KEY, self.CSTTFF_CRITERIA,
74            self.HSTTFF_CRITERIA, self.WSTTFF_CRITERIA, self.TTFF_ITERATION,
75            self.SIMULATOR_LOCATION, self.DIAG_OPTION
76        ]
77
78        self.unpack_userparams(req_param_names=req_params)
79        self.dut = self.android_devices[0]
80        self.gnss_simulator_scenario = self.user_params[
81            self.GNSS_SIMULATOR_SCENARIO_KEY]
82        self.gnss_simulator_power_level = self.user_params[
83            self.GNSS_SIMULATOR_POWER_LEVEL_KEY]
84        self.gtw_gpstool_app = self.user_params[self.GTW_GPSTOOL_APP]
85        custom_files = self.user_params.get(self.CUSTOM_FILES_KEY, [])
86        self.cs_ttff_criteria = self.user_params.get(self.CSTTFF_CRITERIA, [])
87        self.hs_ttff_criteria = self.user_params.get(self.HSTTFF_CRITERIA, [])
88        self.ws_ttff_criteria = self.user_params.get(self.WSTTFF_CRITERIA, [])
89        self.cs_ttff_pecriteria = self.user_params.get(self.CSTTFF_PECRITERIA,
90                                                       [])
91        self.hs_ttff_pecriteria = self.user_params.get(self.HSTTFF_PECRITERIA,
92                                                       [])
93        self.ws_ttff_pecriteria = self.user_params.get(self.WSTTFF_PECRITERIA,
94                                                       [])
95        self.ttff_iteration = self.user_params.get(self.TTFF_ITERATION, [])
96        self.simulator_location = self.user_params.get(self.SIMULATOR_LOCATION,
97                                                       [])
98        self.diag_option = self.user_params.get(self.DIAG_OPTION, [])
99
100        # Create gnss_simulator instance
101        gnss_simulator_key = self.user_params[self.GNSS_SIMULATOR_KEY]
102        gnss_simulator_ip = self.user_params[self.GNSS_SIMULATOR_IP_KEY]
103        gnss_simulator_port = self.user_params[self.GNSS_SIMULATOR_PORT_KEY]
104        if gnss_simulator_key == 'gss7000':
105            gnss_simulator_port_ctrl = self.user_params[
106                self.GNSS_SIMULATOR_PORT_CTRL_KEY]
107        else:
108            gnss_simulator_port_ctrl = None
109        self.gnss_simulator = GnssSimulator.AbstractGnssSimulator(
110            gnss_simulator_key, gnss_simulator_ip, gnss_simulator_port,
111            gnss_simulator_port_ctrl)
112
113        test_type = namedtuple('Type', ['command', 'criteria'])
114        self.test_types = {
115            'cs': test_type('Cold Start', self.cs_ttff_criteria),
116            'ws': test_type('Warm Start', self.ws_ttff_criteria),
117            'hs': test_type('Hot Start', self.hs_ttff_criteria)
118        }
119
120        # Unpack the rockbottom script file if its available.
121        for file in custom_files:
122            if 'rockbottom_' + self.dut.model in file:
123                self.rockbottom_script = file
124                break
125
126    def setup_test(self):
127
128        self.clear_gps_log()
129        self.gnss_simulator.stop_scenario()
130        self.gnss_simulator.close()
131        if self.rockbottom_script:
132            self.log.info('Running rockbottom script for this device ' +
133                          self.dut.model)
134            self.dut_rockbottom()
135        else:
136            self.log.info('Not running rockbottom for this device ' +
137                          self.dut.model)
138
139        utils.set_location_service(self.dut, True)
140        gutils.reinstall_package_apk(self.dut, GPS_PKG_NAME,
141                                     self.gtw_gpstool_app)
142
143        # For BCM DUTs, delete gldata.sto and set IgnoreRomAlm="true" based on b/196936791#comment20
144        if self.diag_option == "BCM":
145            gutils.remount_device(self.dut)
146            # Backup gps.xml
147            copy_cmd = "cp {} {}".format(BCM_GPS_XML_PATH, self.gps_xml_bk_path)
148            self.dut.adb.shell(copy_cmd)
149            gutils.delete_bcm_nvmem_sto_file(self.dut)
150            gutils.bcm_gps_ignore_rom_alm(self.dut)
151            # Reboot DUT to apply the setting
152            gutils.reboot(self.dut)
153        self.gnss_simulator.connect()
154
155    def dut_rockbottom(self):
156        """
157        Set the dut to rockbottom state
158
159        """
160        # The rockbottom script might include a device reboot, so it is
161        # necessary to stop SL4A during its execution.
162        self.dut.stop_services()
163        self.log.info('Executing rockbottom script for ' + self.dut.model)
164        os.chmod(self.rockbottom_script, 0o777)
165        os.system('{} {}'.format(self.rockbottom_script, self.dut.serial))
166        # Make sure the DUT is in root mode after coming back
167        self.dut.root_adb()
168        # Restart SL4A
169        self.dut.start_services()
170
171    def teardown_test(self):
172        """Teardown settings for the test class"""
173        super().teardown_test()
174        # Restore the gps.xml everytime after the test.
175        if self.diag_option == "BCM":
176            # Restore gps.xml
177            rm_cmd = "rm -rf {}".format(BCM_GPS_XML_PATH)
178            restore_cmd = "mv {} {}".format(self.gps_xml_bk_path,
179                                            BCM_GPS_XML_PATH)
180            self.dut.adb.shell(rm_cmd)
181            self.dut.adb.shell(restore_cmd)
182
183    def teardown_class(self):
184        """ Executed after completing all selected test cases."""
185        self.clear_gps_log()
186        if self.gnss_simulator:
187            self.gnss_simulator.stop_scenario()
188            self.gnss_simulator.close()
189
190    def start_and_set_gnss_simulator_power(self):
191        """
192        Start GNSS simulator secnario and set power level.
193
194        """
195
196        self.gnss_simulator.start_scenario(self.gnss_simulator_scenario)
197        time.sleep(25)
198        self.gnss_simulator.set_power(self.gnss_simulator_power_level)
199
200    def get_and_verify_ttff(self, mode):
201        """Retrieve ttff with designate mode.
202
203            Args:
204                mode: A string for identify gnss test mode.
205        """
206        if mode not in self.test_types:
207            raise signals.TestError('Unrecognized mode %s' % mode)
208        test_type = self.test_types.get(mode)
209
210        if mode != 'cs':
211            wait_time = 900
212        else:
213            wait_time = 300
214
215        gutils.process_gnss_by_gtw_gpstool(self.dut,
216                                           self.test_types['cs'].criteria)
217        begin_time = gutils.get_current_epoch_time()
218        gutils.start_ttff_by_gtw_gpstool(self.dut,
219                                         ttff_mode=mode,
220                                         iteration=self.ttff_iteration,
221                                         raninterval=True,
222                                         hot_warm_sleep=wait_time)
223        # Since Wear takes little longer to update the TTFF info.
224        # Workround to solve the wearable timing issue
225        if gutils.is_device_wearable(self.dut):
226            time.sleep(20)
227
228        ttff_data = gutils.process_ttff_by_gtw_gpstool(self.dut, begin_time,
229                                                       self.simulator_location)
230
231        # Create folder for GTW GPStool's log
232        gps_log_path = os.path.join(self.gnss_log_path, 'GPSLogs')
233        os.makedirs(gps_log_path, exist_ok=True)
234
235        self.dut.adb.pull("{} {}".format(DEVICE_GPSLOG_FOLDER, gps_log_path))
236
237        gps_api_log = glob.glob(gps_log_path + '/*/GNSS_*.txt')
238        ttff_loop_log = glob.glob(gps_log_path +
239                                  '/*/GPS_{}_*.txt'.format(mode.upper()))
240
241        if not gps_api_log and ttff_loop_log:
242            raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT),
243                                    gps_log_path)
244
245        df = DataFrame(glogutils.parse_gpstool_ttfflog_to_df(gps_api_log[0]))
246
247        ttff_dict = {}
248        for i in ttff_data:
249            d = ttff_data[i]._asdict()
250            ttff_dict[i] = dict(d)
251
252        ttff_time = []
253        ttff_pe = []
254        ttff_haccu = []
255        for i in ttff_dict.keys():
256            ttff_time.append(ttff_dict[i]['ttff_sec'])
257            ttff_pe.append(ttff_dict[i]['ttff_pe'])
258            ttff_haccu.append(ttff_dict[i]['ttff_haccu'])
259        df['ttff_sec'] = ttff_time
260        df['ttff_pe'] = ttff_pe
261        df['ttff_haccu'] = ttff_haccu
262        df.to_json(gps_log_path + '/gps_log.json', orient='table')
263        result = gutils.check_ttff_data(self.dut,
264                                        ttff_data,
265                                        ttff_mode=test_type.command,
266                                        criteria=test_type.criteria)
267        if not result:
268            raise signals.TestFailure('%s TTFF fails to reach '
269                                      'designated criteria' % test_type.command)
270        return ttff_data
271
272    def verify_pe(self, mode):
273        """
274        Verify ttff Position Error with designate mode.
275
276        Args:
277             mode: A string for identify gnss test mode.
278        """
279
280        ffpe_type = namedtuple('Type', ['command', 'pecriteria'])
281        ffpe_types = {
282            'cs': ffpe_type('Cold Start', self.cs_ttff_pecriteria),
283            'ws': ffpe_type('Warm Start', self.ws_ttff_pecriteria),
284            'hs': ffpe_type('Hot Start', self.hs_ttff_pecriteria)
285        }
286
287        if mode not in ffpe_types:
288            raise signals.TestError('Unrecognized mode %s' % mode)
289        test_type = ffpe_types.get(mode)
290
291        ttff_data = self.get_and_verify_ttff(mode)
292        result = gutils.check_ttff_pe(self.dut,
293                                      ttff_data,
294                                      ttff_mode=test_type.command,
295                                      pe_criteria=test_type.pecriteria)
296        if not result:
297            raise signals.TestFailure('%s TTFF fails to reach '
298                                      'designated criteria' % test_type.command)
299        return ttff_data
300
301    def clear_gps_log(self):
302        """
303        Delete the existing GPS GTW Log from DUT.
304
305        """
306        self.dut.adb.shell("rm -rf {}".format(DEVICE_GPSLOG_FOLDER))
307
308    def gnss_ttff_ffpe(self, mode, sub_context_path=''):
309        """
310        Base ttff and ffpe function
311            Args:
312                mode: Set the TTFF mode for testing. Definitions are as below.
313                      cs(cold start), ws(warm start), hs(hot start)
314                sub_context_path: Set specifc log pathfor ttff_ffpe
315        """
316        # Create log file path
317        full_output_path = get_current_context().get_full_output_path()
318        self.gnss_log_path = os.path.join(full_output_path, sub_context_path)
319        os.makedirs(self.gnss_log_path, exist_ok=True)
320        self.log.debug('Create log path: {}'.format(self.gnss_log_path))
321
322        # Start and set GNSS simulator
323        self.start_and_set_gnss_simulator_power()
324
325        # Start GNSS chip log
326        if self.diag_option == "QCOM":
327            diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile)
328        else:
329            gutils.start_pixel_logger(self.dut)
330
331        # Start verifying TTFF and FFPE
332        self.verify_pe(mode)
333
334        # Set gnss_vendor_log_path based on GNSS solution vendor
335        gnss_vendor_log_path = os.path.join(self.gnss_log_path,
336                                            self.diag_option)
337        os.makedirs(gnss_vendor_log_path, exist_ok=True)
338
339        # Stop GNSS chip log and pull the logs to local file system
340        if self.diag_option == "QCOM":
341            diaglog.stop_background_diagmdlog(self.dut,
342                                              gnss_vendor_log_path,
343                                              keep_logs=False)
344        else:
345            gutils.stop_pixel_logger(self.dut)
346            self.log.info('Getting Pixel BCM Log!')
347            diaglog.get_pixellogger_bcm_log(self.dut,
348                                            gnss_vendor_log_path,
349                                            keep_logs=False)
350