blob: 50ef6dcae5451372bc3714eae66383908bd12ce3 [file] [log] [blame]
Qi Jiang73b25352017-08-02 19:56:31 +00001#!/usr/bin/env python3.4
2#
3# Copyright 2017 Google, Inc.
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 logging
18import os
19import time
Qi Jiang8f9c7582017-09-06 21:00:14 +000020from acts import asserts
Qi Jiang73b25352017-08-02 19:56:31 +000021from acts import utils
22from acts.controllers import monsoon
Qi Jiangcaca55e2017-10-10 23:10:40 +000023from acts.libs.proc import job
Qi Jiang73b25352017-08-02 19:56:31 +000024from acts.test_utils.wifi import wifi_test_utils as wutils
Qi Jiang8f9c7582017-09-06 21:00:14 +000025from bokeh.layouts import layout
Qi Jiang73b25352017-08-02 19:56:31 +000026from bokeh.models import CustomJS, ColumnDataSource
Omar El Ayachf4f132b2018-01-26 03:37:08 +000027from bokeh.models import tools as bokeh_tools
Qi Jiang73b25352017-08-02 19:56:31 +000028from bokeh.models.widgets import DataTable, TableColumn
Qi Jiang8f9c7582017-09-06 21:00:14 +000029from bokeh.plotting import figure, output_file, save
Qi Jiang73b25352017-08-02 19:56:31 +000030from acts.controllers.ap_lib import hostapd_security
31from acts.controllers.ap_lib import hostapd_ap_preset
Daniel Barros43760302017-12-06 04:16:03 +000032from acts.test_utils.bt.bt_test_utils import enable_bluetooth
33from acts.test_utils.bt.bt_test_utils import disable_bluetooth
34
Daniel Barrosfefd8c32017-08-04 15:36:40 -070035# http://www.secdev.org/projects/scapy/
36# On ubuntu, sudo pip3 install scapy-python3
37import scapy.all as scapy
Qi Jiang73b25352017-08-02 19:56:31 +000038
39SETTINGS_PAGE = "am start -n com.android.settings/.Settings"
40SCROLL_BOTTOM = "input swipe 0 2000 0 0"
41UNLOCK_SCREEN = "input keyevent 82"
42SCREENON_USB_DISABLE = "dumpsys battery unplug"
43RESET_BATTERY_STATS = "dumpsys batterystats --reset"
44AOD_OFF = "settings put secure doze_always_on 0"
45MUSIC_IQ_OFF = "pm disable-user com.google.intelligence.sense"
46# Command to disable gestures
47LIFT = "settings put secure doze_pulse_on_pick_up 0"
48DOUBLE_TAP = "settings put secure doze_pulse_on_double_tap 0"
49JUMP_TO_CAMERA = "settings put secure camera_double_tap_power_gesture_disabled 1"
50RAISE_TO_CAMERA = "settings put secure camera_lift_trigger_enabled 0"
51FLIP_CAMERA = "settings put secure camera_double_twist_to_flip_enabled 0"
52ASSIST_GESTURE = "settings put secure assist_gesture_enabled 0"
53ASSIST_GESTURE_ALERT = "settings put secure assist_gesture_silence_alerts_enabled 0"
54ASSIST_GESTURE_WAKE = "settings put secure assist_gesture_wake_enabled 0"
55SYSTEM_NAVI = "settings put secure system_navigation_keys_enabled 0"
56# End of command to disable gestures
57AUTO_TIME_OFF = "settings put global auto_time 0"
58AUTO_TIMEZONE_OFF = "settings put global auto_time_zone 0"
Qi Jiang50733382017-08-22 01:11:58 +000059FORCE_YOUTUBE_STOP = "am force-stop com.google.android.youtube"
60FORCE_DIALER_STOP = "am force-stop com.google.android.dialer"
Qi Jiang73b25352017-08-02 19:56:31 +000061IPERF_TIMEOUT = 180
Daniel Barros7cc34e82017-09-22 02:41:32 +000062THRESHOLD_TOLERANCE = 0.2
Daniel Barrosebbf91a2017-10-04 01:08:40 +000063GET_FROM_PHONE = 'get_from_dut'
64GET_FROM_AP = 'get_from_ap'
Daniel Barros35c901a2017-10-25 13:30:57 +000065PHONE_BATTERY_VOLTAGE = 4.2
66MONSOON_MAX_CURRENT = 8.0
Qi Jiang73b25352017-08-02 19:56:31 +000067
68
69def dut_rockbottom(ad):
70 """Set the phone into Rock-bottom state.
71
72 Args:
73 ad: the target android device, AndroidDevice object
74
75 """
76 ad.log.info("Now set the device to Rockbottom State")
77 utils.require_sl4a((ad, ))
Daniel Barros7cc34e82017-09-22 02:41:32 +000078 ad.droid.connectivityToggleAirplaneMode(False)
79 time.sleep(5)
80 ad.droid.connectivityToggleAirplaneMode(True)
Qi Jiang73b25352017-08-02 19:56:31 +000081 utils.set_ambient_display(ad, False)
82 utils.set_auto_rotate(ad, False)
83 utils.set_adaptive_brightness(ad, False)
84 utils.sync_device_time(ad)
85 utils.set_location_service(ad, False)
86 utils.set_mobile_data_always_on(ad, False)
87 utils.disable_doze_light(ad)
88 utils.disable_doze(ad)
89 wutils.reset_wifi(ad)
90 wutils.wifi_toggle_state(ad, False)
Qi Jiang73b25352017-08-02 19:56:31 +000091 ad.droid.nfcDisable()
92 ad.droid.setScreenBrightness(0)
93 ad.adb.shell(AOD_OFF)
94 ad.droid.setScreenTimeout(2200)
Qi Jiang73b25352017-08-02 19:56:31 +000095 ad.droid.wakeUpNow()
96 ad.adb.shell(LIFT)
97 ad.adb.shell(DOUBLE_TAP)
98 ad.adb.shell(JUMP_TO_CAMERA)
99 ad.adb.shell(RAISE_TO_CAMERA)
100 ad.adb.shell(FLIP_CAMERA)
101 ad.adb.shell(ASSIST_GESTURE)
102 ad.adb.shell(ASSIST_GESTURE_ALERT)
103 ad.adb.shell(ASSIST_GESTURE_WAKE)
104 ad.adb.shell(SCREENON_USB_DISABLE)
105 ad.adb.shell(UNLOCK_SCREEN)
106 ad.adb.shell(SETTINGS_PAGE)
107 ad.adb.shell(SCROLL_BOTTOM)
108 ad.adb.shell(MUSIC_IQ_OFF)
109 ad.adb.shell(AUTO_TIME_OFF)
110 ad.adb.shell(AUTO_TIMEZONE_OFF)
Qi Jiang50733382017-08-22 01:11:58 +0000111 ad.adb.shell(FORCE_YOUTUBE_STOP)
112 ad.adb.shell(FORCE_DIALER_STOP)
113 ad.droid.wakeUpNow()
Qi Jiang73b25352017-08-02 19:56:31 +0000114 ad.log.info('Device has been set to Rockbottom state')
Daniel Barros35c901a2017-10-25 13:30:57 +0000115 ad.log.info('Screen is ON')
Qi Jiang73b25352017-08-02 19:56:31 +0000116
117
Qi Jiang8f9c7582017-09-06 21:00:14 +0000118def pass_fail_check(test_class, test_result):
119 """Check the test result and decide if it passed or failed.
120 The threshold is provided in the config file
121
122 Args:
123 test_class: the specific test class where test is running
124 avg_current: the average current as the test result
125 """
126 test_name = test_class.current_test_name
127 current_threshold = test_class.threshold[test_name]
128 asserts.assert_true(
129 abs(test_result - current_threshold) / current_threshold <
130 THRESHOLD_TOLERANCE,
131 ("Measured average current in [%s]: %s, which is "
132 "more than %d percent off than acceptable threshold %.2fmA") %
133 (test_name, test_result, THRESHOLD_TOLERANCE * 100, current_threshold))
134 asserts.explicit_pass("Measurement finished for %s." % test_name)
135
136
Qi Jiang73b25352017-08-02 19:56:31 +0000137def monsoon_data_collect_save(ad, mon_info, test_name, bug_report):
138 """Current measurement and save the log file.
139
140 Collect current data using Monsoon box and return the path of the
141 log file. Take bug report if requested.
142
143 Args:
144 ad: the android device under test
145 mon_info: dict with information of monsoon measurement, including
146 monsoon device object, measurement frequency, duration and
147 offset etc.
148 test_name: current test name, used to contruct the result file name
149 bug_report: indicator to take bug report or not, 0 or 1
150 Returns:
151 data_path: the absolute path to the log file of monsoon current
152 measurement
153 avg_current: the average current of the test
154 """
155 log = logging.getLogger()
156 log.info("Starting power measurement with monsoon box")
157 tag = (test_name + '_' + ad.model + '_' + ad.build_info['build_id'])
158 #Resets the battery status right before the test started
159 ad.adb.shell(RESET_BATTERY_STATS)
160 begin_time = utils.get_current_human_time()
161 #Start the power measurement using monsoon
162 result = mon_info['dut'].measure_power(
163 mon_info['freq'],
164 mon_info['duration'],
165 tag=tag,
166 offset=mon_info['offset'])
167 data_path = os.path.join(mon_info['data_path'], "%s.txt" % tag)
168 avg_current = result.average_current
169 monsoon.MonsoonData.save_to_text_file([result], data_path)
170 log.info("Power measurement done")
171 if bool(bug_report) == True:
172 ad.take_bug_report(test_name, begin_time)
173 return data_path, avg_current
174
175
176def monsoon_data_plot(mon_info, file_path, tag=""):
177 """Plot the monsoon current data using bokeh interactive plotting tool.
178
179 Plotting power measurement data with bokeh to generate interactive plots.
180 You can do interactive data analysis on the plot after generating with the
181 provided widgets, which make the debugging much easier. To realize that,
182 bokeh callback java scripting is used. View a sample html output file:
183 https://drive.google.com/open?id=0Bwp8Cq841VnpT2dGUUxLYWZvVjA
184
185 Args:
186 mon_info: dict with information of monsoon measurement, including
187 monsoon device object, measurement frequency, duration and
188 offset etc.
189 file_path: the path to the monsoon log file with current data
190
191 Returns:
192 plot: the plotting object of bokeh, optional, will be needed if multiple
193 plots will be combined to one html file.
194 dt: the datatable object of bokeh, optional, will be needed if multiple
195 datatables will be combined to one html file.
196 """
197
198 log = logging.getLogger()
199 log.info("Plot the power measurement data")
200 #Get results as monsoon data object from the input file
201 results = monsoon.MonsoonData.from_text_file(file_path)
202 #Decouple current and timestamp data from the monsoon object
203 current_data = []
204 timestamps = []
205 voltage = results[0].voltage
206 [current_data.extend(x.data_points) for x in results]
207 [timestamps.extend(x.timestamps) for x in results]
208 period = 1 / float(mon_info['freq'])
209 time_relative = [x * period for x in range(len(current_data))]
210 #Calculate the average current for the test
211 current_data = [x * 1000 for x in current_data]
212 avg_current = sum(current_data) / len(current_data)
213 color = ['navy'] * len(current_data)
214
215 #Preparing the data and source link for bokehn java callback
Omar El Ayachf4f132b2018-01-26 03:37:08 +0000216 source = ColumnDataSource(data=dict(
217 x0=time_relative, y0=current_data, color=color))
218 s2 = ColumnDataSource(data=dict(
219 z0=[mon_info['duration']],
220 y0=[round(avg_current, 2)],
221 x0=[round(avg_current * voltage, 2)],
222 z1=[round(avg_current * voltage * mon_info['duration'], 2)],
223 z2=[round(avg_current * mon_info['duration'], 2)]))
Qi Jiang73b25352017-08-02 19:56:31 +0000224 #Setting up data table for the output
225 columns = [
226 TableColumn(field='z0', title='Total Duration (s)'),
227 TableColumn(field='y0', title='Average Current (mA)'),
228 TableColumn(field='x0', title='Average Power (4.2v) (mW)'),
229 TableColumn(field='z1', title='Average Energy (mW*s)'),
230 TableColumn(field='z2', title='Normalized Average Energy (mA*s)')
231 ]
232 dt = DataTable(
233 source=s2, columns=columns, width=1300, height=60, editable=True)
234
235 plot_title = file_path[file_path.rfind('/') + 1:-4] + tag
236 output_file("%s/%s.html" % (mon_info['data_path'], plot_title))
Omar El Ayachf4f132b2018-01-26 03:37:08 +0000237 TOOLS = ('box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
Qi Jiang73b25352017-08-02 19:56:31 +0000238 # Create a new plot with the datatable above
239 plot = figure(
240 plot_width=1300,
241 plot_height=700,
242 title=plot_title,
243 tools=TOOLS,
Omar El Ayachf4f132b2018-01-26 03:37:08 +0000244 output_backend="webgl")
245 plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="width"))
246 plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="height"))
Qi Jiang73b25352017-08-02 19:56:31 +0000247 plot.line('x0', 'y0', source=source, line_width=2)
248 plot.circle('x0', 'y0', source=source, size=0.5, fill_color='color')
249 plot.xaxis.axis_label = 'Time (s)'
250 plot.yaxis.axis_label = 'Current (mA)'
251 plot.title.text_font_size = {'value': '15pt'}
252
253 #Callback Java scripting
254 source.callback = CustomJS(
255 args=dict(mytable=dt),
256 code="""
257 var inds = cb_obj.get('selected')['1d'].indices;
258 var d1 = cb_obj.get('data');
259 var d2 = mytable.get('source').get('data');
260 ym = 0
261 ts = 0
262 d2['x0'] = []
263 d2['y0'] = []
264 d2['z1'] = []
265 d2['z2'] = []
266 d2['z0'] = []
267 min=max=d1['x0'][inds[0]]
268 if (inds.length==0) {return;}
269 for (i = 0; i < inds.length; i++) {
270 ym += d1['y0'][inds[i]]
271 d1['color'][inds[i]] = "red"
272 if (d1['x0'][inds[i]] < min) {
273 min = d1['x0'][inds[i]]}
274 if (d1['x0'][inds[i]] > max) {
275 max = d1['x0'][inds[i]]}
276 }
277 ym /= inds.length
278 ts = max - min
279 dx0 = Math.round(ym*4.2*100.0)/100.0
280 dy0 = Math.round(ym*100.0)/100.0
281 dz1 = Math.round(ym*4.2*ts*100.0)/100.0
282 dz2 = Math.round(ym*ts*100.0)/100.0
283 dz0 = Math.round(ts*1000.0)/1000.0
284 d2['z0'].push(dz0)
285 d2['x0'].push(dx0)
286 d2['y0'].push(dy0)
287 d2['z1'].push(dz1)
288 d2['z2'].push(dz2)
289 mytable.trigger('change');
290 """)
291
292 #Layout the plot and the datatable bar
293 l = layout([[dt], [plot]])
294 save(l)
295 return [plot, dt]
296
297
Qi Jiang43c80e12017-11-04 03:05:21 +0000298def change_dtim(ad, gEnableModulatedDTIM, gMaxLIModulatedDTIM=10):
Qi Jiang73b25352017-08-02 19:56:31 +0000299 """Function to change the DTIM setting in the phone.
300
301 Args:
302 ad: the target android device, AndroidDevice object
303 gEnableModulatedDTIM: Modulated DTIM, int
304 gMaxLIModulatedDTIM: Maximum modulated DTIM, int
305 """
306 serial = ad.serial
307 ini_file_phone = 'vendor/firmware/wlan/qca_cld/WCNSS_qcom_cfg.ini'
308 ini_file_local = 'local_ini_file.ini'
309 ini_pull_cmd = 'adb -s %s pull %s %s' % (serial, ini_file_phone,
310 ini_file_local)
311 ini_push_cmd = 'adb -s %s push %s %s' % (serial, ini_file_local,
312 ini_file_phone)
313 utils.exe_cmd(ini_pull_cmd)
314
315 with open(ini_file_local, 'r') as fin:
316 for line in fin:
317 if 'gEnableModulatedDTIM=' in line:
318 gEDTIM_old = line.strip('gEnableModulatedDTIM=').strip('\n')
319 if 'gMaxLIModulatedDTIM=' in line:
320 gMDTIM_old = line.strip('gMaxLIModulatedDTIM=').strip('\n')
Qi Jiang43c80e12017-11-04 03:05:21 +0000321 if int(gEDTIM_old) == gEnableModulatedDTIM and int(
322 gMDTIM_old) == gMaxLIModulatedDTIM:
Qi Jiang73b25352017-08-02 19:56:31 +0000323 ad.log.info('Current DTIM is already the desired value,'
324 'no need to reset it')
325 return
326
327 gE_old = 'gEnableModulatedDTIM=' + gEDTIM_old
328 gM_old = 'gMaxLIModulatedDTIM=' + gMDTIM_old
329 gE_new = 'gEnableModulatedDTIM=' + str(gEnableModulatedDTIM)
330 gM_new = 'gMaxLIModulatedDTIM=' + str(gMaxLIModulatedDTIM)
331
332 sed_gE = 'sed -i \'s/%s/%s/g\' %s' % (gE_old, gE_new, ini_file_local)
333 sed_gM = 'sed -i \'s/%s/%s/g\' %s' % (gM_old, gM_new, ini_file_local)
334 utils.exe_cmd(sed_gE)
335 utils.exe_cmd(sed_gM)
336
337 utils.exe_cmd('adb -s {} root'.format(serial))
338 cmd_out = utils.exe_cmd('adb -s {} remount'.format(serial))
339 if ("Permission denied").encode() in cmd_out:
340 ad.log.info('Need to disable verity first and reboot')
341 utils.exe_cmd('adb -s {} disable-verity'.format(serial))
342 time.sleep(1)
343 ad.reboot()
344 ad.log.info('Verity disabled and device back from reboot')
345 utils.exe_cmd('adb -s {} root'.format(serial))
346 utils.exe_cmd('adb -s {} remount'.format(serial))
347 time.sleep(1)
348 utils.exe_cmd(ini_push_cmd)
349 ad.log.info('ini file changes checked in and rebooting...')
350 ad.reboot()
351 ad.log.info('DTIM updated and device back from reboot')
352
353
Qi Jiangdc073e52017-12-19 19:12:35 +0000354def ap_setup(ap, network, bandwidth=80):
Qi Jiang73b25352017-08-02 19:56:31 +0000355 """Set up the whirlwind AP with provided network info.
356
357 Args:
358 ap: access_point object of the AP
359 network: dict with information of the network, including ssid, password
360 bssid, channel etc.
Qi Jiangdc073e52017-12-19 19:12:35 +0000361 bandwidth: the operation bandwidth for the AP, default 80MHz
Qi Jiang73b25352017-08-02 19:56:31 +0000362 """
Qi Jiang73b25352017-08-02 19:56:31 +0000363 log = logging.getLogger()
364 bss_settings = []
365 ssid = network[wutils.WifiEnums.SSID_KEY]
Qi Jiangcaca55e2017-10-10 23:10:40 +0000366 if "password" in network.keys():
367 password = network["password"]
368 security = hostapd_security.Security(
369 security_mode="wpa", password=password)
370 else:
371 security = hostapd_security.Security(security_mode=None, password=None)
Qi Jiang73b25352017-08-02 19:56:31 +0000372 channel = network["channel"]
Qi Jiang73b25352017-08-02 19:56:31 +0000373 config = hostapd_ap_preset.create_ap_preset(
374 channel=channel,
375 ssid=ssid,
376 security=security,
377 bss_settings=bss_settings,
Qi Jiangdc073e52017-12-19 19:12:35 +0000378 vht_bandwidth=bandwidth,
379 profile_name='whirlwind',
380 iface_wlan_2g=ap.wlan_2g,
381 iface_wlan_5g=ap.wlan_5g)
Qi Jiang73b25352017-08-02 19:56:31 +0000382 ap.start_ap(config)
383 log.info("AP started on channel {} with SSID {}".format(channel, ssid))
384
385
Omar El Ayachded64232017-12-08 00:53:12 +0000386def bokeh_plot(data_sets, legends, fig_property, output_file_path=None):
Qi Jiang73b25352017-08-02 19:56:31 +0000387 """Plot bokeh figs.
388 Args:
389 data_sets: data sets including lists of x_data and lists of y_data
390 ex: [[[x_data1], [x_data2]], [[y_data1],[y_data2]]]
391 legends: list of legend for each curve
392 fig_property: dict containing the plot property, including title,
393 lables, linewidth, circle size, etc.
394 Returns:
395 plot: bokeh plot figure object
396 """
Omar El Ayachf4f132b2018-01-26 03:37:08 +0000397 TOOLS = ('box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
Qi Jiang73b25352017-08-02 19:56:31 +0000398 plot = figure(
399 plot_width=1300,
400 plot_height=700,
401 title=fig_property['title'],
402 tools=TOOLS,
Omar El Ayachf4f132b2018-01-26 03:37:08 +0000403 output_backend="webgl")
404 plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="width"))
405 plot.add_tools(bokeh_tools.WheelZoomTool(dimensions="height"))
Qi Jiang73b25352017-08-02 19:56:31 +0000406 colors = [
407 'red', 'green', 'blue', 'olive', 'orange', 'salmon', 'black', 'navy',
408 'yellow', 'darkred', 'goldenrod'
409 ]
410 for x_data, y_data, legend in zip(data_sets[0], data_sets[1], legends):
411 index_now = legends.index(legend)
412 color = colors[index_now % len(colors)]
413 plot.line(
414 x_data, y_data, legend=str(legend), line_width=3, color=color)
415 plot.circle(
416 x_data, y_data, size=10, legend=str(legend), fill_color=color)
417 #Plot properties
418 plot.xaxis.axis_label = fig_property['x_label']
419 plot.yaxis.axis_label = fig_property['y_label']
420 plot.legend.location = "top_right"
421 plot.legend.click_policy = "hide"
422 plot.title.text_font_size = {'value': '15pt'}
Omar El Ayachded64232017-12-08 00:53:12 +0000423 if output_file_path is not None:
424 output_file(output_file_path)
425 save(plot)
Qi Jiang73b25352017-08-02 19:56:31 +0000426 return plot
427
428
429def run_iperf_client_nonblocking(ad, server_host, extra_args=""):
430 """Start iperf client on the device with nohup.
431
432 Return status as true if iperf client start successfully.
433 And data flow information as results.
434
435 Args:
436 ad: the android device under test
437 server_host: Address of the iperf server.
438 extra_args: A string representing extra arguments for iperf client,
439 e.g. "-i 1 -t 30".
440
441 """
442 log = logging.getLogger()
443 ad.adb.shell_nb("nohup iperf3 -c {} {} &".format(server_host, extra_args))
444 log.info("IPerf client started")
445
446
447def get_wifi_rssi(ad):
448 """Get the RSSI of the device.
449
450 Args:
451 ad: the android device under test
452 Returns:
453 RSSI: the rssi level of the device
454 """
455 RSSI = ad.droid.wifiGetConnectionInfo()['rssi']
456 return RSSI
Qi Jiang50733382017-08-22 01:11:58 +0000457
458
459def get_phone_ip(ad):
460 """Get the WiFi IP address of the phone.
461
462 Args:
463 ad: the android device under test
464 Returns:
465 IP: IP address of the phone for WiFi, as a string
466 """
467 IP = ad.droid.connectivityGetIPv4Addresses('wlan0')[0]
468
469 return IP
470
471
472def get_phone_mac(ad):
473 """Get the WiFi MAC address of the phone.
474
475 Args:
476 ad: the android device under test
477 Returns:
478 mac: MAC address of the phone for WiFi, as a string
479 """
480 mac = ad.droid.wifiGetConnectionInfo()["mac_address"]
481
482 return mac
483
484
485def get_phone_ipv6(ad):
486 """Get the WiFi IPV6 address of the phone.
487
488 Args:
489 ad: the android device under test
490 Returns:
491 IPv6: IPv6 address of the phone for WiFi, as a string
492 """
493 IPv6 = ad.droid.connectivityGetLinkLocalIpv6Address('wlan0')[:-6]
494
495 return IPv6
Daniel Barrosfefd8c32017-08-04 15:36:40 -0700496
497
498def get_if_addr6(intf, address_type):
499 """Returns the Ipv6 address from a given local interface.
500
501 Returns the desired IPv6 address from the interface 'intf' in human
502 readable form. The address type is indicated by the IPv6 constants like
503 IPV6_ADDR_LINKLOCAL, IPV6_ADDR_GLOBAL, etc. If no address is found,
504 None is returned.
505
506 Args:
507 intf: desired interface name
508 address_type: addrees typle like LINKLOCAL or GLOBAL
509
510 Returns:
511 Ipv6 address of the specified interface in human readable format
512 """
513 for if_list in scapy.in6_getifaddr():
514 if if_list[2] == intf and if_list[1] == address_type:
515 return if_list[0]
516
517 return None
Daniel Barrosebbf91a2017-10-04 01:08:40 +0000518
519
Qi Jiangcaca55e2017-10-10 23:10:40 +0000520@utils.timeout(60)
521def wait_for_dhcp(intf):
522 """Wait the DHCP address assigned to desired interface.
523
524 Getting DHCP address takes time and the wait time isn't constant. Utilizing
525 utils.timeout to keep trying until success
526
527 Args:
528 intf: desired interface name
529 Returns:
530 ip: ip address of the desired interface name
531 Raise:
532 TimeoutError: After timeout, if no DHCP assigned, raise
533 """
534 log = logging.getLogger()
535 reset_host_interface(intf)
536 ip = '0.0.0.0'
537 while ip == '0.0.0.0':
538 ip = scapy.get_if_addr(intf)
539 log.info('DHCP address assigned to {}'.format(intf))
540 return ip
541
542
543def reset_host_interface(intf):
544 """Reset the host interface.
545
546 Args:
547 intf: the desired interface to reset
548 """
549 log = logging.getLogger()
550 intf_down_cmd = 'ifconfig %s down' % intf
551 intf_up_cmd = 'ifconfig %s up' % intf
552 try:
553 job.run(intf_down_cmd)
554 time.sleep(3)
555 job.run(intf_up_cmd)
556 time.sleep(3)
557 log.info('{} has been reset'.format(intf))
558 except job.Error:
559 raise Exception('No such interface')
560
561
Daniel Barrosebbf91a2017-10-04 01:08:40 +0000562def create_pkt_config(test_class):
563 """Creates the config for generating multicast packets
564
565 Args:
566 test_class: object with all networking paramters
567
568 Returns:
569 Dictionary with the multicast packet config
570 """
571 addr_type = (scapy.IPV6_ADDR_LINKLOCAL
572 if test_class.ipv6_src_type == 'LINK_LOCAL' else
573 scapy.IPV6_ADDR_GLOBAL)
574
575 mac_dst = test_class.mac_dst
576 if GET_FROM_PHONE in test_class.mac_dst:
577 mac_dst = get_phone_mac(test_class.dut)
578
579 ipv4_dst = test_class.ipv4_dst
580 if GET_FROM_PHONE in test_class.ipv4_dst:
581 ipv4_dst = get_phone_ip(test_class.dut)
582
583 ipv6_dst = test_class.ipv6_dst
584 if GET_FROM_PHONE in test_class.ipv6_dst:
585 ipv6_dst = get_phone_ipv6(test_class.dut)
586
587 ipv4_gw = test_class.ipv4_gwt
588 if GET_FROM_AP in test_class.ipv4_gwt:
589 ipv4_gw = test_class.access_point.ssh_settings.hostname
590
591 pkt_gen_config = {
592 'interf': test_class.pkt_sender.interface,
593 'subnet_mask': test_class.sub_mask,
594 'src_mac': test_class.mac_src,
595 'dst_mac': mac_dst,
596 'src_ipv4': test_class.ipv4_src,
597 'dst_ipv4': ipv4_dst,
598 'src_ipv6': test_class.ipv6_src,
599 'src_ipv6_type': addr_type,
600 'dst_ipv6': ipv6_dst,
601 'gw_ipv4': ipv4_gw
602 }
603 return pkt_gen_config
604
605
606def create_monsoon_info(test_class):
607 """Creates the config dictionary for monsoon
608
609 Args:
610 test_class: object with all the parameters
611
612 Returns:
613 Dictionary with the monsoon packet config
614 """
615 mon_info = {
616 'dut': test_class.mon,
617 'freq': test_class.mon_freq,
618 'duration': test_class.mon_duration,
619 'offset': test_class.mon_offset,
620 'data_path': test_class.mon_data_path
621 }
622 return mon_info
Daniel Barros43760302017-12-06 04:16:03 +0000623
624
625def setup_phone_wireless(test_class,
626 bt_on,
627 wifi_on,
628 screen_status,
629 network=None,
630 regular_mode=False):
631 """Sets the phone in rock-bottom and in the desired wireless mode
632
633 Args:
634 test_class: the specific test class where test is running
635 bt_on: Enable/Disable BT
636 wifi_on: Enable/Disable WiFi
637 screen_status: screen ON or OFF
638 network: a dict of information for the WiFi network to connect
639 regular_mode: enable cellular data (i.e., disable airplane mode)
640 """
641 # Initialize the dut to rock-bottom state
642 dut_rockbottom(test_class.dut)
643 time.sleep(1)
644
645 if regular_mode:
646 test_class.dut.droid.connectivityToggleAirplaneMode(False)
647 utils.set_mobile_data_always_on(test_class.dut, True)
648 time.sleep(2)
649
650 # Turn ON/OFF BT
651 if bt_on == 'ON':
652 enable_bluetooth(test_class.dut.droid, test_class.dut.ed)
653 test_class.dut.log.info('BT is ON')
654 else:
655 disable_bluetooth(test_class.dut.droid)
656 test_class.dut.droid.bluetoothDisableBLE()
657 test_class.dut.log.info('BT is OFF')
658 time.sleep(2)
659
660 # Turn ON/OFF Wifi
661 if wifi_on == 'ON':
662 wutils.wifi_toggle_state(test_class.dut, True)
663 test_class.dut.log.info('WiFi is ON')
664 if network:
665 # Set attenuation and connect to AP
666 for attn in range(test_class.num_atten):
667 test_class.attenuators[attn].set_atten(
668 test_class.atten_level['zero_atten'][attn])
669 test_class.log.info('Set attenuation level to all zero')
670 ap_setup(test_class.access_point, network)
671 wutils.wifi_connect(test_class.dut, network)
672 else:
673 wutils.wifi_toggle_state(test_class.dut, False)
674 test_class.dut.log.info('WiFi is OFF')
675 time.sleep(1)
676
677 # Set the desired screen status
678 if screen_status == 'OFF':
679 test_class.dut.droid.goToSleepNow()
680 test_class.dut.log.info('Screen is OFF')
681 time.sleep(1)