1#!/usr/bin/env python3
2#
3#   Copyright 2019 - 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 re
18import time
19from queue import Empty
20
21from acts import utils
22from acts import base_test
23from acts.libs.proc import job
24from acts import signals
25from acts.test_decorators import test_tracker_info
26from acts.test_utils.wifi import wifi_test_utils as wutils
27from acts.test_utils.tel import tel_test_utils as tutils
28from acts.test_utils.tel import tel_defines
29from acts.test_utils.tel.anritsu_utils import wait_for_sms_sent_success
30from acts.test_utils.tel.tel_defines import EventMmsSentSuccess
31
32# Time it takes for the usb tethering IP to
33# show up in ifconfig and function waiting.
34DEFAULT_SETTLE_TIME = 5
35WifiEnums = wutils.WifiEnums
36USB_CHARGE_MODE = 'svc usb setFunctions'
37USB_TETHERING_MODE = 'svc usb setFunctions rndis'
38USB_MTP_MODE = 'svc usb setFunctions mtp'
39DEVICE_IP_ADDRESS = 'ip address'
40
41
42class UsbTetheringFunctionsTest(base_test.BaseTestClass):
43    """Tests for usb tethering throughput test.
44
45    Test Bed Requirement:
46        * One Android device.
47        * Wi-Fi networks visible to the device.
48        * Sim card with data call.
49    """
50
51    def setup_class(self):
52        self.dut = self.android_devices[0]
53        req_params = ['wifi_network', 'receiver_number', 'ping_count']
54        self.unpack_userparams(req_param_names=req_params)
55
56        self.ssid_map = {}
57        for network in self.wifi_network:
58            SSID = network['SSID'].replace('-', '_')
59            self.ssid_map[SSID] = network
60        self.dut.droid.setMobileDataEnabled()
61        if not tutils.verify_internet_connection(
62                self.dut.log, self.dut, retries=3):
63            tutils.abort_all_tests(self.dut.log, 'Internet connection Failed.')
64
65    def setup_test(self):
66        self.dut.droid.wakeLockAcquireBright()
67        self.dut.droid.wakeUpNow()
68        self.dut.unlock_screen()
69
70    def teardown_test(self):
71        wutils.wifi_toggle_state(self.dut, False)
72        self.dut.droid.wakeLockRelease()
73        self.dut.droid.goToSleepNow()
74        self.dut.droid.setMobileDataEnabled()
75        self.dut.droid.connectivityStopTethering(tel_defines.TETHERING_WIFI)
76        self.dut.stop_services()
77        # Set usb function back to charge mode.
78        self.dut.adb.shell(USB_CHARGE_MODE)
79        self.dut.adb.wait_for_device()
80        self.dut.start_services()
81
82    def teardown_class(self):
83        wutils.reset_wifi(self.dut)
84
85    def on_fail(self, test_name, begin_time):
86        self.dut.take_bug_report(test_name, begin_time)
87        self.dut.cat_adb_log(test_name, begin_time)
88
89    def enable_usb_tethering(self, attempts=3):
90        """Stop SL4A service and enable usb tethering.
91
92        Logic steps are
93        1. Stop SL4A service.
94        2. Enable usb tethering.
95        3. Restart SL4A service.
96        4. Check usb tethering enabled.
97        5. Attempt if fail to enable usb tethering.
98
99        Args:
100            attempts: number of times for enable usb tethering.
101
102        Raises:
103            TestFailure when unable to find rndis string.
104        """
105        for i in range(attempts):
106            self.dut.stop_services()
107            self.dut.adb.shell(USB_TETHERING_MODE, ignore_status=True)
108            self.dut.adb.wait_for_device()
109            self.dut.start_services()
110            if 'rndis' in self.dut.adb.shell(DEVICE_IP_ADDRESS):
111                self.log.info('Usb tethering is enabled.')
112                return
113            else:
114                self.log.info('Enable usb tethering - attempt %d' % (i + 1))
115        raise signals.TestFailure('Unable to enable USB tethering.')
116
117    def connect_to_wifi_network(self, network):
118        """Connection logic for wifi network.
119
120        Args:
121            network: Dictionary with network info.
122        """
123        SSID = network[WifiEnums.SSID_KEY]
124        self.dut.ed.clear_all_events()
125        wutils.start_wifi_connection_scan(self.dut)
126        scan_results = self.dut.droid.wifiGetScanResults()
127        wutils.assert_network_in_list({WifiEnums.SSID_KEY: SSID}, scan_results)
128        wutils.wifi_connect(self.dut, network, num_of_tries=3)
129
130    def enable_wifi_hotspot(self):
131        """Enable wifi hotspot."""
132        sap_config = wutils.create_softap_config()
133        wutils.start_wifi_tethering(self.dut,
134                                    sap_config[wutils.WifiEnums.SSID_KEY],
135                                    sap_config[wutils.WifiEnums.PWD_KEY],
136                                    wutils.WifiEnums.WIFI_CONFIG_APBAND_2G)
137
138    def get_rndis_interface(self):
139        """Check rndis interface after usb tethering enable.
140
141        Returns:
142            Usb tethering interface from Android device.
143
144        Raises:
145            TestFailure when unable to find correct usb tethering interface.
146        """
147        time.sleep(DEFAULT_SETTLE_TIME)
148        check_usb_tethering = job.run('ifconfig').stdout
149        # A regex that stores the tethering interface in group 1.
150        tethered_interface_regex = r'^(enp.*?):.*?broadcast 192.168.42.255'
151        match = re.search(tethered_interface_regex, check_usb_tethering,
152                          re.DOTALL + re.MULTILINE)
153        if match:
154            return match.group(1)
155        else:
156            raise signals.TestFailure(
157                'Unable to find tethering interface. The device may not be tethered.'
158            )
159
160    def can_ping(self, ip, extra_params='', count=10):
161        """Run ping test and check and check ping lost rate.
162
163        Args:
164            ip: ip address for ping.
165            extra_params: params for ping test.
166            count: default ping count.
167
168        Returns:
169            True: If no packet loss.
170            False: Otherwise.
171        """
172        out = job.run(
173            'ping -c {} {} {}'.format(count, extra_params, ip),
174            ignore_status=True).stdout
175        self.log.info(out)
176        return '0%' in out.split(' ')
177
178    def can_ping_through_usb_interface(self):
179        """Run ping test and check result after usb tethering enabled.
180
181        Raises:
182            TestFailure when unable to ping through usb tethering interface.
183        """
184        ip = '8.8.8.8'
185        interface = self.get_rndis_interface()
186        if not self.can_ping(
187                ip, '-I {}'.format(interface), count=self.ping_count):
188            raise signals.TestFailure(
189                'Fail to ping through usb tethering interface.')
190
191    def enable_usb_mtp(self):
192        """Enable usb mtp mode.
193
194        Raises:
195            TestFailure when unable to set mtp mode.
196        """
197        try:
198            self.dut.stop_services()
199            self.dut.adb.shell(USB_MTP_MODE, ignore_status=True)
200            self.dut.adb.wait_for_device()
201            self.dut.start_services()
202        except:
203            raise signals.TestFailure('Device can not enable mtp mode.')
204
205    def check_sms_send_status(self, message='usb_sms_test'):
206        """Send a SMS and check send status.
207
208        Args:
209            message: SMS string.
210
211        Raises:
212            Exception when unable to send SMS.
213        """
214        self.dut.droid.smsSendTextMessage(self.receiver_number, message, False)
215        self.log.info('Waiting for SMS sent event')
216        test_status = wait_for_sms_sent_success(self.log, self.dut)
217        if not test_status:
218            raise Exception('Failed to send SMS')
219
220    def check_mms_send_status(self,
221                              subject='usb_subject',
222                              message='usb_mms_test'):
223        """Send a MMS and check send status.
224
225        Args:
226            subject: MMS subject.
227            message: MMS string.
228
229        Raises:
230            Exception when unable to send MMS.
231        """
232        # Permission require for send MMS.
233        self.dut.adb.shell('su root setenforce 0')
234        self.dut.droid.smsSendMultimediaMessage(self.receiver_number, subject,
235                                                message)
236        self.log.info('Waiting for MMS sent event')
237        test_status = self.wait_for_mms_sent_success()
238        if not test_status:
239            raise Exception('Failed to send MMS')
240
241    def wait_for_mms_sent_success(self, time_to_wait=60):
242        """Check MMS send status.
243
244        Args:
245            time_to_wait: Time out for check MMS.
246
247        Returns:
248            status = MMS send status.
249        """
250        mms_sent_event = EventMmsSentSuccess
251        try:
252            event = self.dut.ed.pop_event(mms_sent_event, time_to_wait)
253            self.log.info(event)
254        except Empty:
255            self.log.error('Timeout: Expected event is not received.')
256            return False
257        return True
258
259    @test_tracker_info(uuid="7c2ae85e-32a2-416e-a65e-c15a15e76f86")
260    def test_usb_tethering_wifi_only(self):
261        """Enable usb tethering with wifi only then executing ping test.
262
263        Steps:
264        1. Stop SL4A services.
265        2. Enable usb tethering.
266        3. Restart SL4A services.
267        4. Mobile data disable and wifi enable.
268        5. Run ping test through usb tethering interface.
269        """
270        self.enable_usb_tethering()
271        self.log.info('Disable mobile data.')
272        self.dut.droid.setMobileDataEnabled(False)
273        self.log.info('Enable wifi.')
274        wutils.wifi_toggle_state(self.dut, True)
275        self.connect_to_wifi_network(
276            self.ssid_map[self.wifi_network[0]['SSID']])
277        self.can_ping_through_usb_interface()
278
279    @test_tracker_info(uuid="8910b07b-0beb-4d9d-b901-c4195b4e0930")
280    def test_usb_tethering_data_only(self):
281        """Enable usb tethering with data only then executing ping test.
282
283        Steps:
284        1. Stop SL4A services.
285        2. Enable usb tethering.
286        3. Restart SL4A services.
287        4. Wifi disable and mobile data enable.
288        5. Run ping test through usb tethering interface.
289        """
290        self.enable_usb_tethering()
291        wutils.wifi_toggle_state(self.dut, False)
292        self.dut.droid.setMobileDataEnabled()
293        time.sleep(DEFAULT_SETTLE_TIME)
294        self.can_ping_through_usb_interface()
295
296    @test_tracker_info(uuid="f971806e-e003-430a-bc80-321f128d31cb")
297    def test_usb_tethering_after_airplane_mode(self):
298        """Enable usb tethering after airplane mode then executing ping test.
299
300        Steps:
301        1. Stop SL4A services.
302        2. Enable usb tethering.
303        3. Restart SL4A services.
304        4. Wifi disable and mobile data enable.
305        5. Enable/disable airplane mode.
306        6. Run ping test through usb tethering interface.
307        """
308        self.enable_usb_tethering()
309        wutils.wifi_toggle_state(self.dut, False)
310        self.log.info('Enable airplane mode.')
311        utils.force_airplane_mode(self.dut, True)
312        self.log.info('Disable airplane mode.')
313        utils.force_airplane_mode(self.dut, False)
314        time.sleep(DEFAULT_SETTLE_TIME)
315        self.can_ping_through_usb_interface()
316
317    @test_tracker_info(uuid="db1c561d-67bd-47d7-b65e-d882f0e2641e")
318    def test_usb_tethering_coexist_wifi_hotspot(self):
319        """Enable usb tethering with hotspot then executing ping test.
320
321        Steps:
322        1. Enable hotspot
323        2. Stop SL4A services.
324        3. Enable usb tethering.
325        4. Restart SL4A services.
326        5. Run ping test through tethering interface during hotspot enable.
327        6. Run ping test through tethering interface during hotspot disable.
328        """
329        self.log.info('Enable wifi hotspot.')
330        self.enable_wifi_hotspot()
331        self.enable_usb_tethering()
332        self.log.info('Ping test with hotspot enable.')
333        self.can_ping_through_usb_interface()
334        self.log.info('Disable wifi hotspot.')
335        self.dut.droid.connectivityStopTethering(tel_defines.TETHERING_WIFI)
336        self.log.info('Ping test with hotspot disable.')
337        self.can_ping_through_usb_interface()
338
339    @test_tracker_info(uuid="7018abdb-049e-41aa-a4f9-e11012369d9b")
340    def test_usb_tethering_after_mtp(self):
341        """Enable usb tethering after mtp enable then executing ping test.
342
343        Steps:
344        1. Stop SL4A services.
345        2. Enable usb tethering.
346        3. Restart SL4A services.
347        4. Enable usb mtp mode.
348        5. Enable usb tethering and mtp will disable.
349        6. Run ping test through usb tethering interface.
350        """
351        self.enable_usb_tethering()
352        self.log.info('Enable usb mtp mode.')
353        self.enable_usb_mtp()
354        # Turn on mtp mode for 5 sec.
355        time.sleep(DEFAULT_SETTLE_TIME)
356        self.enable_usb_tethering()
357        self.log.info('Usb tethering enable, usb mtp mode disabled.')
358        self.can_ping_through_usb_interface()
359
360    @test_tracker_info(uuid="f1ba2cbc-1cb2-4b8a-92eb-9b366c3f4c37")
361    def test_usb_tethering_after_sms_mms(self):
362        """Enable usb tethering after send sms and mms then executing ping test.
363
364        Steps:
365        1. Stop SL4A services.
366        2. Enable usb tethering.
367        3. Restart SL4A services.
368        4. Send a sms and mms.
369        5. Run ping test through usb tethering interface.
370        """
371        self.enable_usb_tethering()
372        self.log.info('Start send SMS and check status.')
373        self.check_sms_send_status()
374        time.sleep(DEFAULT_SETTLE_TIME)
375        self.log.info('Start send MMS and check status.')
376        self.check_mms_send_status()
377        self.can_ping_through_usb_interface()
378
379    @test_tracker_info(uuid="e6586b30-4886-4c3e-8225-633aa9333968")
380    def test_usb_tethering_after_reboot(self):
381        """Enable usb tethering after reboot then executing ping test.
382
383        Steps:
384        1. Reboot device.
385        2. Stop SL4A services.
386        3. Enable usb tethering.
387        4. Restart SL4A services.
388        5. Run ping test through usb tethering interface.
389        """
390        self.enable_usb_tethering()
391        self.log.info('Reboot device.')
392        self.dut.reboot()
393        self.dut.droid.setMobileDataEnabled()
394        self.log.info('Start usb tethering and ping test.')
395        self.enable_usb_tethering()
396        self.can_ping_through_usb_interface()
397
398    @test_tracker_info(uuid="40093ab8-6db4-4af4-97ae-9467bf33bf23")
399    def test_usb_tethering_after_wipe(self):
400        """Enable usb tethering after wipe.
401
402        Steps:
403        1. Enable usb tethering.
404        2. Wipe device.
405        3. Wake up device and unlock screen.
406        4. Enable usb tethering.
407        5. Run ping test through usb tethering interface.
408        """
409        self.enable_usb_tethering()
410        tutils.fastboot_wipe(self.dut)
411        time.sleep(DEFAULT_SETTLE_TIME)
412        # Skip setup wizard after wipe.
413        self.dut.adb.shell(
414            'am start -a com.android.setupwizard.EXIT', ignore_status=True)
415        self.dut.droid.setMobileDataEnabled()
416        self.dut.droid.wakeUpNow()
417        self.dut.unlock_screen()
418        self.enable_usb_tethering()
419        self.can_ping_through_usb_interface()