Merge "Add hfp test command hfp_waiting_call."
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/acts/framework/acts/controllers/OWNERS b/acts/framework/acts/controllers/OWNERS
index c4ba954..ea76291 100644
--- a/acts/framework/acts/controllers/OWNERS
+++ b/acts/framework/acts/controllers/OWNERS
@@ -1,5 +1,5 @@
 per-file asus_axe11000_ap.py = martschneider@google.com
-per-file fuchsia_device.py = chcl@google.com, dhobsd@google.com, haydennix@google.com, jmbrenna@google.com, mnck@google.com, silberst@google.com, tturney@google.com, sbalana@google.com
+per-file fuchsia_device.py = chcl@google.com, dhobsd@google.com, haydennix@google.com, jmbrenna@google.com, mnck@google.com, nickchee@google.com, sbalana@google.com, silberst@google.com, tturney@google.com
 per-file bluetooth_pts_device.py = tturney@google.com
 per-file cellular_simulator.py = iguarna@google.com, chaoyangf@google.com, codycaldwell@google.com, yixiang@google.com
 per-file openwrt_ap.py = jerrypcchen@google.com, martschneider@google.com, gmoturu@google.com, sishichen@google.com
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index 21e26bb..a2f2840 100755
--- a/acts/framework/acts/controllers/access_point.py
+++ b/acts/framework/acts/controllers/access_point.py
@@ -185,15 +185,14 @@
         ssh_settings: The ssh settings being used by the ssh connection.
         dhcp_settings: The dhcp server settings being used.
     """
-
     def __init__(self, configs):
         """
         Args:
             configs: configs for the access point from config file.
         """
         self.ssh_settings = settings.from_config(configs['ssh_config'])
-        self.log = logger.create_logger(lambda msg: '[Access Point|%s] %s' % (
-            self.ssh_settings.hostname, msg))
+        self.log = logger.create_logger(lambda msg: '[Access Point|%s] %s' %
+                                        (self.ssh_settings.hostname, msg))
         self.device_pdu_config = configs.get('PduDevice', None)
         self.identifier = self.ssh_settings.hostname
 
@@ -429,11 +428,25 @@
     def get_dhcp_logs(self):
         """Get DHCP logs for this AP object.
 
-        This allows consumers of the access point objects validate DHCP
+        This allows consumers of the access point objects to validate DHCP
         behavior.
         """
         return self._dhcp.get_logs()
 
+    def get_hostapd_logs(self):
+        """Get hostapd logs for all interfaces on AP object.
+
+        This allows consumers of the access point objects to validate hostapd
+        behavior.
+
+        Returns: A dict with {interface: log} from hostapd instances.
+        """
+        hostapd_logs = dict()
+        for identifier in self._aps:
+            hostapd_logs[identifier] = self._aps.get(
+                identifier).hostapd.pull_logs()
+        return hostapd_logs
+
     def start_nat(self):
         """Start NAT on the AP.
 
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index cccc248..793cb23 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -48,6 +48,10 @@
 ACTS_CONTROLLER_REFERENCE_NAME = "android_devices"
 
 ANDROID_DEVICE_PICK_ALL_TOKEN = "*"
+# Key name for SL4A extra params in config file
+ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY = "sl4a_client_port"
+ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY = "sl4a_forwarded_port"
+ANDROID_DEVICE_SL4A_SERVER_PORT_KEY = "sl4a_server_port"
 # Key name for adb logcat extra params in config file.
 ANDROID_DEVICE_ADB_LOGCAT_PARAM_KEY = "adb_logcat_param"
 ANDROID_DEVICE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!"
@@ -235,12 +239,41 @@
             raise errors.AndroidDeviceConfigError(
                 "Required value 'serial' is missing in AndroidDevice config %s."
                 % c)
+        client_port = 0
+        if ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY in c:
+            try:
+                client_port = int(c.pop(ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY))
+            except ValueError:
+                raise errors.AndroidDeviceConfigError(
+                    "'%s' is not a valid number for config %s" %
+                    (ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY, c))
+        server_port = None
+        if ANDROID_DEVICE_SL4A_SERVER_PORT_KEY in c:
+            try:
+                server_port = int(c.pop(ANDROID_DEVICE_SL4A_SERVER_PORT_KEY))
+            except ValueError:
+                raise errors.AndroidDeviceConfigError(
+                    "'%s' is not a valid number for config %s" %
+                    (ANDROID_DEVICE_SL4A_SERVER_PORT_KEY, c))
+        forwarded_port = 0
+        if ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY in c:
+            try:
+                forwarded_port = int(
+                    c.pop(ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY))
+            except ValueError:
+                raise errors.AndroidDeviceConfigError(
+                    "'%s' is not a valid number for config %s" %
+                    (ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY, c))
         ssh_config = c.pop('ssh_config', None)
         ssh_connection = None
         if ssh_config is not None:
             ssh_settings = settings.from_config(ssh_config)
             ssh_connection = connection.SshConnection(ssh_settings)
-        ad = AndroidDevice(serial, ssh_connection=ssh_connection)
+        ad = AndroidDevice(serial,
+                           ssh_connection=ssh_connection,
+                           client_port=client_port,
+                           forwarded_port=forwarded_port,
+                           server_port=server_port)
         ad.load_config(c)
         results.append(ad)
     return results
@@ -360,14 +393,27 @@
         adb: An AdbProxy object used for interacting with the device via adb.
         fastboot: A FastbootProxy object used for interacting with the device
                   via fastboot.
+        client_port: Preferred client port number on the PC host side for SL4A
+        forwarded_port: Preferred server port number forwarded from Android
+                        to the host PC via adb for SL4A connections
+        server_port: Preferred server port used by SL4A on Android device
+
     """
 
-    def __init__(self, serial='', ssh_connection=None):
+    def __init__(self,
+                 serial='',
+                 ssh_connection=None,
+                 client_port=0,
+                 forwarded_port=0,
+                 server_port=None):
         self.serial = serial
         # logging.log_path only exists when this is used in an ACTS test run.
         log_path_base = getattr(logging, 'log_path', '/tmp/logs')
         self.log_dir = 'AndroidDevice%s' % serial
         self.log_path = os.path.join(log_path_base, self.log_dir)
+        self.client_port = client_port
+        self.forwarded_port = forwarded_port
+        self.server_port = server_port
         self.log = tracelogger.TraceLogger(
             AndroidDeviceLoggerAdapter(logging.getLogger(),
                                        {'serial': serial}))
@@ -377,8 +423,8 @@
         self.register_service(services.Sl4aService(self))
         self.adb_logcat_process = None
         self.adb = adb.AdbProxy(serial, ssh_connection=ssh_connection)
-        self.fastboot = fastboot.FastbootProxy(
-            serial, ssh_connection=ssh_connection)
+        self.fastboot = fastboot.FastbootProxy(serial,
+                                               ssh_connection=ssh_connection)
         if not self.is_bootloader:
             self.root_adb()
         self._ssh_connection = ssh_connection
@@ -402,6 +448,34 @@
         if self._ssh_connection:
             self._ssh_connection.close()
 
+    def recreate_services(self, serial):
+        """Clean up the AndroidDevice object and re-create adb/sl4a services.
+
+        Unregister the existing services and re-create adb and sl4a services,
+        call this method when the connection break after certain API call
+        (e.g., enable USB tethering by #startTethering)
+
+        Args:
+            serial: the serial number of the AndroidDevice
+        """
+        # Clean the old services
+        for service in self._services:
+            service.unregister()
+        self._services.clear()
+        if self._ssh_connection:
+            self._ssh_connection.close()
+        self._sl4a_manager.stop_service()
+
+        # Wait for old services to stop
+        time.sleep(5)
+
+        # Re-create the new adb and sl4a services
+        self.register_service(services.AdbLogcatService(self))
+        self.register_service(services.Sl4aService(self))
+        self.adb.wait_for_device()
+        self.terminate_all_sessions()
+        self.start_services()
+
     def register_service(self, service):
         """Registers the service on the device. """
         service.register()
@@ -428,8 +502,8 @@
 
         Stop adb logcat and terminate sl4a sessions if exist.
         """
-        event_bus.post(
-            android_events.AndroidStopServicesEvent(self), ignore_errors=True)
+        event_bus.post(android_events.AndroidStopServicesEvent(self),
+                       ignore_errors=True)
 
     def is_connected(self):
         out = self.adb.devices()
@@ -654,7 +728,13 @@
             >>> ad = AndroidDevice()
             >>> droid, ed = ad.get_droid()
         """
-        session = self._sl4a_manager.create_session()
+        self.log.debug(
+            "Creating RPC client_port={}, forwarded_port={}, server_port={}".
+            format(self.client_port, self.forwarded_port, self.server_port))
+        session = self._sl4a_manager.create_session(
+            client_port=self.client_port,
+            forwarded_port=self.forwarded_port,
+            server_port=self.server_port)
         droid = session.rpc_client
         if handle_event:
             ed = session.get_event_dispatcher()
@@ -674,9 +754,8 @@
         """
         for cmd in ("ps -A", "ps"):
             try:
-                out = self.adb.shell(
-                    '%s | grep "S %s"' % (cmd, package_name),
-                    ignore_status=True)
+                out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name),
+                                     ignore_status=True)
                 if package_name not in out:
                     continue
                 try:
@@ -768,10 +847,10 @@
         return adb_excerpt_path
 
     def search_logcat(self,
-                    matching_string,
-                    begin_time=None,
-                    end_time=None,
-                    logcat_path=None):
+                      matching_string,
+                      begin_time=None,
+                      end_time=None,
+                      logcat_path=None):
         """Search logcat message with given string.
 
         Args:
@@ -801,13 +880,12 @@
         """
         if not logcat_path:
             logcat_path = os.path.join(self.device_log_path,
-                                    'adblog_%s_debug.txt' % self.serial)
+                                       'adblog_%s_debug.txt' % self.serial)
         if not os.path.exists(logcat_path):
             self.log.warning("Logcat file %s does not exist." % logcat_path)
             return
-        output = job.run(
-            "grep '%s' %s" % (matching_string, logcat_path),
-            ignore_status=True)
+        output = job.run("grep '%s' %s" % (matching_string, logcat_path),
+                         ignore_status=True)
         if not output.stdout or output.exit_status != 0:
             return []
         if begin_time:
@@ -815,13 +893,13 @@
                 log_begin_time = acts_logger.epoch_to_log_line_timestamp(
                     begin_time)
                 begin_time = datetime.strptime(log_begin_time,
-                                            "%Y-%m-%d %H:%M:%S.%f")
+                                               "%Y-%m-%d %H:%M:%S.%f")
         if end_time:
             if not isinstance(end_time, datetime):
                 log_end_time = acts_logger.epoch_to_log_line_timestamp(
                     end_time)
                 end_time = datetime.strptime(log_end_time,
-                                            "%Y-%m-%d %H:%M:%S.%f")
+                                             "%Y-%m-%d %H:%M:%S.%f")
         result = []
         logs = re.findall(r'(\S+\s\S+)(.*)', output.stdout)
         for log in logs:
@@ -893,8 +971,8 @@
         Returns:
         Linux UID for the apk.
         """
-        output = self.adb.shell(
-            "dumpsys package %s | grep userId=" % apk_name, ignore_status=True)
+        output = self.adb.shell("dumpsys package %s | grep userId=" % apk_name,
+                                ignore_status=True)
         result = re.search(r"userId=(\d+)", output)
         if result:
             return result.group(1)
@@ -960,9 +1038,8 @@
         """
         for cmd in ("ps -A", "ps"):
             try:
-                out = self.adb.shell(
-                    '%s | grep "S %s"' % (cmd, package_name),
-                    ignore_status=True)
+                out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name),
+                                     ignore_status=True)
                 if package_name in out:
                     self.log.info("apk %s is running", package_name)
                     return True
@@ -987,8 +1064,8 @@
         True if package is installed. False otherwise.
         """
         try:
-            self.adb.shell(
-                'am force-stop %s' % package_name, ignore_status=True)
+            self.adb.shell('am force-stop %s' % package_name,
+                           ignore_status=True)
         except Exception as e:
             self.log.warning("Fail to stop package %s: %s", package_name, e)
 
@@ -1029,8 +1106,8 @@
             br_out_path = out.split(':')[1].strip().split()[0]
             self.adb.pull("%s %s" % (br_out_path, full_out_path))
         else:
-            self.adb.bugreport(
-                " > {}".format(full_out_path), timeout=BUG_REPORT_TIMEOUT)
+            self.adb.bugreport(" > {}".format(full_out_path),
+                               timeout=BUG_REPORT_TIMEOUT)
         self.log.info("Bugreport for %s taken at %s.", test_name,
                       full_out_path)
         self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
@@ -1092,10 +1169,10 @@
         if not host_path:
             host_path = self.log_path
         for device_path in device_paths:
-            self.log.info(
-                'Pull from device: %s -> %s' % (device_path, host_path))
-            self.adb.pull(
-                "%s %s" % (device_path, host_path), timeout=PULL_TIMEOUT)
+            self.log.info('Pull from device: %s -> %s' %
+                          (device_path, host_path))
+            self.adb.pull("%s %s" % (device_path, host_path),
+                          timeout=PULL_TIMEOUT)
 
     def check_crash_report(self,
                            test_name=None,
@@ -1110,10 +1187,9 @@
             except Exception as e:
                 self.log.debug("received exception %s", e)
                 continue
-            crashes = self.get_file_names(
-                crash_path,
-                skip_files=CRASH_REPORT_SKIPS,
-                begin_time=begin_time)
+            crashes = self.get_file_names(crash_path,
+                                          skip_files=CRASH_REPORT_SKIPS,
+                                          begin_time=begin_time)
             if crash_path == "/data/tombstones/" and crashes:
                 tombstones = crashes[:]
                 for tombstone in tombstones:
@@ -1136,8 +1212,9 @@
         # Sleep 10 seconds for the buffered log to be written in qxdm log file
         time.sleep(10)
         log_path = getattr(self, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
-        qxdm_logs = self.get_file_names(
-            log_path, begin_time=begin_time, match_string="*.qmdl")
+        qxdm_logs = self.get_file_names(log_path,
+                                        begin_time=begin_time,
+                                        match_string="*.qmdl")
         if qxdm_logs:
             qxdm_log_path = os.path.join(self.device_log_path,
                                          "QXDM_%s" % self.serial)
@@ -1146,10 +1223,9 @@
             self.log.info("Pull QXDM Log %s to %s", qxdm_logs, qxdm_log_path)
             self.pull_files(qxdm_logs, qxdm_log_path)
 
-            self.adb.pull(
-                "/firmware/image/qdsp6m.qdb %s" % qxdm_log_path,
-                timeout=PULL_TIMEOUT,
-                ignore_status=True)
+            self.adb.pull("/firmware/image/qdsp6m.qdb %s" % qxdm_log_path,
+                          timeout=PULL_TIMEOUT,
+                          ignore_status=True)
             # Zip Folder
             utils.zip_directory('%s.zip' % qxdm_log_path, qxdm_log_path)
             shutil.rmtree(qxdm_log_path)
@@ -1176,8 +1252,9 @@
         ]
         sdm_logs = []
         for path in log_paths:
-            sdm_logs += self.get_file_names(
-                path, begin_time=begin_time, match_string="*.sdm*")
+            sdm_logs += self.get_file_names(path,
+                                            begin_time=begin_time,
+                                            match_string="*.sdm*")
         if sdm_logs:
             sdm_log_path = os.path.join(self.device_log_path,
                                         "SDM_%s" % self.serial)
@@ -1185,7 +1262,7 @@
             self.log.info("Pull SDM Log %s to %s", sdm_logs, sdm_log_path)
             self.pull_files(sdm_logs, sdm_log_path)
         else:
-            self.log.error("Didn't find SDM logs in %s." % log_paths)
+            self.log.error("Didn't find SDM logs in %s." % log_path)
         if "Verizon" in self.adb.getprop("gsm.sim.operator.alpha"):
             omadm_log_path = os.path.join(self.device_log_path,
                                           "OMADM_%s" % self.serial)
@@ -1263,8 +1340,8 @@
             status: true if iperf client start successfully.
             results: results have data flow information
         """
-        out = self.adb.shell(
-            "iperf3 -c {} {}".format(server_host, extra_args), timeout=timeout)
+        out = self.adb.shell("iperf3 -c {} {}".format(server_host, extra_args),
+                             timeout=timeout)
         clean_out = out.split('\n')
         if "error" in clean_out[0].lower():
             return False, clean_out
@@ -1315,7 +1392,9 @@
             'Device %s booting process timed out.' % self.serial,
             serial=self.serial)
 
-    def reboot(self, stop_at_lock_screen=False, timeout=180,
+    def reboot(self,
+               stop_at_lock_screen=False,
+               timeout=180,
                wait_after_reboot_complete=1):
         """Reboots the device.
 
@@ -1352,8 +1431,8 @@
                 # want the device to be missing to prove the device has kicked
                 # off the reboot.
                 break
-        self.wait_for_boot_completion(
-            timeout=(timeout - time.time() + timeout_start))
+        self.wait_for_boot_completion(timeout=(timeout - time.time() +
+                                               timeout_start))
 
         self.log.debug('Wait for a while after boot completion.')
         time.sleep(wait_after_reboot_complete)
@@ -1388,8 +1467,8 @@
                 break
             except adb.AdbError as e:
                 if timer + 1 == timeout:
-                    self.log.warning(
-                        'Unable to find IP address for %s.' % interface)
+                    self.log.warning('Unable to find IP address for %s.' %
+                                     interface)
                     return None
                 else:
                     time.sleep(1)
@@ -1454,7 +1533,7 @@
         for cmd in dumpsys_cmd:
             output = self.adb.shell(cmd, ignore_status=True)
             if not output or "not found" in output or "Can't find" in output or (
-                "mFocusedApp=null" in output):
+                    "mFocusedApp=null" in output):
                 result = ''
             else:
                 result = output.split(' ')[-2]
@@ -1603,11 +1682,11 @@
             return
         if not self.is_user_setup_complete() or self.is_setupwizard_on():
             # b/116709539 need this to prevent reboot after skip setup wizard
-            self.adb.shell(
-                "am start -a com.android.setupwizard.EXIT", ignore_status=True)
-            self.adb.shell(
-                "pm disable %s" % self.get_setupwizard_package_name(),
-                ignore_status=True)
+            self.adb.shell("am start -a com.android.setupwizard.EXIT",
+                           ignore_status=True)
+            self.adb.shell("pm disable %s" %
+                           self.get_setupwizard_package_name(),
+                           ignore_status=True)
         # Wait up to 5 seconds for user_setup_complete to be updated
         end_time = time.time() + 5
         while time.time() < end_time:
@@ -1657,8 +1736,8 @@
         try:
             self.ensure_verity_disabled()
             self.adb.remount()
-            out = self.adb.push(
-                '%s %s' % (src_file_path, dst_file_path), timeout=push_timeout)
+            out = self.adb.push('%s %s' % (src_file_path, dst_file_path),
+                                timeout=push_timeout)
             if 'error' in out:
                 self.log.error('Unable to push system file %s to %s due to %s',
                                src_file_path, dst_file_path, out)
diff --git a/acts/framework/acts/controllers/fuchsia_device.py b/acts/framework/acts/controllers/fuchsia_device.py
index efa34dd..59abec3 100644
--- a/acts/framework/acts/controllers/fuchsia_device.py
+++ b/acts/framework/acts/controllers/fuchsia_device.py
@@ -320,17 +320,17 @@
         self.start_services(skip_sl4f=self.skip_sl4f)
         # Init server
         self.init_server_connection()
-        self.init_ffx_connection()
 
         self.setup_commands = fd_conf_data.get('setup_commands', [])
         self.teardown_commands = fd_conf_data.get('teardown_commands', [])
 
         try:
+            self.init_ffx_connection()
             self.run_commands_from_config(self.setup_commands)
-        except FuchsiaDeviceError:
+        except Exception as e:
             # Prevent a threading error, since controller isn't fully up yet.
             self.clean_up()
-            raise FuchsiaDeviceError('Failed to run setup commands.')
+            raise e
 
     def _set_control_path_config(self, old_config, new_config):
         """Given an input ssh_config, write to a new config with proper
diff --git a/acts/framework/acts/controllers/fuchsia_lib/OWNERS b/acts/framework/acts/controllers/fuchsia_lib/OWNERS
index febd4ad..130db54 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/OWNERS
+++ b/acts/framework/acts/controllers/fuchsia_lib/OWNERS
@@ -3,6 +3,7 @@
 haydennix@google.com
 jmbrenna@google.com
 mnck@google.com
+nickchee@google.com
+sbalana@google.com
 silberst@google.com
 tturney@google.com
-sbalana@google.com
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
index 1d202c6..d50f726 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
@@ -111,7 +111,12 @@
         net_ifaces = self.device.netstack_controller.list_interfaces()
         wlan_ifaces_by_role = {'client': {}, 'ap': {}}
         for iface in net_ifaces:
-            iface_mac = utils.mac_address_list_to_str(iface['mac'])
+            try:
+                # Some interfaces might not have a MAC
+                iface_mac = utils.mac_address_list_to_str(iface['mac'])
+            except Exception as e:
+                self.log.debug(f'Error {e} getting MAC for iface {iface}')
+                continue
             if iface_mac in wlan_ifaces_by_mac:
                 wlan_ifaces_by_mac[iface_mac]['netstack_id'] = iface['id']
 
diff --git a/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py b/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
index 8c4bb55..2593dde 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
@@ -33,7 +33,7 @@
         """
         try:
             self.device.ffx_command(
-                "component bind /core/session-manager/session:session")
+                "component start /core/session-manager/session:session")
             return {'error': None, 'result': 'Success'}
         except Exception as e:
             return {'error': e, 'result': None}
diff --git a/acts/framework/acts/controllers/openwrt_lib/network_const.py b/acts/framework/acts/controllers/openwrt_lib/network_const.py
index 0a3fb42..3aba0de 100644
--- a/acts/framework/acts/controllers/openwrt_lib/network_const.py
+++ b/acts/framework/acts/controllers/openwrt_lib/network_const.py
@@ -1,3 +1,5 @@
+LOCALHOST = "192.168.1.1"
+
 # params for ipsec.conf
 IPSEC_CONF = {
     "config setup": {
@@ -15,7 +17,7 @@
     "conn L2TP_PSK": {
         "keyexchange": "ikev1",
         "type": "transport",
-        "left": "192.168.1.1",
+        "left": LOCALHOST,
         "leftprotoport": "17/1701",
         "leftauth": "psk",
         "right": "%any",
@@ -30,7 +32,7 @@
     "conn L2TP_RSA": {
         "keyexchange": "ikev1",
         "type": "transport",
-        "left": "192.168.1.1",
+        "left": LOCALHOST,
         "leftprotoport": "17/1701",
         "leftauth": "pubkey",
         "leftcert": "serverCert.der",
@@ -45,7 +47,7 @@
 IPSEC_HYBRID_RSA = {
     "conn HYBRID_RSA": {
         "keyexchange": "ikev1",
-        "left": "192.168.1.1",
+        "left": LOCALHOST,
         "leftsubnet": "0.0.0.0/0",
         "leftauth": "pubkey",
         "leftcert": "serverCert.der",
@@ -62,7 +64,7 @@
 IPSEC_XAUTH_PSK = {
     "conn XAUTH_PSK": {
         "keyexchange": "ikev1",
-        "left": "192.168.1.1",
+        "left": LOCALHOST,
         "leftsubnet": "0.0.0.0/0",
         "leftauth": "psk",
         "right": "%any",
@@ -76,7 +78,7 @@
 IPSEC_XAUTH_RSA = {
     "conn XAUTH_RSA": {
         "keyexchange": "ikev1",
-        "left": "192.168.1.1",
+        "left": LOCALHOST,
         "leftsubnet": "0.0.0.0/0",
         "leftcert": "serverCert.der",
         "leftsendcert": "always",
@@ -88,6 +90,100 @@
     }
 }
 
+IPSEC_IKEV2_MSCHAPV2 = {
+    "conn IKEV2_MSCHAPV2": {
+        "keyexchange": "ikev2",
+        "left": LOCALHOST,
+        "leftid": LOCALHOST,
+        "leftcert": "serverCert.der",
+        "leftsubnet": "0.0.0.0/0",
+        "leftauth": "pubkey",
+        "leftsendcert": "always",
+        "right": "%any",
+        "rightid": "vpntest",
+        "rightauth": "eap-mschapv2",
+        "auto": "add"
+    }
+}
+
+IPSEC_IKEV2_PSK = {
+    "conn IKEV2_PSK": {
+        "keyexchange": "ikev2",
+        "left": LOCALHOST,
+        "leftid": LOCALHOST,
+        "leftauth": "psk",
+        "leftsubnet": "0.0.0.0/0",
+        "right": "%any",
+        "rightid": "vpntest",
+        "rightauth": "psk",
+        "auto": "add"
+    }
+}
+
+IPSEC_IKEV2_RSA = {
+    "conn IKEV2_RSA": {
+        "keyexchange": "ikev2",
+        "left": LOCALHOST,
+        "leftid": LOCALHOST,
+        "leftcert": "serverCert.der",
+        "leftsubnet": "0.0.0.0/0",
+        "leftauth": "pubkey",
+        "leftsendcert": "always",
+        "right": "%any",
+        "rightid": "vpntest@%s" % LOCALHOST,
+        "rightauth": "pubkey",
+        "rightcert": "clientCert.pem",
+        "auto": "add"
+    }
+}
+
+IPSEC_IKEV2_MSCHAPV2_HOSTNAME = {
+    "conn IKEV2_MSCHAPV2_HOSTNAME": {
+        "keyexchange": "ikev2",
+        "left": LOCALHOST,
+        "leftid": "strongswan-vpn-server.android-iperf.com",
+        "leftcert": "serverCert.der",
+        "leftsubnet": "0.0.0.0/0",
+        "leftauth": "pubkey",
+        "leftsendcert": "always",
+        "right": "%any",
+        "rightid": "vpntest",
+        "rightauth": "eap-mschapv2",
+        "auto": "add"
+    }
+}
+
+IPSEC_IKEV2_PSK_HOSTNAME = {
+    "conn IKEV2_PSK_HOSTNAME": {
+        "keyexchange": "ikev2",
+        "left": LOCALHOST,
+        "leftid": "strongswan-vpn-server.android-iperf.com",
+        "leftauth": "psk",
+        "leftsubnet": "0.0.0.0/0",
+        "right": "%any",
+        "rightid": "vpntest",
+        "rightauth": "psk",
+        "auto": "add"
+    }
+}
+
+IPSEC_IKEV2_RSA_HOSTNAME = {
+    "conn IKEV2_RSA_HOSTNAME": {
+        "keyexchange": "ikev2",
+        "left": LOCALHOST,
+        "leftid": "strongswan-vpn-server.android-iperf.com",
+        "leftcert": "serverCert.der",
+        "leftsubnet": "0.0.0.0/0",
+        "leftauth": "pubkey",
+        "leftsendcert": "always",
+        "right": "%any",
+        "rightid": "vpntest@strongswan-vpn-server.android-iperf.com",
+        "rightauth": "pubkey",
+        "rightcert": "clientCert.pem",
+        "auto": "add"
+    }
+}
+
 # parmas for lx2tpd
 
 XL2TPD_CONF_GLOBAL = (
@@ -149,7 +245,6 @@
     "iptables -I FORWARD  -m policy --dir out --pol ipsec --proto esp -j ACCEPT",
     "iptables -I OUTPUT   -m policy --dir out --pol ipsec --proto esp -j ACCEPT",
     "iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT",
-    "iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT",
     "iptables -A INPUT -p esp -j ACCEPT",
     "iptables -A INPUT -i eth0.2 -p udp --dport 500 -j ACCEPT",
     "iptables -A INPUT -i eth0.2 -p tcp --dport 500 -j ACCEPT",
diff --git a/acts/framework/acts/controllers/openwrt_lib/network_settings.py b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
index f632d57..b3c1e4e 100644
--- a/acts/framework/acts/controllers/openwrt_lib/network_settings.py
+++ b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
@@ -42,6 +42,7 @@
 XL2TPD_OPTION_CONFIG_PATH = "/etc/ppp/options.xl2tpd"
 FIREWALL_CUSTOM_OPTION_PATH = "/etc/firewall.user"
 PPP_CHAP_SECRET_PATH = "/etc/ppp/chap-secrets"
+IKEV2_VPN_CERT_KEYS_PATH = "/var/ikev2_cert.sh"
 TCPDUMP_DIR = "/tmp/tcpdump/"
 LOCALHOST = "192.168.1.1"
 DEFAULT_PACKAGE_INSTALL_TIMEOUT = 200
@@ -463,7 +464,11 @@
         # setup vpn server local ip
         self.setup_vpn_local_ip()
         # generate cert and key for rsa
-        self.generate_vpn_cert_keys(country, org)
+        if self.l2tp.name == "ikev2-server":
+            self.generate_ikev2_vpn_cert_keys(country, org)
+            self.add_resource_record(self.l2tp.hostname, LOCALHOST)
+        else:
+            self.generate_vpn_cert_keys(country, org)
         # restart service
         self.service_manager.need_restart(SERVICE_IPSEC)
         self.service_manager.need_restart(SERVICE_XL2TPD)
@@ -475,6 +480,8 @@
         self.config.discard("setup_vpn_l2tp_server")
         self.restore_firewall_rules_for_l2tp()
         self.remove_vpn_local_ip()
+        if self.l2tp.name == "ikev2-server":
+            self.clear_resource_record()
         self.service_manager.need_restart(SERVICE_IPSEC)
         self.service_manager.need_restart(SERVICE_XL2TPD)
         self.service_manager.need_restart(SERVICE_FIREWALL)
@@ -508,6 +515,12 @@
                 config.append("")
 
         config = []
+        load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2, True)
+        load_ipsec_config(network_const.IPSEC_IKEV2_PSK, True)
+        load_ipsec_config(network_const.IPSEC_IKEV2_RSA, True)
+        load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2_HOSTNAME, True)
+        load_ipsec_config(network_const.IPSEC_IKEV2_PSK_HOSTNAME, True)
+        load_ipsec_config(network_const.IPSEC_IKEV2_RSA_HOSTNAME, True)
         load_ipsec_config(network_const.IPSEC_CONF)
         load_ipsec_config(network_const.IPSEC_L2TP_PSK)
         load_ipsec_config(network_const.IPSEC_L2TP_RSA)
@@ -601,6 +614,54 @@
         self.ssh.run("mv clientPkcs.p12 /www/downloads/")
         self.ssh.run("chmod 664 /www/downloads/clientPkcs.p12")
 
+    def generate_ikev2_vpn_cert_keys(self, country, org):
+        rsa = "--type rsa"
+        lifetime = "--lifetime 365"
+        size = "--size 4096"
+
+        if not self.path_exists("/www/downloads/"):
+            self.ssh.run("mkdir /www/downloads/")
+
+        ikev2_vpn_cert_keys = [
+            "ipsec pki --gen %s %s --outform der > caKey.der" % (rsa, size),
+            "ipsec pki --self --ca %s --in caKey.der %s --dn "
+            "\"C=%s, O=%s, CN=%s\" --outform der > caCert.der" %
+            (lifetime, rsa, country, org, self.l2tp.hostname),
+            "ipsec pki --gen %s %s --outform der > serverKey.der" % (size, rsa),
+            "ipsec pki --pub --in serverKey.der %s | ipsec pki --issue %s "
+            r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s\" "
+            "--san %s --san %s --flag serverAuth --flag ikeIntermediate "
+            "--outform der > serverCert.der" % (rsa, lifetime, country, org,
+                                                self.l2tp.hostname, LOCALHOST,
+                                                self.l2tp.hostname),
+            "ipsec pki --gen %s %s --outform der > clientKey.der" % (size, rsa),
+            "ipsec pki --pub --in clientKey.der %s | ipsec pki --issue %s "
+            r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s@%s\" "
+            r"--san \"%s\" --san \"%s@%s\" --san \"%s@%s\" --outform der "
+            "> clientCert.der" % (rsa, lifetime, country, org, self.l2tp.username,
+                                  self.l2tp.hostname, self.l2tp.username,
+                                  self.l2tp.username, LOCALHOST,
+                                  self.l2tp.username, self.l2tp.hostname),
+            "openssl rsa -inform DER -in clientKey.der "
+            "-out clientKey.pem -outform PEM",
+            "openssl x509 -inform DER -in clientCert.der "
+            "-out clientCert.pem -outform PEM",
+            "openssl x509 -inform DER -in caCert.der "
+            "-out caCert.pem -outform PEM",
+            "openssl pkcs12 -in clientCert.pem -inkey  clientKey.pem "
+            "-certfile caCert.pem -export -out clientPkcs.p12 -passout pass:",
+            "mv caCert.pem /etc/ipsec.d/cacerts/",
+            "mv *Cert* /etc/ipsec.d/certs/",
+            "mv *Key* /etc/ipsec.d/private/",
+            "mv clientPkcs.p12 /www/downloads/",
+            "chmod 664 /www/downloads/clientPkcs.p12",
+        ]
+        file_string = "\n".join(ikev2_vpn_cert_keys)
+        self.create_config_file(file_string, IKEV2_VPN_CERT_KEYS_PATH)
+
+        self.ssh.run("chmod +x %s" % IKEV2_VPN_CERT_KEYS_PATH)
+        self.ssh.run("%s" % IKEV2_VPN_CERT_KEYS_PATH)
+
     def update_firewall_rules_list(self):
         """Update rule list in /etc/config/firewall."""
         new_rules_list = []
@@ -919,9 +980,11 @@
         return tcpdump_remote_path if pull_dir else None
 
     def clear_tcpdump(self):
-        self.ssh.run("killall tpcdump", ignore_status=True)
-        if self.ssh.run("pgrep tpcdump", ignore_status=True).stdout:
+        self.ssh.run("killall tcpdump", ignore_status=True)
+        if self.ssh.run("pgrep tcpdump", ignore_status=True).stdout:
             raise signals.TestFailure("Failed to clean up tcpdump process.")
+        if self.path_exists(TCPDUMP_DIR):
+            self.ssh.run("rm -f  %s/*" % TCPDUMP_DIR)
 
     def _get_tcpdump_pid(self, tcpdump_file_name):
         """Check tcpdump process on OpenWrt."""
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py
index 6c406b3..18c5ab3 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500.py
@@ -22,9 +22,10 @@
 from os import path
 from acts.controllers import abstract_inst
 
-DEFAULT_XLAPI_PATH = '/home/mobileharness/Rohde-Schwarz/XLAPI/7.51.21/venv/lib/python3.7/site-packages'
+DEFAULT_XLAPI_PATH = '/home/mobileharness/Rohde-Schwarz/XLAPI/latest/venv/lib/python3.7/site-packages'
 DEFAULT_LTE_STATE_CHANGE_TIMER = 10
-Default_CELL_SWITCH_ON_TIMER = 60
+DEFAULT_CELL_SWITCH_ON_TIMER = 60
+DEFAULT_ENDC_TIMER = 300
 
 logger = logging.getLogger('Xlapi_cmx500')
 
@@ -42,6 +43,13 @@
     'p0_nominal_pusch',
 ]
 
+LTE_MHZ_UPPER_BOUND_TO_RB = [
+    (1.5, 6),
+    (4.0, 15),
+    (7.5, 25),
+    (12.5, 50),
+    (17.5, 75),
+]
 
 class DciFormat(Enum):
     """Support DCI Formats for MIMOs."""
@@ -177,7 +185,7 @@
         self._config_antenna_ports()
         self.lte_rrc_state_change_timer = DEFAULT_LTE_STATE_CHANGE_TIMER
         self.rrc_state_change_time_enable = False
-        self.cell_switch_on_timer = Default_CELL_SWITCH_ON_TIMER
+        self.cell_switch_on_timer = DEFAULT_CELL_SWITCH_ON_TIMER
 
     # _config_antenna_ports for the special RF connection with cmw500 + cmx500.
     def _config_antenna_ports(self):
@@ -279,6 +287,10 @@
         """
         return self.bts[bts_index]
 
+    def get_network(self):
+        """ Gets the network object from cmx500 object."""
+        return self._network
+
     def init_lte_measurement(self):
         """Gets the class object for lte measurement which can be used to
         initiate measurements.
@@ -332,6 +344,26 @@
                 logger.info(
                     'The LTE cell status is {} after stop'.format(bts.is_on()))
 
+    def switch_on_nsa_signalling(self):
+        if self.bts:
+            self.disconnect()
+        logger.info('Switches on NSA signalling')
+        self.bts.append(LteBaseStation(self, self.lte_cell))
+        self.bts.append(NrBaseStation(self, self.nr_cell))
+        self.bts[0].start()
+        lte_cell_status = self.bts[0].wait_cell_on(self.cell_switch_on_timer)
+        if lte_cell_status:
+            logger.info('The LTE pcell status is on')
+        else:
+            raise CmxError('The LTE pcell cannot be switched on')
+
+        self.bts[1].start()
+        nr_cell_status = self.bts[1].wait_cell_on(self.cell_switch_on_timer)
+        if nr_cell_status:
+            logger.info('The NR cell status is on')
+        else:
+            raise CmxError('The NR cell cannot be switched on')
+
     def update_lte_cell_config(self, config):
         """Updates lte cell settings with config."""
         set_counts = 0
@@ -409,6 +441,7 @@
         self._cell = cell
         self._cmx = cmx
         self._cc = cmx.dut.cc(cell)
+        self._network = cmx.get_network()
 
     @property
     def band(self):
@@ -579,6 +612,8 @@
 
         # Sets num of crs antenna ports back to previous value
         self._cell.set_num_crs_antenna_ports(num_crs_antenna_ports)
+        self._network.apply_changes()
+
         if is_on:
             self._cell.start()
 
@@ -607,16 +642,19 @@
         return self._cell.get_dl_earfcn().to_freq().in_units(
                 Frequency.Units.GHz)
 
+    def _to_rb_bandwidth(self, bandwidth):
+        for idx in range(5):
+            if bandwidth < LTE_MHZ_UPPER_BOUND_TO_RB[idx][0]:
+                return LTE_MHZ_UPPER_BOUND_TO_RB[idx][1]
+        return 100
+
     def set_bandwidth(self, bandwidth):
         """Sets the channel bandwidth of the cell.
 
         Args:
-            bandwidth: channel bandwidth of cell.
+            bandwidth: channel bandwidth of cell in MHz.
         """
-        if not isinstance(bandwidth, LteBandwidth):
-            raise ValueError('bandwidth should be an instance of '
-                             'LteBandwidth.')
-        self._cell.set_bandwidth(bandwidth.value)
+        self._cell.set_bandwidth(self._to_rb_bandwidth(bandwidth))
 
     def set_cell_frequency_band(self, tdd_cfg=None, ssf_cfg=None):
         """Sets cell frequency band with tdd and ssf config.
@@ -639,6 +677,7 @@
                 subframe_assignment=tdd_subframe,
                 special_subframe_pattern=ssf_pattern))
         self._cell.stub.SetCellFrequencyBand(CellFrequencyBand(tdd=tdd))
+        self._network.apply_changes()
 
     def set_cfi(self, cfi):
         """Sets number of pdcch symbols (cfi).
@@ -807,5 +846,240 @@
 
         super().__init__(cmx, cell)
 
+    def _config_scheduler(self, dl_mcs=None, dl_mcs_table=None,
+                          dl_rb_alloc=None, dl_mimo_mode=None,
+                          ul_mcs=None, ul_mcs_table=None, ul_rb_alloc=None,
+                          ul_mimo_mode=None):
+
+        from rs_mrt.testenvironment.signaling.sri.rat.nr import McsTable
+
+        log_list = []
+        if dl_mcs:
+            log_list.append('dl_mcs: {}'.format(dl_mcs))
+        if ul_mcs:
+            log_list.append('ul_mcs: {}'.format(ul_mcs))
+
+        # If rb alloc is not a tuple, add 0 as start RBs for XLAPI NR scheduler
+        if dl_rb_alloc:
+            if not isinstance(dl_rb_alloc, tuple):
+                dl_rb_alloc = (0, dl_rb_alloc)
+            log_list.append('dl_rb_alloc: {}'.format(dl_rb_alloc))
+        if ul_rb_alloc:
+            if not isinstance(ul_rb_alloc, tuple):
+                ul_rb_alloc = (0, ul_rb_alloc)
+            log_list.append('ul_rb_alloc: {}'.format(ul_rb_alloc))
+        if dl_mcs_table:
+            dl_mcs_table = McsTable(dl_mcs_table)
+            log_list.append('dl_mcs_table: {}'.format(dl_mcs_table))
+        if ul_mcs_table:
+            ul_mcs_table = McsTable(ul_mcs_table)
+            log_list.append('ul_mcs_table: {}'.format(ul_mcs_table))
+        if dl_mimo_mode:
+            log_list.append('dl_mimo_mode: {}'.format(dl_mimo_mode))
+        if ul_mimo_mode:
+            log_list.append('ul_mimo_mode: {}'.format(ul_mimo_mode))
+
+        is_on = self._cell.is_on()
+        if is_on:
+            self._cell.stop()
+            time.sleep(1)
+        scheduler = self._cmx.dut.get_scheduler(self._cell)
+        logger.info('configure scheduler for {}'.format(','.join(log_list)))
+
+        scheduler.configure_ue_scheduler(
+                dl_mcs=dl_mcs, dl_mcs_table=dl_mcs_table,
+                dl_rb_alloc=dl_rb_alloc, dl_mimo_mode=dl_mimo_mode,
+                ul_mcs=ul_mcs, ul_mcs_table=ul_mcs_table,
+                ul_rb_alloc=ul_rb_alloc, ul_mimo_mode=ul_mimo_mode)
+        logger.info('Configure scheduler succeeds')
+        self._network.apply_changes()
+
+        if is_on:
+            self._cell.start()
+
+    def attach_as_secondary_cell(self, endc_timer=DEFAULT_ENDC_TIMER):
+        """Enable endc mode for NR cell.
+
+        Args:
+            endc_timer: timeout for endc state
+        """
+        logger.info('enable endc mode for nsa dual connection')
+        self._cmx.dut.signaling.nsa_dual_connect(self._cell)
+        time_count = 0
+        while time_count < endc_timer:
+            if str(self._cmx.dut.state.radio_connectivity) == \
+                    'RadioConnectivityMode.EPS_LTE_NR':
+                logger.info('enter endc mode')
+                return
+            time.sleep(1)
+            time_count += 1
+            if time_count % 30 == 0:
+                logger.info('did not reach endc at {} s'.format(time_count))
+        raise CmxError('Cannot reach endc after {} s'.format(endc_timer))
+
+    @property
+    def dl_channel(self):
+        """Gets the downlink channel of cell.
+
+        Return:
+            the downlink channel (earfcn) in int.
+        """
+        return int(self._cell.get_dl_ref_a())
+
+    def _bandwidth_to_carrier_bandwidth(self, bandwidth):
+        """Converts bandwidth in MHz to CarrierBandwidth.
+            CarrierBandwidth Enum in XLAPI:
+                MHZ_5 = 0
+                MHZ_10 = 1
+                MHZ_15 = 2
+                MHZ_20 = 3
+                MHZ_25 = 4
+                MHZ_30 = 5
+                MHZ_40 = 6
+                MHZ_50 = 7
+                MHZ_60 = 8
+                MHZ_70 = 9
+                MHZ_80 = 10
+                MHZ_90 = 11
+                MHZ_100 = 12
+                MHZ_200 = 13
+                MHZ_400 = 14
+        Args:
+            bandwidth: channel bandwidth in MHz.
+
+        Return:
+            the corresponding NR Carrier Bandwidth.
+        """
+        from mrtype.nr.frequency import CarrierBandwidth
+        if bandwidth > 100:
+            return CarrierBandwidth(12 + bandwidth // 200)
+        elif bandwidth > 30:
+            return CarrierBandwidth(2 + bandwidth // 10)
+        else:
+            return CarrierBandwidth(bandwidth // 5 - 1)
+
+    def set_band(self, band, frequency_range=None):
+        """Sets the Band of cell.
+
+        Args:
+            band: band of cell.
+            frequency_range: LOW, MID and HIGH for NR cell
+        """
+        from mrtype.frequency import FrequencyRange
+        if not frequency_range or frequency_range.upper() == 'LOW':
+            frequency_range = FrequencyRange.LOW
+        elif frequency_range.upper() == 'MID':
+            frequency_range = FrequencyRange.MID
+        elif frequency_range.upper() == 'HIGH':
+            frequency_range = FrequencyRange.HIGH
+        else:
+            raise CmxError('Wrong type FrequencyRange')
+
+        self._cell.set_dl_ref_a_offset(band, frequency_range)
+        logger.info('The band is set to {} and is {} after setting'.format(
+                band, self.band))
+
+    def set_bandwidth(self, bandwidth, scs=None):
+        """Sets the channel bandwidth of the cell.
+
+        Args:
+            bandwidth: channel bandwidth of cell.
+            scs: subcarrier spacing (SCS) of resource grid 0
+        """
+        if not scs:
+            scs = self._cell.get_scs()
+        self._cell.set_carrier_bandwidth_and_scs(
+                self._bandwidth_to_carrier_bandwidth(bandwidth), scs)
+        logger.info('The bandwidth in MHz is {}. After setting, the value is {}'
+                    .format(bandwidth, str(self._cell.get_carrier_bandwidth())))
+
+    def set_dl_channel(self, channel):
+        """Sets the downlink channel number of cell.
+
+        Args:
+            channel: downlink channel number of cell.
+        """
+        from mrtype.nr.frequency import NrArfcn
+        if self.dl_channel == channel:
+            logger.info('The dl_channel was at {}'.format(self.dl_channel))
+            return
+        self._cell.set_dl_ref_a_offset(self.band, NrArfcn(channel))
+        logger.info('The dl_channel was set to {}'.format(self.dl_channel))
+
+    def set_dl_modulation_table(self, modulation):
+        """Sets down link modulation table.
+
+        Args:
+            modulation: modulation table setting (ModulationType).
+        """
+        if not isinstance(modulation, ModulationType):
+            raise CmxError('The modulation is not the type of Modulation')
+        self._config_scheduler(dl_mcs_table=modulation.value)
+
+    def set_mimo_mode(self, mimo):
+        """Sets mimo mode for NR nsa scenario.
+
+        Args:
+            mimo: the mimo mode.
+        """
+        from rs_mrt.testenvironment.signaling.sri.rat.nr import DownlinkMimoMode
+        if not isinstance(mimo, MimoModes):
+            raise CmxError("Wrong type of mimo mode")
+
+        is_on = self._cell.is_on()
+        if is_on:
+            self._cell.stop()
+        self._cc.set_dl_mimo_mode(DownlinkMimoMode.Enum(mimo.value))
+        if is_on:
+            self._cell.start()
+
+    def set_scheduling_mode(
+        self, mcs_dl=None, mcs_ul=None, nrb_dl=None, nrb_ul=None):
+        """Sets scheduling mode.
+
+        Args:
+            mcs_dl: Downlink MCS.
+            mcs_ul: Uplink MCS.
+            nrb_dl: Number of RBs for downlink.
+            nrb_ul: Number of RBs for uplink.
+        """
+        self._config_scheduler(dl_mcs=mcs_dl, ul_mcs=mcs_ul, dl_rb_alloc=nrb_dl,
+                ul_rb_alloc=nrb_ul)
+
+    def set_ssf_config(self, ssf_config):
+        """Sets ssf subframe assignment with tdd_config.
+
+        Args:
+            ssf_config: the special subframe pattern config (from 1-9).
+        """
+        raise CmxError('the set ssf config for nr did not implemente yet')
+
+    def set_tdd_config(self, tdd_config):
+        """Sets tdd subframe assignment with tdd_config.
+
+        Args:
+            tdd_config: the subframe assignemnt config (from 0-6).
+        """
+        raise CmxError('the set tdd config for nr did not implemente yet')
+
+    def set_transmission_mode(self, transmission_mode):
+        """Sets transmission mode with schedular.
+
+        Args:
+            transmission_mode: the download link transmission mode.
+        """
+        logger.info('The set transmission mode for nr is set by mimo mode')
+
+    def set_ul_modulation_table(self, modulation):
+        """Sets down link modulation table.
+
+        Args:
+            modulation: modulation table setting (ModulationType).
+        """
+        if not isinstance(modulation, ModulationType):
+            raise CmxError('The modulation is not the type of Modulation')
+        self._config_scheduler(ul_mcs_table=modulation.value)
+
+
 class CmxError(Exception):
     """Class to raise exceptions related to cmx."""
diff --git a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py
index bd01759..ca281d1 100644
--- a/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py
+++ b/acts/framework/acts/controllers/rohdeschwarz_lib/cmx500_cellular_simulator.py
@@ -42,14 +42,6 @@
     LteSimulation.MimoMode.MIMO_4x4: cmx500.MimoModes.MIMO4x4,
 }
 
-MHZ_UPPER_BOUND_TO_RB = [
-    (1.5, 6),
-    (4.0, 15),
-    (7.5, 25),
-    (12.5, 50),
-    (17.5, 75),
-]
-
 
 class CMX500CellularSimulator(cc.AbstractCellularSimulator):
     """ A cellular simulator for telephony simulations based on the CMX 500
@@ -87,7 +79,8 @@
 
     def setup_nr_nsa_scenario(self):
         """ Configures the equipment for an NR non stand alone simulation. """
-        raise NotImplementedError()
+        self.log.info('setup nsa scenario (start lte cell and nr cell')
+        self.cmx.switch_on_nsa_signalling()
 
     def set_band_combination(self, bands):
         """ Prepares the test equipment for the indicated band combination.
@@ -110,7 +103,7 @@
         self.cmx.lte_rrc_state_change_timer = time
 
 
-    def set_band(self, bts_index, band):
+    def set_band(self, bts_index, band, frequency_range=None):
         """ Sets the band for the indicated base station.
 
         Args:
@@ -118,7 +111,11 @@
             band: the new band
         """
         self.log.info('set band to {}'.format(band))
-        self.bts[bts_index].set_band(int(band))
+        if frequency_range:
+            self.bts[bts_index].set_band(
+                    int(band), frequency_range=frequency_range)
+        else:
+            self.bts[bts_index].set_band(int(band))
 
     def get_duplex_mode(self, band):
         """ Determines if the band uses FDD or TDD duplex mode
@@ -177,24 +174,18 @@
             ssf_config: the new ssf config number (from 0 to 9)
         """
         self.log.info('set ssf config to {}'.format(ssf_config))
-        self.bts[bts_index].set_tdd_config(ssf_config)
+        self.bts[bts_index].set_ssf_config(ssf_config)
 
     def set_bandwidth(self, bts_index, bandwidth):
         """ Sets the bandwidth for the indicated base station.
 
         Args:
             bts_index: the base station number
-            bandwidth: the new bandwidth in rb
+            bandwidth: the new bandwidth in MHz
         """
         self.log.info('set bandwidth of bts {} to {}'.format(
                 bts_index, bandwidth))
-        self.bts[bts_index].set_bandwidth(self._to_rb_bandwidth(bandwidth))
-
-    def _to_rb_bandwidth(self, bandwidth):
-        for idx in range(5):
-            if bandwidth < MHZ_UPPER_BOUND_TO_RB[idx][0]:
-                return LteBandwidth(MHZ_UPPER_BOUND_TO_RB[idx][1])
-        return LteBandwidth(100)
+        self.bts[bts_index].set_bandwidth(int(bandwidth))
 
     def set_downlink_channel_number(self, bts_index, channel_number):
         """ Sets the downlink channel number for the indicated base station.
@@ -338,7 +329,8 @@
             ue_capability_enquiry: UE capability enquiry message to be sent to
         the UE before starting carrier aggregation.
         """
-        raise NotImplementedError()
+        self.wait_until_communication_state()
+        self.bts[1].attach_as_secondary_cell()
 
     def wait_until_attached(self, timeout=120):
         """ Waits until the DUT is attached to the primary carrier.
diff --git a/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py b/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
index dbc59e7..959274d 100644
--- a/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
+++ b/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
@@ -111,12 +111,12 @@
         self._listen_for_port_lock = threading.Lock()
         self._sl4a_ports = set()
         self.adb = adb
-        self.log = logger.create_logger(
-            lambda msg: '[SL4A Manager|%s] %s' % (adb.serial, msg))
+        self.log = logger.create_logger(lambda msg: '[SL4A Manager|%s] %s' % (
+            adb.serial, msg))
         self.sessions = {}
         self._started = False
-        self.error_reporter = error_reporter.ErrorReporter(
-            'SL4A %s' % adb.serial)
+        self.error_reporter = error_reporter.ErrorReporter('SL4A %s' %
+                                                           adb.serial)
 
     @property
     def sl4a_ports_in_use(self):
@@ -163,8 +163,8 @@
 
         raise rpc_client.Sl4aConnectionError(
             'Unable to find a valid open port for a new server connection. '
-            'Expected port: %s. Open ports: %s' % (device_port,
-                                                   self._sl4a_ports))
+            'Expected port: %s. Open ports: %s' %
+            (device_port, self._sl4a_ports))
 
     def _get_all_ports_command(self):
         """Returns the list of all ports from the command to get ports."""
@@ -242,6 +242,7 @@
     def create_session(self,
                        max_connections=None,
                        client_port=0,
+                       forwarded_port=0,
                        server_port=None):
         """Creates an SL4A server with the given ports if possible.
 
@@ -250,7 +251,9 @@
         be randomized.
 
         Args:
-            client_port: The port on the host machine
+            client_port: The client port on the host machine
+            forwarded_port: The server port on the host machine forwarded
+                            by adb from the Android device
             server_port: The port on the Android device.
             max_connections: The max number of client connections for the
                 session.
@@ -266,22 +269,25 @@
             # Otherwise, open a new server on a random port.
             else:
                 server_port = 0
+        self.log.debug(
+            "Creating SL4A session client_port={}, forwarded_port={}, server_port={}"
+            .format(client_port, forwarded_port, server_port))
         self.start_sl4a_service()
-        session = sl4a_session.Sl4aSession(
-            self.adb,
-            client_port,
-            server_port,
-            self.obtain_sl4a_server,
-            self.diagnose_failure,
-            max_connections=max_connections)
+        session = sl4a_session.Sl4aSession(self.adb,
+                                           client_port,
+                                           server_port,
+                                           self.obtain_sl4a_server,
+                                           self.diagnose_failure,
+                                           forwarded_port,
+                                           max_connections=max_connections)
         self.sessions[session.uid] = session
         return session
 
     def stop_service(self):
         """Stops The SL4A Service. Force-stops the SL4A apk."""
         try:
-            self.adb.shell(
-                'am force-stop %s' % SL4A_PKG_NAME, ignore_status=True)
+            self.adb.shell('am force-stop %s' % SL4A_PKG_NAME,
+                           ignore_status=True)
         except Exception as e:
             self.log.warning("Fail to stop package %s: %s", SL4A_PKG_NAME, e)
         self._started = False
diff --git a/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py b/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
index c0a4e1d..04fd787 100644
--- a/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
+++ b/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
@@ -55,6 +55,7 @@
                  device_port,
                  get_server_port_func,
                  on_error_callback,
+                 forwarded_port=0,
                  max_connections=None):
         """Creates an SL4A Session.
 
@@ -67,6 +68,8 @@
                 server for its first connection.
             device_port: The SL4A server port to be used as a hint for which
                 SL4A server to connect to.
+            forwarded_port: The server port on host machine forwarded by adb
+                            from Android device to accept SL4A connection
         """
         self._event_dispatcher = None
         self._terminate_lock = threading.Lock()
@@ -79,24 +82,24 @@
 
         self.log = logger.create_logger(_log_formatter)
 
+        self.forwarded_port = forwarded_port
         self.server_port = device_port
         self.uid = UNKNOWN_UID
         self.obtain_server_port = get_server_port_func
         self._on_error_callback = on_error_callback
 
         connection_creator = self._rpc_connection_creator(host_port)
-        self.rpc_client = rpc_client.RpcClient(
-            self.uid,
-            self.adb.serial,
-            self.diagnose_failure,
-            connection_creator,
-            max_connections=max_connections)
+        self.rpc_client = rpc_client.RpcClient(self.uid,
+                                               self.adb.serial,
+                                               self.diagnose_failure,
+                                               connection_creator,
+                                               max_connections=max_connections)
 
     def _rpc_connection_creator(self, host_port):
         def create_client(uid):
-            return self._create_rpc_connection(
-                ports=sl4a_ports.Sl4aPorts(host_port, 0, self.server_port),
-                uid=uid)
+            return self._create_rpc_connection(ports=sl4a_ports.Sl4aPorts(
+                host_port, self.forwarded_port, self.server_port),
+                                               uid=uid)
 
         return create_client
 
@@ -156,10 +159,14 @@
         ports.server_port = self.obtain_server_port(ports.server_port)
         self.server_port = ports.server_port
         # Forward the device port to the host.
-        ports.forwarded_port = self._create_forwarded_port(ports.server_port)
+        ports.forwarded_port = self._create_forwarded_port(
+            ports.server_port, hinted_port=ports.forwarded_port)
         client_socket, fd = self._create_client_side_connection(ports)
-        client = rpc_connection.RpcConnection(
-            self.adb, ports, client_socket, fd, uid=uid)
+        client = rpc_connection.RpcConnection(self.adb,
+                                              ports,
+                                              client_socket,
+                                              fd,
+                                              uid=uid)
         client.open()
         if uid == UNKNOWN_UID:
             self.uid = client.uid
@@ -195,9 +202,9 @@
             except OSError as e:
                 # If the port is in use, log and ask for any open port.
                 if e.errno == errno.EADDRINUSE:
-                    self.log.warning(
-                        'Port %s is already in use on the host. '
-                        'Generating a random port.' % ports.client_port)
+                    self.log.warning('Port %s is already in use on the host. '
+                                     'Generating a random port.' %
+                                     ports.client_port)
                     ports.client_port = 0
                     return self._create_client_side_connection(ports)
                 raise
diff --git a/acts/framework/tests/acts_utils_test.py b/acts/framework/tests/acts_utils_test.py
index 2c7c8ab..e662db8 100755
--- a/acts/framework/tests/acts_utils_test.py
+++ b/acts/framework/tests/acts_utils_test.py
@@ -72,74 +72,68 @@
 FUCHSIA_INTERFACES = {
     'id':
     '1',
-    'result': [{
-        'features':
-        4,
-        'filepath':
-        '[none]',
-        'id':
-        1,
-        'ipv4_addresses': [[127, 0, 0, 1]],
-        'ipv6_addresses': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]],
-        'is_administrative_status_enabled':
-        True,
-        'is_physical_status_up':
-        True,
-        'mac': [0, 0, 0, 0, 0, 0],
-        'mtu':
-        65536,
-        'name':
-        'lo',
-        'topopath':
-        'loopback'
-    }, {
-        'features':
-        0,
-        'filepath':
-        '/dev/class/ethernet/000',
-        'id':
-        2,
-        'ipv4_addresses': [[100, 127, 110, 79]],
-        'ipv6_addresses':
-        [[254, 128, 0, 0, 0, 0, 0, 0, 198, 109, 60, 117, 44, 236, 29, 114],
-         [36, 1, 250, 0, 4, 128, 122, 0, 141, 79, 133, 255, 204, 92, 120, 126],
-         [36, 1, 250, 0, 4, 128, 122, 0, 4, 89, 185, 147, 252, 191, 20, 25]],
-        'is_administrative_status_enabled':
-        True,
-        'is_physical_status_up':
-        True,
-        'mac': [0, 224, 76, 5, 76, 229],
-        'mtu':
-        1514,
-        'name':
-        'eno1',
-        'topopath':
-        '@/dev/xhci/xhci/usb-bus/001/001/ifc-000/usb-cdc-ecm/ethernet'
-    }, {
-        'features':
-        1,
-        'filepath':
-        '/dev/class/ethernet/001',
-        'id':
-        3,
-        'ipv4_addresses': [],
-        'ipv6_addresses':
-        [[254, 128, 0, 0, 0, 0, 0, 0, 96, 255, 93, 96, 52, 253, 253, 243],
-         [254, 128, 0, 0, 0, 0, 0, 0, 70, 7, 11, 255, 254, 118, 126, 192]],
-        'is_administrative_status_enabled':
-        False,
-        'is_physical_status_up':
-        False,
-        'mac': [68, 7, 11, 118, 126, 192],
-        'mtu':
-        1500,
-        'name':
-        'wlanxc0',
-        'topopath':
-        '@/dev/wifi/wlanphy/wlanif-client/wlan-ethernet/ethernet'
-    }],
+    'result': [
+        {
+            'id': 1,
+            'name': 'lo',
+            'ipv4_addresses': [
+                [127, 0, 0, 1],
+            ],
+            'ipv6_addresses': [
+                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+            ],
+            'online': True,
+            'mac': [0, 0, 0, 0, 0, 0],
+        },
+        {
+            'id':
+            2,
+            'name':
+            'eno1',
+            'ipv4_addresses': [
+                [100, 127, 110, 79],
+            ],
+            'ipv6_addresses': [
+                [
+                    254, 128, 0, 0, 0, 0, 0, 0, 198, 109, 60, 117, 44, 236, 29,
+                    114
+                ],
+                [
+                    36, 1, 250, 0, 4, 128, 122, 0, 141, 79, 133, 255, 204, 92,
+                    120, 126
+                ],
+                [
+                    36, 1, 250, 0, 4, 128, 122, 0, 4, 89, 185, 147, 252, 191,
+                    20, 25
+                ],
+            ],
+            'online':
+            True,
+            'mac': [0, 224, 76, 5, 76, 229],
+        },
+        {
+            'id':
+            3,
+            'name':
+            'wlanxc0',
+            'ipv4_addresses': [],
+            'ipv6_addresses': [
+                [
+                    254, 128, 0, 0, 0, 0, 0, 0, 96, 255, 93, 96, 52, 253, 253,
+                    243
+                ],
+                [
+                    254, 128, 0, 0, 0, 0, 0, 0, 70, 7, 11, 255, 254, 118, 126,
+                    192
+                ],
+            ],
+            'online':
+            False,
+            'mac': [68, 7, 11, 118, 126, 192],
+        },
+    ],
     'error':
-    None
+    None,
 }
 
 CORRECT_FULL_IP_LIST = {
diff --git a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
index a39eeed..ba05a53 100644
--- a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
@@ -13,6 +13,9 @@
 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
+import os
+
+from acts import context
 from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
 
 from mobly import utils
@@ -54,3 +57,24 @@
 
         if device.hard_reboot_on_fail:
             device.reboot(reboot_type='hard', testbed_pdus=self.pdu_devices)
+
+    def download_ap_logs(self):
+        """Downloads the DHCP and hostapad logs from the access_point.
+
+        Using the current TestClassContext and TestCaseContext this method pulls
+        the DHCP and hostapd logs and outputs them to the correct path.
+        """
+        current_path = context.get_current_context().get_full_output_path()
+        dhcp_full_out_path = os.path.join(current_path, "dhcp_log.txt")
+
+        dhcp_log_file = open(dhcp_full_out_path, 'w')
+        dhcp_log_file.write(self.access_point.get_dhcp_logs())
+        dhcp_log_file.close()
+
+        hostapd_logs = self.access_point.get_hostapd_logs()
+        for interface in hostapd_logs:
+            out_name = interface + "_hostapd_log.txt"
+            hostapd_full_out_path = os.path.join(current_path, out_name)
+            hostapd_log_file = open(hostapd_full_out_path, 'w')
+            hostapd_log_file.write(hostapd_logs[interface])
+            hostapd_log_file.close()
diff --git a/acts_tests/acts_contrib/test_utils/bt/bt_constants.py b/acts_tests/acts_contrib/test_utils/bt/bt_constants.py
index f7bc93f..71cebd7 100644
--- a/acts_tests/acts_contrib/test_utils/bt/bt_constants.py
+++ b/acts_tests/acts_contrib/test_utils/bt/bt_constants.py
@@ -282,6 +282,12 @@
     "high": 3
 }
 
+# Bluetooth Low Energy advertise settings own address type
+ble_advertise_settings_own_address_types = {
+    "public": 0,
+    "random": 1
+}
+
 # Bluetooth Low Energy service uuids for specific devices
 ble_uuids = {
     "p_service": "0000feef-0000-1000-8000-00805f9b34fb",
diff --git a/acts_tests/acts_contrib/test_utils/net/net_test_utils.py b/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
index c2e4de4..81416c8 100644
--- a/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
@@ -16,7 +16,6 @@
 import logging
 import os
 import re
-import subprocess
 import time
 import urllib.request
 
@@ -33,6 +32,7 @@
 from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
 from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
 from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
+
 from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
 from scapy.config import conf
 from scapy.compat import plain_str
@@ -43,7 +43,6 @@
 TCPDUMP_PATH = "/data/local/tmp/"
 USB_CHARGE_MODE = "svc usb setFunctions"
 USB_TETHERING_MODE = "svc usb setFunctions rndis"
-USB_TETHERING_MODE_NCM = "svc usb setFunctions ncm"
 DEVICE_IP_ADDRESS = "ip address"
 LOCALHOST = "192.168.1.1"
 
@@ -510,59 +509,15 @@
 
 
 def start_usb_tethering(ad):
-    """Start USB tethering.
+    """Start USB tethering using #startTethering API.
 
-    Note: Start USB tethering with svc command will skip the entitlement check
-    flow, which is supported by carrier ATT, VZW, and SoftBank, and lead tests
-    to failed.
-    Since we're still using svc command to enable the USB tethering, make sure
-    your carrier doesn't support the entitlement.
+    Enable USB tethering by #startTethering API will break the RPC session,
+    Make sure you call #ad.recreate_services after call this API - b/149116235
 
     Args:
-        ad: android device object
+        ad: AndroidDevice object
     """
-    # TODO: test USB tethering by #startTethering API - b/149116235
-    if is_carrier_supports_entitlement(ad):
-        raise signals.TestFailure(
-            "Carrier supports entitlement, fail to enable the USB tethering.")
-    if not start_usb_tethering_rndis(ad) and not start_usb_tethering_ncm(ad):
-        raise signals.TestFailure("Unable to enable USB tethering.")
-
-
-def start_usb_tethering_rndis(ad):
-    """Start USB tethering using RNDIS.
-
-    Args:
-        ad: Android device object
-    Return:
-        true if USB tethering enabled
-    """
-    ad.log.info("Starting USB Tethering RNDIS")
-    ad.stop_services()
-    ad.adb.shell(USB_TETHERING_MODE, ignore_status=True)
-    ad.adb.wait_for_device()
-    ad.start_services()
-    if "rndis" not in ad.adb.shell(DEVICE_IP_ADDRESS):
-        return False
-    return True
-
-
-def start_usb_tethering_ncm(ad):
-    """Start USB tethering using NCM.
-
-    Args:
-        ad: Android device object
-    Return:
-        true if USB tethering enabled.
-    """
-    ad.log.info("Starting USB Tethering NCM")
-    ad.stop_services()
-    ad.adb.shell(USB_TETHERING_MODE_NCM, ignore_status=True)
-    ad.adb.wait_for_device()
-    ad.start_services()
-    if "ncm" not in ad.adb.shell(DEVICE_IP_ADDRESS):
-        return False
-    return True
+    ad.droid.connectivityStartTethering(tel_defines.TETHERING_USB, False)
 
 
 def stop_usb_tethering(ad):
diff --git a/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py b/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
index 4ee6b16..9ff86be 100644
--- a/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
@@ -126,7 +126,7 @@
                 adjust_gradually = self.user_params.get('adjust_gradually')
             if adjust_gradually:
                 self.log.info("adjust wifi signal set mini-circuits to %s" %(power))
-                self.adjust_atten_slowly(10, NO_SERVICE_AREA)
+                self.adjust_atten_slowly(10, NO_WIFI_AREA)
             else:
                 self.log.info("adjust wifi signal and set mini-circuits to %s" %(power))
                 self.attenuators[WIFI_PORT].set_atten(power)
@@ -175,7 +175,7 @@
         """adjust attenuator slowly
         Args:
             adjust_level: adjust power level for each cycle
-            move_to: no service area, in service area, wifi area
+            move_to: NO_SERVICE_AREA, IN_SERVICE_AREA , WIFI_AREA, NO_WIFI_AREA
             step: adjust attenuator how many time
             step_time: wait for how many sec for each loop
         Returns:
@@ -225,7 +225,7 @@
         return True
 
     def verify_device_status(self, ad, call_type=None, end_call=True,
-        talk_time=30, verify_data=True, verify_voice=True, retry=True, data_retries=2):
+        talk_time=30, verify_data=True, verify_voice=True, data_retries=2, voice_retries=2):
         """verfiy device status includes network service, data connection and voice call
         Args:
             ad: android device
@@ -234,37 +234,39 @@
             talk_time: in call duration in sec
             verify_data: flag to check data connection
             verify_voice: flag to check voice
+            data_retries: retry times for data verification
+            voice_retris:retry times for voice call
         Returns:
             return True if pass
         """
-        test_result = True
         tasks = [(check_network_service, (ad, )) for ad in self.android_devices]
         if not multithread_func(self.log, tasks):
             log_screen_shot(ad, "check_network_service_fail")
-            ad.log.info("check_network_service_fail")
-            test_result = False
-        if retry:
-            if call_type:
-                tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time, 3))
-                    for ad in self.android_devices]
-                test_result = multithread_func(self.log, tasks)
-        elif verify_data and test_result:
+            ad.log.info("check_network_service fail")
+            return False
+        else:
+            self.log.info("check_network_service pass")
+        if verify_data:
             tasks = [(verify_data_connection, (ad, data_retries ))
                 for ad in self.android_devices]
             if not multithread_func(self.log, tasks):
                 log_screen_shot(ad, "verify_data_connection_fail")
                 ad.log.info("verify_data_connection_fail")
-                test_result = False
-        elif verify_voice and test_result:
+                return False
+            else:
+                self.log.info("verify_data_connection pass")
+        if verify_voice:
             if call_type:
-                tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time))
-                    for ad in self.android_devices]
+                tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time,
+                    voice_retries)) for ad in self.android_devices]
             if not multithread_func(self.log, tasks):
                 log_screen_shot(ad, "verify_voice_call_fail")
                 ad.log.info("verify_voice_call_fail")
-                test_result = False
-        return test_result
-
+                return False
+            else:
+                self.log.info("verify_voice_call pass")
+                return True
+        return True
 
     def _on_failure(self, error_msg="", assert_on_fail=True, test_result=False):
         """ operation on fail
@@ -279,3 +281,4 @@
         for ad in self.android_devices:
             log_screen_shot(ad, error_msg)
         self.log.info(error_msg)
+
diff --git a/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py b/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
index 60941ce..ca65cb8 100644
--- a/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
@@ -503,6 +503,11 @@
         stop_tcpdumps(self.android_devices)
 
     def on_fail(self, test_name, begin_time):
+        for ad in self.android_devices:
+            # open Phone information page
+            ad.adb.shell("am start -n com.android.phone/.settings.RadioInfo")
+            time.sleep(3)
+            ad.screenshot(f"{ad.serial}_last_screen")
         self._take_bug_report(test_name, begin_time)
 
     def on_pass(self, test_name, begin_time):
diff --git a/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py b/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
index 87f0e68..2e4cfd4 100644
--- a/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
@@ -15,7 +15,6 @@
 #   limitations under the License.
 
 import time
-
 from acts_contrib.test_utils.tel.gft_inout_defines import VOLTE_CALL
 from acts_contrib.test_utils.tel.gft_inout_defines import CSFB_CALL
 from acts_contrib.test_utils.tel.gft_inout_defines import WFC_CALL
@@ -61,6 +60,7 @@
         %(timeout, service_state))
     return False
 
+
 def check_back_to_service_time(ad, timeout=120):
     """ check device is back to service or not
 
@@ -90,6 +90,7 @@
         %(timeout, service_state))
     return False
 
+
 def check_network_service(ad):
     """ check network service
 
@@ -231,7 +232,8 @@
         ad.log.error("device is not in call")
     return "UNKNOWN"
 
-def verify_data_connection(ad, retries=1, retry_time=30):
+
+def verify_data_connection(ad, retries=3, retry_time=30):
     """ verify data connection
 
         Args:
@@ -247,19 +249,18 @@
         wifi_info = ad.droid.wifiGetConnectionInfo()
         if wifi_info["supplicant_state"] == "completed":
             ad.log.info("Wifi is connected=%s" %(wifi_info["SSID"]))
-        else:
-            ad.log.info("verify_data_connection attempt %d", i + 1)
-            if not verify_internet_connection(ad.log, ad, retries=3):
-                data_state = ad.droid.telephonyGetDataConnectionState()
-                network_type_data = ad.droid.telephonyGetCurrentDataNetworkType()
-                ad.log.error("verify_internet fail. data_state=%s, network_type_data=%s"
+        ad.log.info("verify_data_connection attempt %d", i + 1)
+        if not verify_internet_connection(ad.log, ad, retries=3):
+            data_state = ad.droid.telephonyGetDataConnectionState()
+            network_type_data = ad.droid.telephonyGetCurrentDataNetworkType()
+            ad.log.error("verify_internet fail. data_state=%s, network_type_data=%s"
                 %(data_state, network_type_data))
-                ad.log.info("verify_data_connection fail attempt %d", i + 1)
-                log_screen_shot(ad, "verify_internet")
-                time.sleep(retry_time)
-            else:
-                ad.log.info("verify_data_connection pass")
-                return True
+            ad.log.info("verify_data_connection fail attempt %d", i + 1)
+            log_screen_shot(ad, "verify_internet")
+            time.sleep(retry_time)
+        else:
+            ad.log.info("verify_data_connection pass")
+            return True
     return False
 
 
@@ -282,6 +283,7 @@
     ad.log.info("telephonyIsVolteAvailable=%s" %(r4))
     return r1
 
+
 def browsing_test_ping_retry(ad):
     """ If browse test fails, use ping to test data connection
 
@@ -300,8 +302,4 @@
             ad.log.info("Ping fail!")
             return False
     else:
-        ad.log.info("Successful to browse websites!")
-
-
-
-
+        ad.log.info("Successful to browse websites!")
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
index 13838d2..5b81979 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
@@ -38,46 +38,53 @@
 from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
 
 
-def provision_device_for_5g(log, ads, nr_type=None):
+def provision_device_for_5g(log, ads, nr_type = None, mmwave = None):
     """Provision Devices for 5G
 
     Args:
         log: Log object.
         ads: android device object(s).
-        nr_type: NR network type
+        nr_type: NR network type.
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
 
     Returns:
         True: Device(s) are provisioned on 5G
         False: Device(s) are not provisioned on 5G
     """
     if nr_type == 'sa':
-        if not provision_device_for_5g_sa(log, ads):
+        if not provision_device_for_5g_sa(
+            log, ads, mmwave=mmwave):
             return False
     elif nr_type == 'nsa':
-        if not provision_device_for_5g_nsa(log, ads, nr_type='nsa'):
+        if not provision_device_for_5g_nsa(
+            log, ads, mmwave=mmwave):
             return False
     elif nr_type == 'mmwave':
-        if not provision_device_for_5g_nsa(log, ads, nr_type='mmwave'):
+        if not provision_device_for_5g_nsa(
+            log, ads, mmwave=mmwave):
             return False
     else:
-        if not provision_device_for_5g_nsa(log, ads, nr_type='nsa'):
+        if not provision_device_for_5g_nsa(
+            log, ads, mmwave=mmwave):
             return False
     return True
 
 
-def provision_device_for_5g_nsa(log, ads, nr_type=None):
+def provision_device_for_5g_nsa(log, ads, mmwave = None):
     """Provision Devices for 5G NSA
 
     Args:
         log: Log object.
         ads: android device object(s).
-        nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
-                wave
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
 
     Returns:
         True: Device(s) are provisioned on 5G NSA
         False: Device(s) are not provisioned on 5G NSA
     """
+
     if isinstance(ads, list):
         # Mode Pref
         tasks = [(set_preferred_mode_for_5g, [ad]) for ad in ads]
@@ -85,7 +92,7 @@
             log.error("failed to set preferred network mode on 5g")
             return False
         # Attach
-        tasks = [(is_current_network_5g_nsa, [ad, nr_type]) for ad in ads]
+        tasks = [(is_current_network_5g_nsa, [ad, None, mmwave]) for ad in ads]
         if not multithread_func(log, tasks):
             log.error("phone not on 5g")
             return False
@@ -95,7 +102,7 @@
         set_preferred_mode_for_5g(ads)
 
         # Attach nsa5g
-        if not is_current_network_5g_nsa(ads, nr_type):
+        if not is_current_network_5g_nsa(ads, mmwave=mmwave):
             ads.log.error("Phone not attached on 5g")
             return False
         return True
@@ -177,29 +184,32 @@
     return True
 
 
-def verify_5g_attach_for_both_devices(log, ads, nr_type=None):
+def verify_5g_attach_for_both_devices(log, ads, nr_type = None, mmwave = None):
     """Verify the network is attached
 
     Args:
         log: Log object.
         ads: android device object(s).
-        nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
-                wave
+        nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone,
+            'mmwave' for 5G millimeter wave.
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
 
     Returns:
         True: Device(s) are attached on 5G
         False: Device(s) are not attached on 5G NSA
     """
+
     if nr_type=='sa':
         # Attach
-        tasks = [(is_current_network_5g_sa, [ad]) for ad in ads]
+        tasks = [(is_current_network_5g_sa, [ad, None, mmwave]) for ad in ads]
         if not multithread_func(log, tasks):
             log.error("phone not on 5g sa")
             return False
         return True
     else:
         # Attach
-        tasks = [(is_current_network_5g_nsa, [ad, nr_type]) for ad in ads]
+        tasks = [(is_current_network_5g_nsa, [ad, None, mmwave]) for ad in ads]
         if not multithread_func(log, tasks):
             log.error("phone not on 5g nsa")
             return False
@@ -220,17 +230,20 @@
     return set_preferred_network_mode_pref(ad.log, ad, sub_id, mode)
 
 
-def provision_device_for_5g_sa(log, ads):
+def provision_device_for_5g_sa(log, ads, mmwave = None):
     """Provision Devices for 5G SA
 
     Args:
         log: Log object.
         ads: android device object(s).
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
 
     Returns:
         True: Device(s) are provisioned on 5G SA
         False: Device(s) are not provisioned on 5G SA
     """
+
     if isinstance(ads, list):
         # Mode Pref
         tasks = [(set_preferred_mode_for_5g, [ad, None, NETWORK_MODE_NR_ONLY]) for ad in ads]
@@ -238,7 +251,7 @@
             log.error("failed to set preferred network mode on 5g SA")
             return False
 
-        tasks = [(is_current_network_5g_sa, [ad]) for ad in ads]
+        tasks = [(is_current_network_5g_sa, [ad, None, mmwave]) for ad in ads]
         if not multithread_func(log, tasks):
             log.error("phone not on 5g SA")
             return False
@@ -247,46 +260,59 @@
         # Mode Pref
         set_preferred_mode_for_5g(ads, None, NETWORK_MODE_NR_ONLY)
 
-        if not is_current_network_5g_sa(ads):
+        if not is_current_network_5g_sa(ads, None, mmwave):
             ads.log.error("Phone not attached on SA 5g")
             return False
         return True
 
 
-def check_current_network_5g(ad, timeout=30, nr_type=None):
+def check_current_network_5g(
+    ad, sub_id = None, nr_type = None, mmwave = None, timeout = 30):
     """Verifies data network type is on 5G
 
     Args:
         ad: android device object.
-        timeout: max time to wait for event
+        sub_id: The target SIM for querying.
         nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
-                wave
+                wave.
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
+        timeout: max time to wait for event.
 
     Returns:
         True: if data is on 5g
         False: if data is not on 5g
     """
+    sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
     if nr_type == 'sa':
-        if not is_current_network_5g_sa(ad):
+        if not is_current_network_5g_sa(ad, sub_id, mmwave=mmwave):
             return False
     else:
-        if not is_current_network_5g_nsa(ad, nr_type= nr_type, timeout=timeout):
+        if not is_current_network_5g_nsa(ad, sub_id, mmwave=mmwave,
+                                         timeout=timeout):
             return False
     return True
 
 
-def test_activation_by_condition(ad, from_3g=False, nr_type=None, precond_func=None):
+def test_activation_by_condition(ad, sub_id=None, from_3g=False, nr_type=None,
+                                 precond_func=None, mmwave=None):
     """Test 5G activation based on various pre-conditions.
 
     Args:
         ad: android device object.
+        sub_id: The target SIM for querying.
         from_3g: If true, test 5G activation from 3G attaching. Otherwise, starting from 5G attaching.
         nr_type: check the band of NR network. Default is to check sub-6.
         precond_func: A function to execute pre conditions before testing 5G activation.
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
 
     Returns:
         If success, return true. Otherwise, return false.
     """
+    sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
     wifi_toggle_state(ad.log, ad, False)
     toggle_airplane_mode(ad.log, ad, False)
     if not from_3g:
@@ -313,7 +339,7 @@
             ad.log.error("Fail to ensure initial data in 4G")
         # 5G attach
         ad.log.info("Waiting for 5g NSA attach for 60 secs")
-        if is_current_network_5g_nsa(ad, nr_type= nr_type, timeout=60):
+        if is_current_network_5g_nsa(ad, sub_id, mmwave=mmwave, timeout=60):
             ad.log.info("Success! attached on 5g NSA")
             return True
         else:
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
index 58ce9ee..f35272e 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
@@ -19,140 +19,121 @@
 from acts_contrib.test_utils.tel.tel_defines import DisplayInfoContainer
 from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
 
-def is_current_network_5g_nsa(ad, nr_type=None, timeout=30):
+def is_current_network_5g_nsa(ad, sub_id = None, mmwave = None, timeout=30):
     """Verifies 5G NSA override network type
     Args:
         ad: android device object.
-        nr_type: 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
-                wave
+        sub_id: The target SIM for querying.
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
         timeout: max time to wait for event.
 
     Returns:
         True: if data is on nsa5g NSA
         False: if data is not on nsa5g NSA
     """
-    ad.ed.clear_events(EventDisplayInfoChanged)
-    ad.droid.telephonyStartTrackingDisplayInfoChange()
-    if nr_type == 'mmwave':
-        nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE
-    elif nr_type == 'nsa':
-        nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
+    sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
+    def _nsa_display_monitor(ad, sub_id, mmwave, timeout):
+        ad.ed.clear_events(EventDisplayInfoChanged)
+        ad.droid.telephonyStartTrackingDisplayInfoChangeForSubscription(sub_id)
+        if mmwave:
+            nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE
+        else:
+            nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
+        try:
+            event = ad.ed.wait_for_event(
+                    EventDisplayInfoChanged,
+                    ad.ed.is_event_match,
+                    timeout=timeout,
+                    field=DisplayInfoContainer.OVERRIDE,
+                    value=nsa_band)
+            ad.log.info("Got expected event %s", event)
+            return True
+        except Empty:
+            ad.log.info("No event for display info change with <%s>", nsa_band)
+            ad.screenshot("5g_nsa_icon_checking")
+            return False
+        finally:
+            ad.droid.telephonyStopTrackingServiceStateChangeForSubscription(
+                sub_id)
+
+    if mmwave is None:
+        return _nsa_display_monitor(
+            ad, sub_id, mmwave=False, timeout=timeout) or _nsa_display_monitor(
+            ad, sub_id, mmwave=True, timeout=timeout)
     else:
-        nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
-    try:
-        event = ad.ed.wait_for_event(
-                EventDisplayInfoChanged,
-                ad.ed.is_event_match,
-                timeout=timeout,
-                field=DisplayInfoContainer.OVERRIDE,
-                value=nsa_band)
-        ad.log.info("Got expected event %s", event)
-        return True
-    except Empty:
-        ad.log.info("No event for display info change")
-        ad.screenshot("5g_nsa_icon_checking")
-        return False
-    finally:
-        ad.droid.telephonyStopTrackingDisplayInfoChange()
-    return None
+        return _nsa_display_monitor(ad, sub_id, mmwave, timeout)
 
 
-def is_current_network_5g_nsa_for_subscription(ad, nr_type=None, timeout=30, sub_id=None):
-    """Verifies 5G NSA override network type for subscription id.
-    Args:
-        ad: android device object.
-        nr_type: 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter wave
-        timeout: max time to wait for event.
-        sub_id: subscription id.
-
-    Returns:
-        True: if data is on nsa5g NSA
-        False: if data is not on nsa5g NSA
-    """
-    if not sub_id:
-        return is_current_network_5g_nsa(ad, nr_type=nr_type)
-
-    voice_sub_id_changed = False
-    current_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
-    if current_sub_id != sub_id:
-        ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
-        voice_sub_id_changed = True
-
-    result = is_current_network_5g_nsa(ad, nr_type=nr_type)
-
-    if voice_sub_id_changed:
-        ad.droid.subscriptionSetDefaultVoiceSubId(current_sub_id)
-
-    return result
-
-
-def is_current_network_5g_sa(ad):
+def is_current_network_5g_sa(ad, sub_id = None, mmwave = None):
     """Verifies 5G SA override network type
 
     Args:
         ad: android device object.
+        sub_id: The target SIM for querying.
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
 
     Returns:
         True: if data is on 5g SA
         False: if data is not on 5g SA
     """
-    network_connected = ad.droid.telephonyGetCurrentDataNetworkType()
-    if network_connected == 'NR':
-        ad.log.debug("Network is currently connected to %s", network_connected)
-        return True
-    else:
-        ad.log.error("Network is currently connected to %s, Expected on NR", network_connected)
-        ad.screenshot("5g_sa_icon_checking")
+    sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+    current_rat = ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+        sub_id)
+    # TODO(richardwychang): check SA MMWAVE when function ready.
+    sa_type = ['NR',]
+    if mmwave is None:
+        if current_rat in sa_type:
+            ad.log.debug("Network is currently connected to %s", current_rat)
+            return True
+        else:
+            ad.log.error(
+                "Network is currently connected to %s, Expected on %s",
+                current_rat, sa_type)
+            ad.screenshot("5g_sa_icon_checking")
+            return False
+    elif mmwave:
+        ad.log.error("SA MMWAVE currently not support.")
         return False
+    else:
+        if current_rat == 'NR':
+            ad.log.debug("Network is currently connected to %s", current_rat)
+            return True
+        else:
+            ad.log.error(
+                "Network is currently connected to %s, Expected on NR",
+                current_rat)
+            ad.screenshot("5g_sa_icon_checking")
+            return False
 
 
-def is_current_network_5g(ad, nr_type=None, timeout=30):
+def is_current_network_5g(ad, sub_id = None, nr_type = None, mmwave = None,
+                          timeout = 30):
     """Verifies 5G override network type
 
     Args:
         ad: android device object
-        nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
-                wave
+        sub_id: The target SIM for querying.
+        nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone.
+        mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+            None to detect both.
         timeout: max time to wait for event.
 
     Returns:
         True: if data is on 5G regardless of SA or NSA
         False: if data is not on 5G refardless of SA or NSA
     """
+    sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
     if nr_type == 'nsa':
-        return is_current_network_5g_nsa(ad, nr_type = 'nsa', timeout=timeout)
+        return is_current_network_5g_nsa(
+            ad, sub_id=sub_id, mmwave=mmwave, timeout=timeout)
     elif nr_type == 'sa':
-        return is_current_network_5g_sa(ad)
-    elif nr_type == 'mmwave':
-        return is_current_network_5g_nsa(ad, nr_type = 'mmwave', timeout=timeout)
+        return is_current_network_5g_sa(ad, sub_id=sub_id, mmwave=mmwave)
     else:
-        return is_current_network_5g_nsa(ad, nr_type=None) or is_current_network_5g_sa(ad)
-
-
-def is_current_network_5g_for_subscription(ad, sub_id=None, nr_type=None):
-    """Verifies 5G override network type for subscription id.
-    Args:
-        ad: android device object
-        sub_id: subscription id
-        nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
-                wave
-
-    Returns:
-        True: if data is on 5G regardless of NSA or SA.
-        False: if data is not on 5G regardless of NSA or SA.
-    """
-    if not sub_id:
-        return is_current_network_5g(ad, nr_type=nr_type)
-
-    voice_sub_id_changed = False
-    current_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
-    if current_sub_id != sub_id:
-        ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
-        voice_sub_id_changed = True
-
-    result = is_current_network_5g(ad, nr_type=nr_type)
-
-    if voice_sub_id_changed:
-        ad.droid.subscriptionSetDefaultVoiceSubId(current_sub_id)
-
-    return result
+        return is_current_network_5g_nsa(
+            ad, sub_id=sub_id, mmwave=mmwave,
+            timeout=timeout) or is_current_network_5g_sa(
+                ad, sub_id=sub_id, mmwave=mmwave)
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py
index 6f49178..8f754ed 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -21,9 +21,9 @@
 from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
 from acts_contrib.test_utils.tel.tel_data_utils import test_internet_connection
-from acts_contrib.test_utils.tel.tel_data_utils import verify_internet_connection
 from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
 from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
 from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
 from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
index 62c1bed..05808f9 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -16,10 +16,12 @@
 
 
 import logging
+import os
 import time
 import random
 from queue import Empty
 
+from acts.controllers.android_device import SL4A_APK_NAME
 from acts.utils import adb_shell_ping
 from acts.utils import rand_ascii_str
 from acts.utils import disable_doze
@@ -49,11 +51,15 @@
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
 from acts_contrib.test_utils.tel.tel_defines import RAT_5G
 from acts_contrib.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
+from acts_contrib.test_utils.tel.tel_defines import TYPE_MOBILE
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_AFTER_REBOOT
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_NW_VALID_FAIL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL_RECOVERY
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_TETHERING_AFTER_REBOOT
 from acts_contrib.test_utils.tel.tel_defines import DataConnectionStateContainer
@@ -72,23 +78,22 @@
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_voice_attach_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existence
+from acts_contrib.test_utils.tel.tel_test_utils import _generate_file_directory_and_file_name
 from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
 from acts_contrib.test_utils.tel.tel_test_utils import get_internet_connection_type
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
 from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
 from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
 from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_network_generation_for_subscription
 from acts_contrib.test_utils.tel.tel_test_utils import is_event_match
 from acts_contrib.test_utils.tel.tel_test_utils import rat_generation_from_rat
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
 from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
 from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
 from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_voice_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_task
 from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
 from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
 from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_active
@@ -522,7 +527,7 @@
             return False
 
         if nw_gen == GEN_5G:
-            if not check_current_network_5g(ad, timeout=60, nr_type=nr_type):
+            if not check_current_network_5g(ad, nr_type=nr_type, timeout=60):
                 return False
         else:
             if not is_droid_in_network_generation_for_subscription(
@@ -871,7 +876,7 @@
     ensure_phones_idle(log, ad_list)
 
     if nw_gen == GEN_5G:
-        if not provision_device_for_5g(log, android_devices, nr_type= nr_type):
+        if not provision_device_for_5g(log, android_devices, nr_type=nr_type):
             return False
     elif nw_gen:
         if not ensure_network_generation_for_subscription(
@@ -1027,7 +1032,7 @@
     ensure_phones_idle(log, clients)
     wifi_toggle_state(log, provider, False)
     if network_generation == RAT_5G:
-        if not provision_device_for_5g(log, provider, nr_type= nr_type):
+        if not provision_device_for_5g(log, provider, nr_type=nr_type):
             return False
     elif network_generation:
         if not ensure_network_generation(
@@ -1097,7 +1102,7 @@
         return False
 
     if provider_setup_func == RAT_5G:
-        if not provision_device_for_5g(log, provider, nr_type= nr_type):
+        if not provision_device_for_5g(log, provider, nr_type=nr_type):
             return False
     try:
         log.info("1. Setup WiFi Tethering.")
@@ -1244,7 +1249,7 @@
                                    wait_time_in_call)
 
     if nw_gen == GEN_5G:
-        if not provision_device_for_5g(log, ads[0], nr_type= nr_type):
+        if not provision_device_for_5g(log, ads[0], nr_type=nr_type):
             return False
     elif nw_gen:
         if not ensure_network_generation(log, ads[0], nw_gen,
@@ -1299,7 +1304,8 @@
             return False
     # Disable airplane mode if test under apm on.
     toggle_airplane_mode(log, ads[0], False)
-    if nw_gen == GEN_5G and not check_current_network_5g(ads[0], nr_type= nr_type):
+    if nw_gen == GEN_5G and not check_current_network_5g(ads[0],
+                                                         nr_type=nr_type):
         ads[0].log.error("Phone not attached on 5G after call.")
         return False
     return True
@@ -1330,7 +1336,7 @@
         False if failed.
     """
     if nw_gen == GEN_5G:
-        if not provision_device_for_5g(log, ads[0], nr_type= nr_type):
+        if not provision_device_for_5g(log, ads[0], nr_type=nr_type):
             return False
     elif nw_gen:
         if not ensure_network_generation(log, ads[0], nw_gen,
@@ -1377,7 +1383,8 @@
     ad_download.force_stop_apk("com.google.android.youtube")
     # Disable airplane mode if test under apm on.
     toggle_airplane_mode(log, ads[0], False)
-    if nw_gen == GEN_5G and not check_current_network_5g(ads[0], nr_type= nr_type):
+    if nw_gen == GEN_5G and not check_current_network_5g(ads[0],
+                                                         nr_type=nr_type):
         ads[0].log.error("Phone not attached on 5G after call.")
         result = False
     return result
@@ -1447,7 +1454,8 @@
 
     time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
 
-    if nw_gen == GEN_5G and not verify_5g_attach_for_both_devices(log, ads, nr_type= nr_type):
+    if nw_gen == GEN_5G and not verify_5g_attach_for_both_devices(
+        log, ads, nr_type=nr_type):
         log.error("Phone not attached on 5G after epdg call.")
         return False
 
@@ -1548,7 +1556,7 @@
                         ssid=None,
                         password=None,
                         pre_teardown_func=None,
-                        nr_type= None):
+                        nr_type=None):
     """WiFi Tethering test
     Args:
         log: log object.
@@ -1574,7 +1582,7 @@
         nr_type: NR network type e.g. NSA, SA, MMWAVE.
 
     """
-    if not test_setup_tethering(log, provider, clients, nw_gen, nr_type= nr_type):
+    if not test_setup_tethering(log, provider, clients, nw_gen, nr_type=nr_type):
         log.error("Verify %s Internet access failed.", nw_gen)
         return False
 
@@ -1875,7 +1883,7 @@
                                              provider,
                                              clients,
                                              new_gen=None,
-                                             nr_type= None):
+                                             nr_type=None):
     """Verify toggle Data network during WiFi Tethering.
     Args:
         log: log object.
@@ -1900,7 +1908,7 @@
                                    check_iteration=2,
                                    do_cleanup=False,
                                    ssid=ssid,
-                                   nr_type= nr_type):
+                                   nr_type=nr_type):
             log.error("WiFi Tethering failed.")
             return False
         if not provider.droid.wifiIsApEnabled():
@@ -2361,4 +2369,500 @@
         ad.log.error("Exception error %s", str(e))
         return False
     finally:
-        ad.droid.connectivityStopTrackingConnectivityStateChange()
\ No newline at end of file
+        ad.droid.connectivityStopTrackingConnectivityStateChange()
+
+
+def check_curl_availability(ad):
+    if not hasattr(ad, "curl_capable"):
+        try:
+            out = ad.adb.shell("/data/curl --version")
+            if not out or "not found" in out:
+                setattr(ad, "curl_capable", False)
+                ad.log.info("curl is unavailable, use chrome to download file")
+            else:
+                setattr(ad, "curl_capable", True)
+        except Exception:
+            setattr(ad, "curl_capable", False)
+            ad.log.info("curl is unavailable, use chrome to download file")
+    return ad.curl_capable
+
+
+def start_youtube_video(ad, url="vnd.youtube:watch?v=pSJoP0LR8CQ"):
+    ad.log.info("Open an youtube video")
+    for _ in range(3):
+        ad.ensure_screen_on()
+        ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
+        if wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1):
+            ad.log.info("Started a video in youtube, audio is in MUSIC state")
+            return True
+        ad.log.info("Audio is not in MUSIC state. Quit Youtube.")
+        for _ in range(3):
+            ad.send_keycode("BACK")
+            time.sleep(1)
+        time.sleep(3)
+    return False
+
+
+def http_file_download_by_sl4a(ad,
+                               url,
+                               out_path=None,
+                               expected_file_size=None,
+                               remove_file_after_check=True,
+                               timeout=300):
+    """Download http file by sl4a RPC call.
+
+    Args:
+        ad: Android Device Object.
+        url: The url that file to be downloaded from".
+        out_path: Optional. Where to download file to.
+                  out_path is /sdcard/Download/ by default.
+        expected_file_size: Optional. Provided if checking the download file meet
+                            expected file size in unit of byte.
+        remove_file_after_check: Whether to remove the downloaded file after
+                                 check.
+        timeout: timeout for file download to complete.
+    """
+    file_folder, file_name = _generate_file_directory_and_file_name(
+        url, out_path)
+    file_path = os.path.join(file_folder, file_name)
+    ad.adb.shell("rm -f %s" % file_path)
+    accounting_apk = SL4A_APK_NAME
+    result = True
+    try:
+        if not getattr(ad, "data_droid", None):
+            ad.data_droid, ad.data_ed = ad.get_droid()
+            ad.data_ed.start()
+        else:
+            try:
+                if not ad.data_droid.is_live:
+                    ad.data_droid, ad.data_ed = ad.get_droid()
+                    ad.data_ed.start()
+            except Exception:
+                ad.log.info("Start new sl4a session for file download")
+                ad.data_droid, ad.data_ed = ad.get_droid()
+                ad.data_ed.start()
+        data_accounting = {
+            "mobile_rx_bytes":
+            ad.droid.getMobileRxBytes(),
+            "subscriber_mobile_data_usage":
+            get_mobile_data_usage(ad, None, None),
+            "sl4a_mobile_data_usage":
+            get_mobile_data_usage(ad, None, accounting_apk)
+        }
+        ad.log.debug("Before downloading: %s", data_accounting)
+        ad.log.info("Download file from %s to %s by sl4a RPC call", url,
+                    file_path)
+        try:
+            ad.data_droid.httpDownloadFile(url, file_path, timeout=timeout)
+        except Exception as e:
+            ad.log.warning("SL4A file download error: %s", e)
+            ad.data_droid.terminate()
+            return False
+        if _check_file_existence(ad, file_path, expected_file_size):
+            ad.log.info("%s is downloaded successfully", url)
+            new_data_accounting = {
+                "mobile_rx_bytes":
+                ad.droid.getMobileRxBytes(),
+                "subscriber_mobile_data_usage":
+                get_mobile_data_usage(ad, None, None),
+                "sl4a_mobile_data_usage":
+                get_mobile_data_usage(ad, None, accounting_apk)
+            }
+            ad.log.debug("After downloading: %s", new_data_accounting)
+            accounting_diff = {
+                key: value - data_accounting[key]
+                for key, value in new_data_accounting.items()
+            }
+            ad.log.debug("Data accounting difference: %s", accounting_diff)
+            if getattr(ad, "on_mobile_data", False):
+                for key, value in accounting_diff.items():
+                    if value < expected_file_size:
+                        ad.log.debug("%s diff is %s less than %s", key,
+                                       value, expected_file_size)
+                        ad.data_accounting["%s_failure"] += 1
+            else:
+                for key, value in accounting_diff.items():
+                    if value >= expected_file_size:
+                        ad.log.error("%s diff is %s. File download is "
+                                     "consuming mobile data", key, value)
+                        result = False
+            return result
+        else:
+            ad.log.warning("Fail to download %s", url)
+            return False
+    except Exception as e:
+        ad.log.error("Download %s failed with exception %s", url, e)
+        raise
+    finally:
+        if remove_file_after_check:
+            ad.log.info("Remove the downloaded file %s", file_path)
+            ad.adb.shell("rm %s" % file_path, ignore_status=True)
+
+
+def http_file_download_by_curl(ad,
+                               url,
+                               out_path=None,
+                               expected_file_size=None,
+                               remove_file_after_check=True,
+                               timeout=3600,
+                               limit_rate=None,
+                               retry=3):
+    """Download http file by adb curl.
+
+    Args:
+        ad: Android Device Object.
+        url: The url that file to be downloaded from".
+        out_path: Optional. Where to download file to.
+                  out_path is /sdcard/Download/ by default.
+        expected_file_size: Optional. Provided if checking the download file meet
+                            expected file size in unit of byte.
+        remove_file_after_check: Whether to remove the downloaded file after
+                                 check.
+        timeout: timeout for file download to complete.
+        limit_rate: download rate in bps. None, if do not apply rate limit.
+        retry: the retry request times provided in curl command.
+    """
+    file_directory, file_name = _generate_file_directory_and_file_name(
+        url, out_path)
+    file_path = os.path.join(file_directory, file_name)
+    curl_cmd = "/data/curl"
+    if limit_rate:
+        curl_cmd += " --limit-rate %s" % limit_rate
+    if retry:
+        curl_cmd += " --retry %s" % retry
+    curl_cmd += " --url %s > %s" % (url, file_path)
+    try:
+        ad.log.info("Download %s to %s by adb shell command %s", url,
+                    file_path, curl_cmd)
+
+        ad.adb.shell(curl_cmd, timeout=timeout)
+        if _check_file_existence(ad, file_path, expected_file_size):
+            ad.log.info("%s is downloaded to %s successfully", url, file_path)
+            return True
+        else:
+            ad.log.warning("Fail to download %s", url)
+            return False
+    except Exception as e:
+        ad.log.warning("Download %s failed with exception %s", url, e)
+        return False
+    finally:
+        if remove_file_after_check:
+            ad.log.info("Remove the downloaded file %s", file_path)
+            ad.adb.shell("rm %s" % file_path, ignore_status=True)
+
+
+def open_url_by_adb(ad, url):
+    ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
+
+
+def http_file_download_by_chrome(ad,
+                                 url,
+                                 expected_file_size=None,
+                                 remove_file_after_check=True,
+                                 timeout=3600):
+    """Download http file by chrome.
+
+    Args:
+        ad: Android Device Object.
+        url: The url that file to be downloaded from".
+        expected_file_size: Optional. Provided if checking the download file meet
+                            expected file size in unit of byte.
+        remove_file_after_check: Whether to remove the downloaded file after
+                                 check.
+        timeout: timeout for file download to complete.
+    """
+    chrome_apk = "com.android.chrome"
+    file_directory, file_name = _generate_file_directory_and_file_name(
+        url, "/sdcard/Download/")
+    file_path = os.path.join(file_directory, file_name)
+    # Remove pre-existing file
+    ad.force_stop_apk(chrome_apk)
+    file_to_be_delete = os.path.join(file_directory, "*%s*" % file_name)
+    ad.adb.shell("rm -f %s" % file_to_be_delete)
+    ad.adb.shell("rm -rf /sdcard/Download/.*")
+    ad.adb.shell("rm -f /sdcard/Download/.*")
+    data_accounting = {
+        "total_rx_bytes": ad.droid.getTotalRxBytes(),
+        "mobile_rx_bytes": ad.droid.getMobileRxBytes(),
+        "subscriber_mobile_data_usage": get_mobile_data_usage(ad, None, None),
+        "chrome_mobile_data_usage": get_mobile_data_usage(
+            ad, None, chrome_apk)
+    }
+    ad.log.debug("Before downloading: %s", data_accounting)
+    ad.log.info("Download %s with timeout %s", url, timeout)
+    ad.ensure_screen_on()
+    open_url_by_adb(ad, url)
+    elapse_time = 0
+    result = True
+    while elapse_time < timeout:
+        time.sleep(30)
+        if _check_file_existence(ad, file_path, expected_file_size):
+            ad.log.info("%s is downloaded successfully", url)
+            if remove_file_after_check:
+                ad.log.info("Remove the downloaded file %s", file_path)
+                ad.adb.shell("rm -f %s" % file_to_be_delete)
+                ad.adb.shell("rm -rf /sdcard/Download/.*")
+                ad.adb.shell("rm -f /sdcard/Download/.*")
+            #time.sleep(30)
+            new_data_accounting = {
+                "mobile_rx_bytes":
+                ad.droid.getMobileRxBytes(),
+                "subscriber_mobile_data_usage":
+                get_mobile_data_usage(ad, None, None),
+                "chrome_mobile_data_usage":
+                get_mobile_data_usage(ad, None, chrome_apk)
+            }
+            ad.log.info("After downloading: %s", new_data_accounting)
+            accounting_diff = {
+                key: value - data_accounting[key]
+                for key, value in new_data_accounting.items()
+            }
+            ad.log.debug("Data accounting difference: %s", accounting_diff)
+            if getattr(ad, "on_mobile_data", False):
+                for key, value in accounting_diff.items():
+                    if value < expected_file_size:
+                        ad.log.warning("%s diff is %s less than %s", key,
+                                       value, expected_file_size)
+                        ad.data_accounting["%s_failure" % key] += 1
+            else:
+                for key, value in accounting_diff.items():
+                    if value >= expected_file_size:
+                        ad.log.error("%s diff is %s. File download is "
+                                     "consuming mobile data", key, value)
+                        result = False
+            return result
+        elif _check_file_existence(ad, "%s.crdownload" % file_path):
+            ad.log.info("Chrome is downloading %s", url)
+        elif elapse_time < 60:
+            # download not started, retry download wit chrome again
+            open_url_by_adb(ad, url)
+        else:
+            ad.log.error("Unable to download file from %s", url)
+            break
+        elapse_time += 30
+    ad.log.warning("Fail to download file from %s", url)
+    ad.force_stop_apk("com.android.chrome")
+    ad.adb.shell("rm -f %s" % file_to_be_delete)
+    ad.adb.shell("rm -rf /sdcard/Download/.*")
+    ad.adb.shell("rm -f /sdcard/Download/.*")
+    return False
+
+
+def get_mobile_data_usage(ad, sid=None, apk=None):
+    if not sid:
+        sid = ad.droid.subscriptionGetDefaultDataSubId()
+    current_time = int(time.time() * 1000)
+    begin_time = current_time - 10 * 24 * 60 * 60 * 1000
+    end_time = current_time + 10 * 24 * 60 * 60 * 1000
+
+    if apk:
+        uid = ad.get_apk_uid(apk)
+        ad.log.debug("apk %s uid = %s", apk, uid)
+        try:
+            usage_info = ad.droid.getMobileDataUsageInfoForUid(uid, sid)
+            ad.log.debug("Mobile data usage info for uid %s = %s", uid,
+                        usage_info)
+            return usage_info["UsageLevel"]
+        except:
+            try:
+                return ad.droid.connectivityQueryDetailsForUid(
+                    TYPE_MOBILE,
+                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+                    begin_time, end_time, uid)
+            except:
+                return ad.droid.connectivityQueryDetailsForUid(
+                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+                    begin_time, end_time, uid)
+    else:
+        try:
+            usage_info = ad.droid.getMobileDataUsageInfo(sid)
+            ad.log.debug("Mobile data usage info = %s", usage_info)
+            return usage_info["UsageLevel"]
+        except:
+            try:
+                return ad.droid.connectivityQuerySummaryForDevice(
+                    TYPE_MOBILE,
+                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+                    begin_time, end_time)
+            except:
+                return ad.droid.connectivityQuerySummaryForDevice(
+                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+                    begin_time, end_time)
+
+
+def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
+    if not subscriber_id:
+        subscriber_id = ad.droid.telephonyGetSubscriberId()
+    ad.log.debug("Set subscriber mobile data usage limit to %s", limit)
+    ad.droid.logV("Setting subscriber mobile data usage limit to %s" % limit)
+    try:
+        ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
+    except:
+        ad.droid.connectivitySetDataUsageLimit(subscriber_id, limit)
+
+
+def remove_mobile_data_usage_limit(ad, subscriber_id=None):
+    if not subscriber_id:
+        subscriber_id = ad.droid.telephonyGetSubscriberId()
+    ad.log.debug("Remove subscriber mobile data usage limit")
+    ad.droid.logV(
+        "Setting subscriber mobile data usage limit to -1, unlimited")
+    try:
+        ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
+    except:
+        ad.droid.connectivitySetDataUsageLimit(subscriber_id, -1)
+
+
+def active_file_download_task(log, ad, file_name="5MB", method="curl"):
+    # files available for download on the same website:
+    # 1GB.zip, 512MB.zip, 200MB.zip, 50MB.zip, 20MB.zip, 10MB.zip, 5MB.zip
+    # download file by adb command, as phone call will use sl4a
+    file_size_map = {
+        '1MB': 1000000,
+        '5MB': 5000000,
+        '10MB': 10000000,
+        '20MB': 20000000,
+        '50MB': 50000000,
+        '100MB': 100000000,
+        '200MB': 200000000,
+        '512MB': 512000000
+    }
+    url_map = {
+        "1MB": [
+            "http://146.148.91.8/download/1MB.zip",
+            "http://ipv4.download.thinkbroadband.com/1MB.zip"
+        ],
+        "5MB": [
+            "http://146.148.91.8/download/5MB.zip",
+            "http://212.183.159.230/5MB.zip",
+            "http://ipv4.download.thinkbroadband.com/5MB.zip"
+        ],
+        "10MB": [
+            "http://146.148.91.8/download/10MB.zip",
+            "http://212.183.159.230/10MB.zip",
+            "http://ipv4.download.thinkbroadband.com/10MB.zip",
+            "http://lax.futurehosting.com/test.zip",
+            "http://ovh.net/files/10Mio.dat"
+        ],
+        "20MB": [
+            "http://146.148.91.8/download/20MB.zip",
+            "http://212.183.159.230/20MB.zip",
+            "http://ipv4.download.thinkbroadband.com/20MB.zip"
+        ],
+        "50MB": [
+            "http://146.148.91.8/download/50MB.zip",
+            "http://212.183.159.230/50MB.zip",
+            "http://ipv4.download.thinkbroadband.com/50MB.zip"
+        ],
+        "100MB": [
+            "http://146.148.91.8/download/100MB.zip",
+            "http://212.183.159.230/100MB.zip",
+            "http://ipv4.download.thinkbroadband.com/100MB.zip",
+            "http://speedtest-ca.turnkeyinternet.net/100mb.bin",
+            "http://ovh.net/files/100Mio.dat",
+            "http://lax.futurehosting.com/test100.zip"
+        ],
+        "200MB": [
+            "http://146.148.91.8/download/200MB.zip",
+            "http://212.183.159.230/200MB.zip",
+            "http://ipv4.download.thinkbroadband.com/200MB.zip"
+        ],
+        "512MB": [
+            "http://146.148.91.8/download/512MB.zip",
+            "http://212.183.159.230/512MB.zip",
+            "http://ipv4.download.thinkbroadband.com/512MB.zip"
+        ]
+    }
+
+    file_size = file_size_map.get(file_name)
+    file_urls = url_map.get(file_name)
+    file_url = None
+    for url in file_urls:
+        url_splits = url.split("/")
+        if verify_http_connection(log, ad, url=url, retry=1):
+            output_path = "/sdcard/Download/%s" % url_splits[-1]
+            file_url = url
+            break
+    if not file_url:
+        ad.log.error("No url is available to download %s", file_name)
+        return False
+    timeout = min(max(file_size / 100000, 600), 3600)
+    if method == "sl4a":
+        return (http_file_download_by_sl4a, (ad, file_url, output_path,
+                                             file_size, True, timeout))
+    if method == "curl" and check_curl_availability(ad):
+        return (http_file_download_by_curl, (ad, file_url, output_path,
+                                             file_size, True, timeout))
+    elif method == "sl4a" or method == "curl":
+        return (http_file_download_by_sl4a, (ad, file_url, output_path,
+                                             file_size, True, timeout))
+    else:
+        return (http_file_download_by_chrome, (ad, file_url, file_size, True,
+                                               timeout))
+
+
+def active_file_download_test(log, ad, file_name="5MB", method="sl4a"):
+    task = active_file_download_task(log, ad, file_name, method=method)
+    if not task:
+        return False
+    return task[0](*task[1])
+
+
+def check_data_stall_detection(ad, wait_time=WAIT_TIME_FOR_DATA_STALL):
+    data_stall_detected = False
+    time_var = 1
+    try:
+        while (time_var < wait_time):
+            out = ad.adb.shell("dumpsys network_stack " \
+                              "| grep \"Suspecting data stall\"",
+                            ignore_status=True)
+            ad.log.debug("Output is %s", out)
+            if out:
+                ad.log.info("NetworkMonitor detected - %s", out)
+                data_stall_detected = True
+                break
+            time.sleep(30)
+            time_var += 30
+    except Exception as e:
+        ad.log.error(e)
+    return data_stall_detected
+
+
+def check_network_validation_fail(ad, begin_time=None,
+                                  wait_time=WAIT_TIME_FOR_NW_VALID_FAIL):
+    network_validation_fail = False
+    time_var = 1
+    try:
+        while (time_var < wait_time):
+            time_var += 30
+            nw_valid = ad.search_logcat("validation failed",
+                                         begin_time)
+            if nw_valid:
+                ad.log.info("Validation Failed received here - %s",
+                            nw_valid[0]["log_message"])
+                network_validation_fail = True
+                break
+            time.sleep(30)
+    except Exception as e:
+        ad.log.error(e)
+    return network_validation_fail
+
+
+def check_data_stall_recovery(ad, begin_time=None,
+                              wait_time=WAIT_TIME_FOR_DATA_STALL_RECOVERY):
+    data_stall_recovery = False
+    time_var = 1
+    try:
+        while (time_var < wait_time):
+            time_var += 30
+            recovery = ad.search_logcat("doRecovery() cleanup all connections",
+                                         begin_time)
+            if recovery:
+                ad.log.info("Recovery Performed here - %s",
+                            recovery[-1]["log_message"])
+                data_stall_recovery = True
+                break
+            time.sleep(30)
+    except Exception as e:
+        ad.log.error(e)
+    return data_stall_recovery
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
index 4d91839..6b15886 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -14,19 +14,25 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+from datetime import datetime, timedelta
 import re
 import time
-from datetime import datetime, timedelta
+from typing import Optional, Sequence
 
 from acts import signals
+from acts import tracelogger
+from acts.controllers.android_device import AndroidDevice
 from acts.utils import rand_ascii_str
 from acts.libs.utils.multithread import multithread_func
 from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
 from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
 from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
 from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
 from acts_contrib.test_utils.tel.tel_message_utils import log_messaging_screen_shot
 from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
 from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify_for_subscription
@@ -51,12 +57,10 @@
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
 from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
 from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim
 from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
 from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
@@ -76,6 +80,237 @@
 CallResult = TelephonyVoiceTestResult.CallResult.Value
 
 
+def dsds_long_call_streaming_test(
+    log: tracelogger.TraceLogger,
+    tel_logger: TelephonyMetricLogger.for_test_case,
+    ads: Sequence[AndroidDevice],
+    test_rat: list,
+    test_slot: int,
+    dds_slot: int,
+    direction: str = "mo",
+    duration: int = 360,
+    streaming: bool = True,
+    is_airplane_mode = False,
+    wfc_mode: list[str, str] = [
+        WFC_MODE_CELLULAR_PREFERRED,
+        WFC_MODE_CELLULAR_PREFERRED],
+    wifi_network_ssid: Optional[str] = None,
+    wifi_network_pass: Optional[str] = None,
+    turn_off_wifi_in_the_end: bool = False,
+    turn_off_airplane_mode_in_the_end: bool = False) -> bool:
+    """Make MO/MT call at specific slot in specific RAT with DDS at specific
+    slot for the given time.
+
+    Args:
+        log: Logger object.
+        tel_logger: Logger object for telephony proto.
+        ads: A list of Android device objects.
+        test_rat: RAT for both slots of primary device.
+        test_slot: The slot which make/receive MO/MT call of primary device.
+        dds_slot: Preferred data slot of primary device.
+        direction: The direction of call("mo" or "mt").
+        streaming: True for playing Youtube and False on the contrary.
+        is_airplane_mode: True or False for WFC setup
+        wfc_mode: Cellular preferred or Wi-Fi preferred.
+        wifi_network_ssid: SSID of Wi-Fi AP.
+        wifi_network_pass: Password of Wi-Fi AP SSID.
+        turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
+            off Wi-Fi in the end of the function.
+        turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
+            False not to turn off airplane mode in the end of the function.
+
+    Returns:
+        TestFailure if failed.
+    """
+    log.info("Step 1: Switch DDS.")
+    if not set_dds_on_slot(ads[0], dds_slot):
+        ads[0].log.error(
+            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+        return False
+
+    log.info("Step 2: Check HTTP connection after DDS switch.")
+    if not verify_http_connection(log, ads[0]):
+        ads[0].log.error("Failed to verify http connection.")
+        return False
+    else:
+        ads[0].log.info("Verify http connection successfully.")
+
+    log.info("Step 3: Set up phones in desired RAT.")
+    if direction == "mo":
+        # setup voice subid on primary device.
+        ad_mo = ads[0]
+        mo_sub_id = get_subid_from_slot_index(log, ad_mo, test_slot)
+        if mo_sub_id == INVALID_SUB_ID:
+            ad_mo.log.warning("Failed to get sub ID at slot %s.", test_slot)
+            return False
+        mo_other_sub_id = get_subid_from_slot_index(
+            log, ad_mo, 1-test_slot)
+        sub_id_list = [mo_sub_id, mo_other_sub_id]
+        set_voice_sub_id(ad_mo, mo_sub_id)
+        ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", test_slot,
+        get_outgoing_voice_sub_id(ad_mo))
+
+        # setup voice subid on secondary device.
+        ad_mt = ads[1]
+        _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+        if mt_sub_id == INVALID_SUB_ID:
+            ad_mt.log.warning("Failed to get sub ID at default voice slot.")
+            return False
+        mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
+        set_voice_sub_id(ad_mt, mt_sub_id)
+        ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
+        get_outgoing_voice_sub_id(ad_mt))
+
+        # setup the rat on non-test slot(primary device).
+        phone_setup_on_rat(
+            log,
+            ad_mo,
+            test_rat[1-test_slot],
+            mo_other_sub_id,
+            is_airplane_mode,
+            wfc_mode[1-test_slot],
+            wifi_network_ssid,
+            wifi_network_pass)
+        # assign phone setup argv for test slot.
+        mo_phone_setup_func_argv = (
+            log,
+            ad_mo,
+            test_rat[test_slot],
+            mo_sub_id,
+            is_airplane_mode,
+            wfc_mode[test_slot],
+            wifi_network_ssid,
+            wifi_network_pass)
+        verify_caller_func = is_phone_in_call_on_rat(
+            log, ad_mo, test_rat[test_slot], only_return_fn=True)
+        mt_phone_setup_func_argv = (log, ad_mt, 'general')
+        verify_callee_func = is_phone_in_call_on_rat(
+            log, ad_mt, 'general', only_return_fn=True)
+    else:
+        # setup voice subid on primary device.
+        ad_mt = ads[0]
+        mt_sub_id = get_subid_from_slot_index(log, ad_mt, test_slot)
+        if mt_sub_id == INVALID_SUB_ID:
+            ad_mt.log.warning("Failed to get sub ID at slot %s.", test_slot)
+            return False
+        mt_other_sub_id = get_subid_from_slot_index(
+            log, ad_mt, 1-test_slot)
+        sub_id_list = [mt_sub_id, mt_other_sub_id]
+        set_voice_sub_id(ad_mt, mt_sub_id)
+        ad_mt.log.info("Sub ID for incoming call at slot %s: %s", test_slot,
+        get_outgoing_voice_sub_id(ad_mt))
+
+        # setup voice subid on secondary device.
+        ad_mo = ads[1]
+        _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+        if mo_sub_id == INVALID_SUB_ID:
+            ad_mo.log.warning("Failed to get sub ID at default voice slot.")
+            return False
+        mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+        set_voice_sub_id(ad_mo, mo_sub_id)
+        ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", mo_slot,
+        get_outgoing_voice_sub_id(ad_mo))
+
+        # setup the rat on non-test slot(primary device).
+        phone_setup_on_rat(
+            log,
+            ad_mt,
+            test_rat[1-test_slot],
+            mt_other_sub_id,
+            is_airplane_mode,
+            wfc_mode[1-test_slot],
+            wifi_network_ssid,
+            wifi_network_pass)
+        # assign phone setup argv for test slot.
+        mt_phone_setup_func_argv = (
+            log,
+            ad_mt,
+            test_rat[test_slot],
+            mt_sub_id,
+            is_airplane_mode,
+            wfc_mode[test_slot],
+            wifi_network_ssid,
+            wifi_network_pass)
+        verify_callee_func = is_phone_in_call_on_rat(
+            log, ad_mt, test_rat[test_slot], only_return_fn=True)
+        mo_phone_setup_func_argv = (log, ad_mo, 'general')
+        verify_caller_func = is_phone_in_call_on_rat(
+            log, ad_mo, 'general', only_return_fn=True)
+
+    tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
+             (phone_setup_on_rat, mt_phone_setup_func_argv)]
+    if not multithread_func(log, tasks):
+        log.error("Phone Failed to Set Up Properly.")
+        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+        raise signals.TestFailure("Failed",
+            extras={"fail_reason": "Phone Failed to Set Up Properly."})
+    if streaming:
+        log.info("Step 4-0: Start Youtube streaming.")
+        if not start_youtube_video(ads[0]):
+            raise signals.TestFailure("Failed",
+                extras={"fail_reason": "Fail to bring up youtube video."})
+        time.sleep(10)
+
+    log.info("Step 4: Make voice call.")
+    result = call_setup_teardown(log,
+                                 ad_mo,
+                                 ad_mt,
+                                 ad_hangup=ad_mo,
+                                 verify_caller_func=verify_caller_func,
+                                 verify_callee_func=verify_callee_func,
+                                 wait_time_in_call=duration)
+    tel_logger.set_result(result.result_value)
+
+    if not result:
+        log.error(
+            "Failed to make %s call from %s slot %s to %s slot %s",
+                direction, ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
+        raise signals.TestFailure("Failed",
+            extras={"fail_reason": str(result.result_value)})
+
+    log.info("Step 5: Verify RAT and HTTP connection.")
+    # For the tese cases related to WFC in which airplane mode will be turned
+    # off in the end.
+    if turn_off_airplane_mode_in_the_end:
+        log.info("Step 5-1: Turning off airplane mode......")
+        if not toggle_airplane_mode(log, ads[0], False):
+            ads[0].log.error('Failed to toggle off airplane mode.')
+
+    # For the tese cases related to WFC in which Wi-Fi will be turned off in the
+    # end.
+
+    rat_list = [test_rat[test_slot], test_rat[1-test_slot]]
+
+    if turn_off_wifi_in_the_end:
+        log.info("Step 5-2: Turning off Wi-Fi......")
+        if not wifi_toggle_state(log, ads[0], False):
+            ads[0].log.error('Failed to toggle off Wi-Fi.')
+            return False
+
+        for index, value in enumerate(rat_list):
+            if value == '5g_wfc':
+                rat_list[index] = '5g'
+            elif value == 'wfc':
+                rat_list[index] = '4g'
+
+    for rat, sub_id in zip(rat_list, sub_id_list):
+        if not wait_for_network_idle(log, ads[0], rat, sub_id):
+            raise signals.TestFailure(
+                "Failed",
+                extras={
+                    "fail_reason": "Idle state of sub ID %s does not match the "
+                    "given RAT %s." % (sub_id, rat)})
+
+    if not verify_http_connection(log, ads[0]):
+        ads[0].log.error("Failed to verify http connection.")
+        return False
+    else:
+        ads[0].log.info("Verify http connection successfully.")
+
+    if streaming:
+        ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
+
+
 def dsds_voice_call_test(
         log,
         tel_logger,
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
index b204364..1cb6bb5 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
@@ -29,6 +29,21 @@
 from acts.utils import start_standing_subprocess
 
 
+_LS_MASK_NAME = "Lassen default + TCP"
+
+_LS_ENABLE_LOG_SHELL = f"""\
+am broadcast -n com.android.pixellogger/.receiver.AlwaysOnLoggingReceiver \
+    -a com.android.pixellogger.service.logging.LoggingService.ACTION_CONFIGURE_ALWAYS_ON_LOGGING \
+    -e intent_key_enable "true" -e intent_key_config "{_LS_MASK_NAME}" \
+    --ei intent_key_max_log_size_mb 100 --ei intent_key_max_number_of_files 100
+"""
+_LS_DISABLE_LOG_SHELL = """\
+am broadcast -n com.android.pixellogger/.receiver.AlwaysOnLoggingReceiver \
+    -a com.android.pixellogger.service.logging.LoggingService.ACTION_CONFIGURE_ALWAYS_ON_LOGGING \
+    -e intent_key_enable "false"
+"""
+
+
 def check_if_tensor_platform(ad):
     """Check if current platform belongs to the Tensor platform
 
@@ -71,42 +86,54 @@
         return True
 
 
-def start_sdm_logger(ad, retry=5):
+def start_sdm_logger(ad):
     """Start SDM logger."""
     if not getattr(ad, "sdm_log", True): return
+
     # Delete existing SDM logs which were created 15 mins prior
     ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
     file_count = ad.adb.shell(
-        "find %s -type f -iname sbuff_[0-9]*.sdm* | wc -l" % ad.sdm_log_path)
+        f"find {ad.sdm_log_path} -type f -iname sbuff_[0-9]*.sdm* | wc -l")
     if int(file_count) > 3:
         seconds = 15 * 60
         # Remove sdm logs modified more than specified seconds ago
         ad.adb.shell(
-            "find %s -type f -iname sbuff_[0-9]*.sdm* -not -mtime -%ss -delete" %
-            (ad.sdm_log_path, seconds))
-    # Disable any modem logging already running
-    if not getattr(ad, "enable_always_on_modem_logger", False):
-        ad.adb.shell("setprop persist.vendor.sys.modem.logging.enable false")
+            f"find {ad.sdm_log_path} -type f -iname sbuff_[0-9]*.sdm* "
+            f"-not -mtime -{seconds}s -delete")
+
+    # Disable modem logging already running
+    stop_sdm_logger(ad)
+
     # start logging
-    cmd = "setprop vendor.sys.modem.logging.enable true"
-    for _ in range(retry):
-        disable_complete = '0' in ad.adb.shell(
-            "find %s -type f -iname sbuff_profile.sdm | wc -l" % ad.sdm_log_path)
-        if disable_complete:
-            ad.log.debug("start sdm logging")
-            ad.adb.shell(cmd, ignore_status=True)
-            break
+    ad.log.debug("start sdm logging")
+    while int(
+        ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+                     "-iname sbuff_profile.sdm | wc -l") == 0 or
+        int(
+            ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+                         "-iname sbuff_[0-9]*.sdm* | wc -l")) == 0):
+        ad.adb.shell(_LS_ENABLE_LOG_SHELL, ignore_status=True)
         time.sleep(5)
-        ad.adb.shell("setprop persist.vendor.sys.modem.logging.enable false")
-    time.sleep(5)
 
 
 def stop_sdm_logger(ad):
     """Stop SDM logger."""
-    cmd = "setprop vendor.sys.modem.logging.enable false"
+    ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
+    cycle = 1
+
     ad.log.debug("stop sdm logging")
-    ad.adb.shell(cmd, ignore_status=True)
-    time.sleep(5)
+    while int(
+        ad.adb.shell(
+            f"find {ad.sdm_log_path} -type f -iname sbuff_profile.sdm -o "
+            "-iname sbuff_[0-9]*.sdm* | wc -l")) != 0:
+        if cycle == 1 and int(
+            ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+                         "-iname sbuff_profile.sdm | wc -l")) == 0:
+            ad.adb.shell(_LS_ENABLE_LOG_SHELL, ignore_status=True)
+            time.sleep(5)
+        ad.adb.shell(_LS_DISABLE_LOG_SHELL, ignore_status=True)
+        cycle += 1
+        time.sleep(15)
 
 
 def start_sdm_loggers(log, ads):
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py
index a847980..6077d9c 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py
@@ -37,6 +37,7 @@
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
+from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
 from acts_contrib.test_utils.tel.tel_defines import RAT_5G
 from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
 from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
@@ -45,10 +46,11 @@
 from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
 from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
 from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_for_subscription
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
 from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
 from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte_for_subscription
 from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
@@ -66,6 +68,8 @@
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import _is_attached
+from acts_contrib.test_utils.tel.tel_test_utils import _is_attached_for_subscription
 from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
 from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state_for_subscription
 from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
@@ -82,7 +86,6 @@
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
 from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_voice_attach_for_subscription
 from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
 from acts_contrib.test_utils.tel.tel_wifi_utils import set_wifi_to_default
 from acts.libs.utils.multithread import multithread_func
@@ -750,8 +753,7 @@
         nr_type: NR network type e.g. NSA, SA, MMWAVE
     """
     if nw_gen == GEN_5G:
-        if not is_current_network_5g_for_subscription(ad, sub_id=sub_id,
-                                            nr_type=nr_type):
+        if not is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
             ad.log.error("Not in 5G coverage.")
             return False
     else:
@@ -836,7 +838,7 @@
         nw_gen: GEN_4G or GEN_5G
     """
     if nw_gen == GEN_5G:
-        if not is_current_network_5g_for_subscription(ad, sub_id=sub_id, nr_type=nr_type):
+        if not is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
             ad.log.error("Not in 5G coverage.")
             return False
     else:
@@ -1403,8 +1405,7 @@
         return True
 
     if (generation == GEN_5G) or (generation == RAT_5G):
-        if is_current_network_5g_for_subscription(ad, sub_id=sub_id,
-                                        nr_type=nr_type):
+        if is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
             ad.log.info("Current network type is 5G.")
             return True
         else:
@@ -1529,7 +1530,7 @@
         nr_type=None):
 
     if generation == GEN_5G:
-        if is_current_network_5g_for_subscription(ad, sub_id=sub_id, nr_type=nr_type):
+        if is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
             ad.log.info("Current network type is 5G.")
             return True
         else:
@@ -1712,4 +1713,46 @@
         If phone become not in call state within max_time, return True.
         Return False if timeout.
     """
-    return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
\ No newline at end of file
+    return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
+
+
+def wait_for_voice_attach(log, ad, max_time=MAX_WAIT_TIME_NW_SELECTION):
+    """Wait for android device to attach on voice.
+
+    Args:
+        log: log object.
+        ad:  android device.
+        max_time: maximal wait time.
+
+    Returns:
+        Return True if device attach voice within max_time.
+        Return False if timeout.
+    """
+    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
+                                    NETWORK_SERVICE_VOICE)
+
+
+def wait_for_voice_attach_for_subscription(
+        log, ad, sub_id, max_time=MAX_WAIT_TIME_NW_SELECTION):
+    """Wait for android device to attach on voice in subscription id.
+
+    Args:
+        log: log object.
+        ad:  android device.
+        sub_id: subscription id.
+        max_time: maximal wait time.
+
+    Returns:
+        Return True if device attach voice within max_time.
+        Return False if timeout.
+    """
+    if not _wait_for_droid_in_state_for_subscription(
+            log, ad, sub_id, max_time, _is_attached_for_subscription,
+            NETWORK_SERVICE_VOICE):
+        return False
+
+    # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
+    # receive incoming call immediately.
+    if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
+        time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
+    return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
index d4685e4..3d7e935 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@
 from acts.controllers.android_device import list_adb_devices
 from acts.controllers.android_device import list_fastboot_devices
 
-from acts.controllers.android_device import SL4A_APK_NAME
 from acts.libs.proc.job import TimeoutError
 from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
 from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
@@ -59,18 +58,13 @@
 from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
 from acts_contrib.test_utils.tel.tel_defines import MAX_SCREEN_ON_TIME
 from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_AIRPLANEMODE_EVENT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
 from acts_contrib.test_utils.tel.tel_defines import MESSAGE_PACKAGE_NAME
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_NW_VALID_FAIL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL_RECOVERY
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
 from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_7_DIGIT
 from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_10_DIGIT
 from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_11_DIGIT
 from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_12_DIGIT
-from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
 from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
 from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
 from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
@@ -83,7 +77,6 @@
 from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
 from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_READY
 from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
 from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
@@ -91,7 +84,6 @@
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import TYPE_MOBILE
 from acts_contrib.test_utils.tel.tel_defines import EventActiveDataSubIdChanged
 from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
 from acts_contrib.test_utils.tel.tel_defines import EventServiceStateChanged
@@ -554,66 +546,6 @@
     return None
 
 
-def check_data_stall_detection(ad, wait_time=WAIT_TIME_FOR_DATA_STALL):
-    data_stall_detected = False
-    time_var = 1
-    try:
-        while (time_var < wait_time):
-            out = ad.adb.shell("dumpsys network_stack " \
-                              "| grep \"Suspecting data stall\"",
-                            ignore_status=True)
-            ad.log.debug("Output is %s", out)
-            if out:
-                ad.log.info("NetworkMonitor detected - %s", out)
-                data_stall_detected = True
-                break
-            time.sleep(30)
-            time_var += 30
-    except Exception as e:
-        ad.log.error(e)
-    return data_stall_detected
-
-
-def check_network_validation_fail(ad, begin_time=None,
-                                  wait_time=WAIT_TIME_FOR_NW_VALID_FAIL):
-    network_validation_fail = False
-    time_var = 1
-    try:
-        while (time_var < wait_time):
-            time_var += 30
-            nw_valid = ad.search_logcat("validation failed",
-                                         begin_time)
-            if nw_valid:
-                ad.log.info("Validation Failed received here - %s",
-                            nw_valid[0]["log_message"])
-                network_validation_fail = True
-                break
-            time.sleep(30)
-    except Exception as e:
-        ad.log.error(e)
-    return network_validation_fail
-
-
-def check_data_stall_recovery(ad, begin_time=None,
-                              wait_time=WAIT_TIME_FOR_DATA_STALL_RECOVERY):
-    data_stall_recovery = False
-    time_var = 1
-    try:
-        while (time_var < wait_time):
-            time_var += 30
-            recovery = ad.search_logcat("doRecovery() cleanup all connections",
-                                         begin_time)
-            if recovery:
-                ad.log.info("Recovery Performed here - %s",
-                            recovery[-1]["log_message"])
-                data_stall_recovery = True
-                break
-            time.sleep(30)
-    except Exception as e:
-        ad.log.error(e)
-    return data_stall_recovery
-
-
 def break_internet_except_sl4a_port(ad, sl4a_port):
     ad.log.info("Breaking internet using iptables rules")
     ad.adb.shell("iptables -I INPUT 1 -p tcp --dport %s -j ACCEPT" % sl4a_port,
@@ -1404,7 +1336,7 @@
     return file_directory, file_name
 
 
-def _check_file_existance(ad, file_path, expected_file_size=None):
+def _check_file_existence(ad, file_path, expected_file_size=None):
     """Check file existance by file_path. If expected_file_size
        is provided, then also check if the file meet the file size requirement.
     """
@@ -1432,132 +1364,6 @@
         return False
 
 
-def check_curl_availability(ad):
-    if not hasattr(ad, "curl_capable"):
-        try:
-            out = ad.adb.shell("/data/curl --version")
-            if not out or "not found" in out:
-                setattr(ad, "curl_capable", False)
-                ad.log.info("curl is unavailable, use chrome to download file")
-            else:
-                setattr(ad, "curl_capable", True)
-        except Exception:
-            setattr(ad, "curl_capable", False)
-            ad.log.info("curl is unavailable, use chrome to download file")
-    return ad.curl_capable
-
-
-def start_youtube_video(ad, url="vnd.youtube:watch?v=pSJoP0LR8CQ"):
-    ad.log.info("Open an youtube video")
-    for _ in range(3):
-        ad.ensure_screen_on()
-        ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
-        if wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1):
-            ad.log.info("Started a video in youtube, audio is in MUSIC state")
-            return True
-        ad.log.info("Audio is not in MUSIC state. Quit Youtube.")
-        for _ in range(3):
-            ad.send_keycode("BACK")
-            time.sleep(1)
-        time.sleep(3)
-    return False
-
-
-def active_file_download_task(log, ad, file_name="5MB", method="curl"):
-    # files available for download on the same website:
-    # 1GB.zip, 512MB.zip, 200MB.zip, 50MB.zip, 20MB.zip, 10MB.zip, 5MB.zip
-    # download file by adb command, as phone call will use sl4a
-    file_size_map = {
-        '1MB': 1000000,
-        '5MB': 5000000,
-        '10MB': 10000000,
-        '20MB': 20000000,
-        '50MB': 50000000,
-        '100MB': 100000000,
-        '200MB': 200000000,
-        '512MB': 512000000
-    }
-    url_map = {
-        "1MB": [
-            "http://146.148.91.8/download/1MB.zip",
-            "http://ipv4.download.thinkbroadband.com/1MB.zip"
-        ],
-        "5MB": [
-            "http://146.148.91.8/download/5MB.zip",
-            "http://212.183.159.230/5MB.zip",
-            "http://ipv4.download.thinkbroadband.com/5MB.zip"
-        ],
-        "10MB": [
-            "http://146.148.91.8/download/10MB.zip",
-            "http://212.183.159.230/10MB.zip",
-            "http://ipv4.download.thinkbroadband.com/10MB.zip",
-            "http://lax.futurehosting.com/test.zip",
-            "http://ovh.net/files/10Mio.dat"
-        ],
-        "20MB": [
-            "http://146.148.91.8/download/20MB.zip",
-            "http://212.183.159.230/20MB.zip",
-            "http://ipv4.download.thinkbroadband.com/20MB.zip"
-        ],
-        "50MB": [
-            "http://146.148.91.8/download/50MB.zip",
-            "http://212.183.159.230/50MB.zip",
-            "http://ipv4.download.thinkbroadband.com/50MB.zip"
-        ],
-        "100MB": [
-            "http://146.148.91.8/download/100MB.zip",
-            "http://212.183.159.230/100MB.zip",
-            "http://ipv4.download.thinkbroadband.com/100MB.zip",
-            "http://speedtest-ca.turnkeyinternet.net/100mb.bin",
-            "http://ovh.net/files/100Mio.dat",
-            "http://lax.futurehosting.com/test100.zip"
-        ],
-        "200MB": [
-            "http://146.148.91.8/download/200MB.zip",
-            "http://212.183.159.230/200MB.zip",
-            "http://ipv4.download.thinkbroadband.com/200MB.zip"
-        ],
-        "512MB": [
-            "http://146.148.91.8/download/512MB.zip",
-            "http://212.183.159.230/512MB.zip",
-            "http://ipv4.download.thinkbroadband.com/512MB.zip"
-        ]
-    }
-
-    file_size = file_size_map.get(file_name)
-    file_urls = url_map.get(file_name)
-    file_url = None
-    for url in file_urls:
-        url_splits = url.split("/")
-        if verify_http_connection(log, ad, url=url, retry=1):
-            output_path = "/sdcard/Download/%s" % url_splits[-1]
-            file_url = url
-            break
-    if not file_url:
-        ad.log.error("No url is available to download %s", file_name)
-        return False
-    timeout = min(max(file_size / 100000, 600), 3600)
-    if method == "sl4a":
-        return (http_file_download_by_sl4a, (ad, file_url, output_path,
-                                             file_size, True, timeout))
-    if method == "curl" and check_curl_availability(ad):
-        return (http_file_download_by_curl, (ad, file_url, output_path,
-                                             file_size, True, timeout))
-    elif method == "sl4a" or method == "curl":
-        return (http_file_download_by_sl4a, (ad, file_url, output_path,
-                                             file_size, True, timeout))
-    else:
-        return (http_file_download_by_chrome, (ad, file_url, file_size, True,
-                                               timeout))
-
-
-def active_file_download_test(log, ad, file_name="5MB", method="sl4a"):
-    task = active_file_download_task(log, ad, file_name, method=method)
-    if not task:
-        return False
-    return task[0](*task[1])
-
-
 def verify_internet_connection_by_ping(log,
                                        ad,
                                        retries=1,
@@ -1811,316 +1617,6 @@
             return False
 
 
-def http_file_download_by_curl(ad,
-                               url,
-                               out_path=None,
-                               expected_file_size=None,
-                               remove_file_after_check=True,
-                               timeout=3600,
-                               limit_rate=None,
-                               retry=3):
-    """Download http file by adb curl.
-
-    Args:
-        ad: Android Device Object.
-        url: The url that file to be downloaded from".
-        out_path: Optional. Where to download file to.
-                  out_path is /sdcard/Download/ by default.
-        expected_file_size: Optional. Provided if checking the download file meet
-                            expected file size in unit of byte.
-        remove_file_after_check: Whether to remove the downloaded file after
-                                 check.
-        timeout: timeout for file download to complete.
-        limit_rate: download rate in bps. None, if do not apply rate limit.
-        retry: the retry request times provided in curl command.
-    """
-    file_directory, file_name = _generate_file_directory_and_file_name(
-        url, out_path)
-    file_path = os.path.join(file_directory, file_name)
-    curl_cmd = "/data/curl"
-    if limit_rate:
-        curl_cmd += " --limit-rate %s" % limit_rate
-    if retry:
-        curl_cmd += " --retry %s" % retry
-    curl_cmd += " --url %s > %s" % (url, file_path)
-    try:
-        ad.log.info("Download %s to %s by adb shell command %s", url,
-                    file_path, curl_cmd)
-
-        ad.adb.shell(curl_cmd, timeout=timeout)
-        if _check_file_existance(ad, file_path, expected_file_size):
-            ad.log.info("%s is downloaded to %s successfully", url, file_path)
-            return True
-        else:
-            ad.log.warning("Fail to download %s", url)
-            return False
-    except Exception as e:
-        ad.log.warning("Download %s failed with exception %s", url, e)
-        return False
-    finally:
-        if remove_file_after_check:
-            ad.log.info("Remove the downloaded file %s", file_path)
-            ad.adb.shell("rm %s" % file_path, ignore_status=True)
-
-
-def open_url_by_adb(ad, url):
-    ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
-
-
-def http_file_download_by_chrome(ad,
-                                 url,
-                                 expected_file_size=None,
-                                 remove_file_after_check=True,
-                                 timeout=3600):
-    """Download http file by chrome.
-
-    Args:
-        ad: Android Device Object.
-        url: The url that file to be downloaded from".
-        expected_file_size: Optional. Provided if checking the download file meet
-                            expected file size in unit of byte.
-        remove_file_after_check: Whether to remove the downloaded file after
-                                 check.
-        timeout: timeout for file download to complete.
-    """
-    chrome_apk = "com.android.chrome"
-    file_directory, file_name = _generate_file_directory_and_file_name(
-        url, "/sdcard/Download/")
-    file_path = os.path.join(file_directory, file_name)
-    # Remove pre-existing file
-    ad.force_stop_apk(chrome_apk)
-    file_to_be_delete = os.path.join(file_directory, "*%s*" % file_name)
-    ad.adb.shell("rm -f %s" % file_to_be_delete)
-    ad.adb.shell("rm -rf /sdcard/Download/.*")
-    ad.adb.shell("rm -f /sdcard/Download/.*")
-    data_accounting = {
-        "total_rx_bytes": ad.droid.getTotalRxBytes(),
-        "mobile_rx_bytes": ad.droid.getMobileRxBytes(),
-        "subscriber_mobile_data_usage": get_mobile_data_usage(ad, None, None),
-        "chrome_mobile_data_usage": get_mobile_data_usage(
-            ad, None, chrome_apk)
-    }
-    ad.log.debug("Before downloading: %s", data_accounting)
-    ad.log.info("Download %s with timeout %s", url, timeout)
-    ad.ensure_screen_on()
-    open_url_by_adb(ad, url)
-    elapse_time = 0
-    result = True
-    while elapse_time < timeout:
-        time.sleep(30)
-        if _check_file_existance(ad, file_path, expected_file_size):
-            ad.log.info("%s is downloaded successfully", url)
-            if remove_file_after_check:
-                ad.log.info("Remove the downloaded file %s", file_path)
-                ad.adb.shell("rm -f %s" % file_to_be_delete)
-                ad.adb.shell("rm -rf /sdcard/Download/.*")
-                ad.adb.shell("rm -f /sdcard/Download/.*")
-            #time.sleep(30)
-            new_data_accounting = {
-                "mobile_rx_bytes":
-                ad.droid.getMobileRxBytes(),
-                "subscriber_mobile_data_usage":
-                get_mobile_data_usage(ad, None, None),
-                "chrome_mobile_data_usage":
-                get_mobile_data_usage(ad, None, chrome_apk)
-            }
-            ad.log.info("After downloading: %s", new_data_accounting)
-            accounting_diff = {
-                key: value - data_accounting[key]
-                for key, value in new_data_accounting.items()
-            }
-            ad.log.debug("Data accounting difference: %s", accounting_diff)
-            if getattr(ad, "on_mobile_data", False):
-                for key, value in accounting_diff.items():
-                    if value < expected_file_size:
-                        ad.log.warning("%s diff is %s less than %s", key,
-                                       value, expected_file_size)
-                        ad.data_accounting["%s_failure" % key] += 1
-            else:
-                for key, value in accounting_diff.items():
-                    if value >= expected_file_size:
-                        ad.log.error("%s diff is %s. File download is "
-                                     "consuming mobile data", key, value)
-                        result = False
-            return result
-        elif _check_file_existance(ad, "%s.crdownload" % file_path):
-            ad.log.info("Chrome is downloading %s", url)
-        elif elapse_time < 60:
-            # download not started, retry download wit chrome again
-            open_url_by_adb(ad, url)
-        else:
-            ad.log.error("Unable to download file from %s", url)
-            break
-        elapse_time += 30
-    ad.log.warning("Fail to download file from %s", url)
-    ad.force_stop_apk("com.android.chrome")
-    ad.adb.shell("rm -f %s" % file_to_be_delete)
-    ad.adb.shell("rm -rf /sdcard/Download/.*")
-    ad.adb.shell("rm -f /sdcard/Download/.*")
-    return False
-
-
-def http_file_download_by_sl4a(ad,
-                               url,
-                               out_path=None,
-                               expected_file_size=None,
-                               remove_file_after_check=True,
-                               timeout=300):
-    """Download http file by sl4a RPC call.
-
-    Args:
-        ad: Android Device Object.
-        url: The url that file to be downloaded from".
-        out_path: Optional. Where to download file to.
-                  out_path is /sdcard/Download/ by default.
-        expected_file_size: Optional. Provided if checking the download file meet
-                            expected file size in unit of byte.
-        remove_file_after_check: Whether to remove the downloaded file after
-                                 check.
-        timeout: timeout for file download to complete.
-    """
-    file_folder, file_name = _generate_file_directory_and_file_name(
-        url, out_path)
-    file_path = os.path.join(file_folder, file_name)
-    ad.adb.shell("rm -f %s" % file_path)
-    accounting_apk = SL4A_APK_NAME
-    result = True
-    try:
-        if not getattr(ad, "data_droid", None):
-            ad.data_droid, ad.data_ed = ad.get_droid()
-            ad.data_ed.start()
-        else:
-            try:
-                if not ad.data_droid.is_live:
-                    ad.data_droid, ad.data_ed = ad.get_droid()
-                    ad.data_ed.start()
-            except Exception:
-                ad.log.info("Start new sl4a session for file download")
-                ad.data_droid, ad.data_ed = ad.get_droid()
-                ad.data_ed.start()
-        data_accounting = {
-            "mobile_rx_bytes":
-            ad.droid.getMobileRxBytes(),
-            "subscriber_mobile_data_usage":
-            get_mobile_data_usage(ad, None, None),
-            "sl4a_mobile_data_usage":
-            get_mobile_data_usage(ad, None, accounting_apk)
-        }
-        ad.log.debug("Before downloading: %s", data_accounting)
-        ad.log.info("Download file from %s to %s by sl4a RPC call", url,
-                    file_path)
-        try:
-            ad.data_droid.httpDownloadFile(url, file_path, timeout=timeout)
-        except Exception as e:
-            ad.log.warning("SL4A file download error: %s", e)
-            ad.data_droid.terminate()
-            return False
-        if _check_file_existance(ad, file_path, expected_file_size):
-            ad.log.info("%s is downloaded successfully", url)
-            new_data_accounting = {
-                "mobile_rx_bytes":
-                ad.droid.getMobileRxBytes(),
-                "subscriber_mobile_data_usage":
-                get_mobile_data_usage(ad, None, None),
-                "sl4a_mobile_data_usage":
-                get_mobile_data_usage(ad, None, accounting_apk)
-            }
-            ad.log.debug("After downloading: %s", new_data_accounting)
-            accounting_diff = {
-                key: value - data_accounting[key]
-                for key, value in new_data_accounting.items()
-            }
-            ad.log.debug("Data accounting difference: %s", accounting_diff)
-            if getattr(ad, "on_mobile_data", False):
-                for key, value in accounting_diff.items():
-                    if value < expected_file_size:
-                        ad.log.debug("%s diff is %s less than %s", key,
-                                       value, expected_file_size)
-                        ad.data_accounting["%s_failure"] += 1
-            else:
-                for key, value in accounting_diff.items():
-                    if value >= expected_file_size:
-                        ad.log.error("%s diff is %s. File download is "
-                                     "consuming mobile data", key, value)
-                        result = False
-            return result
-        else:
-            ad.log.warning("Fail to download %s", url)
-            return False
-    except Exception as e:
-        ad.log.error("Download %s failed with exception %s", url, e)
-        raise
-    finally:
-        if remove_file_after_check:
-            ad.log.info("Remove the downloaded file %s", file_path)
-            ad.adb.shell("rm %s" % file_path, ignore_status=True)
-
-
-def get_mobile_data_usage(ad, sid=None, apk=None):
-    if not sid:
-        sid = ad.droid.subscriptionGetDefaultDataSubId()
-    current_time = int(time.time() * 1000)
-    begin_time = current_time - 10 * 24 * 60 * 60 * 1000
-    end_time = current_time + 10 * 24 * 60 * 60 * 1000
-
-    if apk:
-        uid = ad.get_apk_uid(apk)
-        ad.log.debug("apk %s uid = %s", apk, uid)
-        try:
-            usage_info = ad.droid.getMobileDataUsageInfoForUid(uid, sid)
-            ad.log.debug("Mobile data usage info for uid %s = %s", uid,
-                        usage_info)
-            return usage_info["UsageLevel"]
-        except:
-            try:
-                return ad.droid.connectivityQueryDetailsForUid(
-                    TYPE_MOBILE,
-                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
-                    begin_time, end_time, uid)
-            except:
-                return ad.droid.connectivityQueryDetailsForUid(
-                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
-                    begin_time, end_time, uid)
-    else:
-        try:
-            usage_info = ad.droid.getMobileDataUsageInfo(sid)
-            ad.log.debug("Mobile data usage info = %s", usage_info)
-            return usage_info["UsageLevel"]
-        except:
-            try:
-                return ad.droid.connectivityQuerySummaryForDevice(
-                    TYPE_MOBILE,
-                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
-                    begin_time, end_time)
-            except:
-                return ad.droid.connectivityQuerySummaryForDevice(
-                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
-                    begin_time, end_time)
-
-
-def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
-    if not subscriber_id:
-        subscriber_id = ad.droid.telephonyGetSubscriberId()
-    ad.log.debug("Set subscriber mobile data usage limit to %s", limit)
-    ad.droid.logV("Setting subscriber mobile data usage limit to %s" % limit)
-    try:
-        ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
-    except:
-        ad.droid.connectivitySetDataUsageLimit(subscriber_id, limit)
-
-
-def remove_mobile_data_usage_limit(ad, subscriber_id=None):
-    if not subscriber_id:
-        subscriber_id = ad.droid.telephonyGetSubscriberId()
-    ad.log.debug("Remove subscriber mobile data usage limit")
-    ad.droid.logV(
-        "Setting subscriber mobile data usage limit to -1, unlimited")
-    try:
-        ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
-    except:
-        ad.droid.connectivitySetDataUsageLimit(subscriber_id, -1)
-
-
 def trigger_modem_crash(ad, timeout=120):
     cmd = "echo restart > /sys/kernel/debug/msm_subsys/modem"
     ad.log.info("Triggering Modem Crash from kernel using adb command %s", cmd)
@@ -2456,48 +1952,6 @@
         log, ad, ad.droid.subscriptionGetDefaultSubId(), NETWORK_SERVICE_VOICE)
 
 
-def wait_for_voice_attach(log, ad, max_time=MAX_WAIT_TIME_NW_SELECTION):
-    """Wait for android device to attach on voice.
-
-    Args:
-        log: log object.
-        ad:  android device.
-        max_time: maximal wait time.
-
-    Returns:
-        Return True if device attach voice within max_time.
-        Return False if timeout.
-    """
-    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
-                                    NETWORK_SERVICE_VOICE)
-
-
-def wait_for_voice_attach_for_subscription(
-        log, ad, sub_id, max_time=MAX_WAIT_TIME_NW_SELECTION):
-    """Wait for android device to attach on voice in subscription id.
-
-    Args:
-        log: log object.
-        ad:  android device.
-        sub_id: subscription id.
-        max_time: maximal wait time.
-
-    Returns:
-        Return True if device attach voice within max_time.
-        Return False if timeout.
-    """
-    if not _wait_for_droid_in_state_for_subscription(
-            log, ad, sub_id, max_time, _is_attached_for_subscription,
-            NETWORK_SERVICE_VOICE):
-        return False
-
-    # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
-    # receive incoming call immediately.
-    if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
-        time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
-    return True
-
-
 def wait_for_data_attach(log, ad, max_time):
     """Wait for android device to attach on data.
 
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
index 68b4f63..62e3d1e 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
@@ -64,7 +64,6 @@
 from acts_contrib.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
 from acts_contrib.test_utils.tel.tel_defines import CallStateContainer
 from acts_contrib.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
 from acts_contrib.test_utils.tel.tel_ims_utils import is_wfc_enabled
 from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
 from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
@@ -77,6 +76,7 @@
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_rat
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_not_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_voice_attach
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
@@ -103,7 +103,6 @@
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
 from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
 from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_voice_attach
 from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
 from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
 
@@ -351,15 +350,8 @@
                   ad,
                   callee_number,
                   emergency=False,
-                  timeout=MAX_WAIT_TIME_CALL_INITIATION,
-                  checking_interval=5,
                   incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
-                  video=False,
-                  voice_type_init=None,
-                  call_stats_check=False,
-                  result_info=result_dict,
-                  nw_gen_5g=False,
-                  nr_type= None):
+                  video=False):
     """Make phone call from caller to callee.
 
     Args:
@@ -400,10 +392,6 @@
             ad.adb.shell("i2cset -fy 3 65 6 1 b", ignore_status=True)
         ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
 
-        if nw_gen_5g:
-            if not is_current_network_5g(ad, nr_type= nr_type):
-                ad.log.error("Phone is not attached on 5G")
-
         if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
             ad.droid.telecomShowInCallScreen()
         elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
@@ -738,9 +726,7 @@
                         slot_id_callee=None,
                         voice_type_init=None,
                         call_stats_check=False,
-                        result_info=result_dict,
-                        nsa_5g_for_stress=False,
-                        nr_type= None):
+                        result_info=result_dict):
     """ Call process, including make a phone call from caller,
     accept from callee, and hang up. The call is on default voice subscription
 
@@ -779,8 +765,7 @@
         log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
         verify_caller_func, verify_callee_func, wait_time_in_call,
         incall_ui_display, dialing_number_length, video_state,
-        voice_type_init, call_stats_check, result_info, nsa_5g_for_stress,
-        nr_type)
+        voice_type_init, call_stats_check, result_info)
 
 
 def call_setup_teardown_for_subscription(
@@ -798,9 +783,7 @@
         video_state=None,
         voice_type_init=None,
         call_stats_check=False,
-        result_info=result_dict,
-        nsa_5g_for_stress=False,
-        nr_type= None):
+        result_info=result_dict):
     """ Call process, including make a phone call from caller,
     accept from callee, and hang up. The call is on specified subscription
 
@@ -874,136 +857,91 @@
         setattr(ad, "call_ids", call_ids)
         if call_ids:
             ad.log.info("Pre-exist CallId %s before making call", call_ids)
-    try:
-        if not initiate_call(
-                log,
-                ad_caller,
-                callee_number,
-                incall_ui_display=incall_ui_display,
-                video=video):
-            ad_caller.log.error("Initiate call failed.")
-            tel_result_wrapper.result_value = CallResult('INITIATE_FAILED')
-            return tel_result_wrapper
-        else:
-            ad_caller.log.info("Caller initate call successfully")
-        if not wait_and_answer_call_for_subscription(
-                log,
-                ad_callee,
-                subid_callee,
-                incoming_number=caller_number,
-                caller=ad_caller,
-                incall_ui_display=incall_ui_display,
-                video_state=video_state):
-            ad_callee.log.error("Answer call fail.")
-            tel_result_wrapper.result_value = CallResult(
-                'NO_RING_EVENT_OR_ANSWER_FAILED')
-            return tel_result_wrapper
-        else:
-            ad_callee.log.info("Callee answered the call successfully")
 
-        for ad, call_func in zip([ad_caller, ad_callee],
-                                 [verify_caller_func, verify_callee_func]):
-            call_ids = ad.droid.telecomCallGetCallIds()
-            new_call_ids = set(call_ids) - set(ad.call_ids)
-            if not new_call_ids:
-                ad.log.error(
-                    "No new call ids are found after call establishment")
-                ad.log.error("telecomCallGetCallIds returns %s",
-                             ad.droid.telecomCallGetCallIds())
-                tel_result_wrapper.result_value = CallResult('NO_CALL_ID_FOUND')
-            for new_call_id in new_call_ids:
-                if not wait_for_in_call_active(ad, call_id=new_call_id):
-                    tel_result_wrapper.result_value = CallResult(
-                        'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
-                else:
-                    ad.log.info("callProperties = %s",
-                                ad.droid.telecomCallGetProperties(new_call_id))
+    if not initiate_call(
+            log,
+            ad_caller,
+            callee_number,
+            incall_ui_display=incall_ui_display,
+            video=video):
+        ad_caller.log.error("Initiate call failed.")
+        tel_result_wrapper.result_value = CallResult('INITIATE_FAILED')
+        return tel_result_wrapper
+    else:
+        ad_caller.log.info("Caller initate call successfully")
+    if not wait_and_answer_call_for_subscription(
+            log,
+            ad_callee,
+            subid_callee,
+            incoming_number=caller_number,
+            caller=ad_caller,
+            incall_ui_display=incall_ui_display,
+            video_state=video_state):
+        ad_callee.log.error("Answer call fail.")
+        tel_result_wrapper.result_value = CallResult(
+            'NO_RING_EVENT_OR_ANSWER_FAILED')
+        return tel_result_wrapper
+    else:
+        ad_callee.log.info("Callee answered the call successfully")
 
-            if not ad.droid.telecomCallGetAudioState():
-                ad.log.error("Audio is not in call state")
+    for ad, call_func in zip([ad_caller, ad_callee],
+                                [verify_caller_func, verify_callee_func]):
+        call_ids = ad.droid.telecomCallGetCallIds()
+        new_call_ids = set(call_ids) - set(ad.call_ids)
+        if not new_call_ids:
+            ad.log.error(
+                "No new call ids are found after call establishment")
+            ad.log.error("telecomCallGetCallIds returns %s",
+                            ad.droid.telecomCallGetCallIds())
+            tel_result_wrapper.result_value = CallResult('NO_CALL_ID_FOUND')
+        for new_call_id in new_call_ids:
+            if not wait_for_in_call_active(ad, call_id=new_call_id):
                 tel_result_wrapper.result_value = CallResult(
-                    'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
-
-            if call_func(log, ad):
-                ad.log.info("Call is in %s state", call_func.__name__)
+                    'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
             else:
-                ad.log.error("Call is not in %s state, voice in RAT %s",
-                             call_func.__name__,
-                             ad.droid.telephonyGetCurrentVoiceNetworkType())
-                tel_result_wrapper.result_value = CallResult(
-                    'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
-        if not tel_result_wrapper:
-            return tel_result_wrapper
+                ad.log.info("callProperties = %s",
+                            ad.droid.telecomCallGetProperties(new_call_id))
 
-        if call_stats_check:
-            voice_type_in_call = check_voice_network_type([ad_caller, ad_callee], voice_init=False)
-            phone_a_call_type = check_call_status(ad_caller,
-                                                  voice_type_init[0],
-                                                  voice_type_in_call[0])
-            result_info["Call Stats"] = phone_a_call_type
-            ad_caller.log.debug("Voice Call Type: %s", phone_a_call_type)
-            phone_b_call_type = check_call_status(ad_callee,
-                                                  voice_type_init[1],
-                                                  voice_type_in_call[1])
-            result_info["Call Stats"] = phone_b_call_type
-            ad_callee.log.debug("Voice Call Type: %s", phone_b_call_type)
+        if not ad.droid.telecomCallGetAudioState():
+            ad.log.error("Audio is not in call state")
+            tel_result_wrapper.result_value = CallResult(
+                'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
 
-        elapsed_time = 0
-        while (elapsed_time < wait_time_in_call):
-            CHECK_INTERVAL = min(CHECK_INTERVAL,
-                                 wait_time_in_call - elapsed_time)
-            time.sleep(CHECK_INTERVAL)
-            elapsed_time += CHECK_INTERVAL
-            time_message = "at <%s>/<%s> second." % (elapsed_time,
-                                                     wait_time_in_call)
-            for ad, call_func in [(ad_caller, verify_caller_func),
-                                  (ad_callee, verify_callee_func)]:
-                if not call_func(log, ad):
-                    ad.log.error(
-                        "NOT in correct %s state at %s, voice in RAT %s",
-                        call_func.__name__, time_message,
-                        ad.droid.telephonyGetCurrentVoiceNetworkType())
-                    tel_result_wrapper.result_value = CallResult(
-                        'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
-                else:
-                    ad.log.info("In correct %s state at %s",
-                                call_func.__name__, time_message)
-                if not ad.droid.telecomCallGetAudioState():
-                    ad.log.error("Audio is not in call state at %s",
-                                 time_message)
-                    tel_result_wrapper.result_value = CallResult(
-                        'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
-            if not tel_result_wrapper:
-                return tel_result_wrapper
+        if call_func(log, ad):
+            ad.log.info("Call is in %s state", call_func.__name__)
+        else:
+            ad.log.error("Call is not in %s state, voice in RAT %s",
+                            call_func.__name__,
+                            ad.droid.telephonyGetCurrentVoiceNetworkType())
+            tel_result_wrapper.result_value = CallResult(
+                'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
+    if not tel_result_wrapper:
+        return tel_result_wrapper
 
-        if ad_hangup:
-            if not hangup_call(log, ad_hangup):
-                ad_hangup.log.info("Failed to hang up the call")
-                tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
-                return tel_result_wrapper
-    finally:
-        if not tel_result_wrapper:
-            for ad in (ad_caller, ad_callee):
-                last_call_drop_reason(ad, begin_time)
-                try:
-                    if ad.droid.telecomIsInCall():
-                        ad.log.info("In call. End now.")
-                        ad.droid.telecomEndCall()
-                except Exception as e:
-                    log.error(str(e))
+    if call_stats_check:
+        voice_type_in_call = check_voice_network_type([ad_caller, ad_callee], voice_init=False)
+        phone_a_call_type = check_call_status(ad_caller,
+                                                voice_type_init[0],
+                                                voice_type_in_call[0])
+        result_info["Call Stats"] = phone_a_call_type
+        ad_caller.log.debug("Voice Call Type: %s", phone_a_call_type)
+        phone_b_call_type = check_call_status(ad_callee,
+                                                voice_type_init[1],
+                                                voice_type_in_call[1])
+        result_info["Call Stats"] = phone_b_call_type
+        ad_callee.log.debug("Voice Call Type: %s", phone_b_call_type)
 
-        if nsa_5g_for_stress:
-            for ad in (ad_caller, ad_callee):
-                if not is_current_network_5g(ad, nr_type):
-                    ad.log.error("Phone not attached on 5G")
-
-        if ad_hangup or not tel_result_wrapper:
-            for ad in (ad_caller, ad_callee):
-                if not wait_for_call_id_clearing(
-                        ad, getattr(ad, "caller_ids", [])):
-                    tel_result_wrapper.result_value = CallResult(
-                        'CALL_ID_CLEANUP_FAIL')
-    return tel_result_wrapper
+    return wait_for_call_end(
+        log,
+        ad_caller,
+        ad_callee,
+        ad_hangup,
+        verify_caller_func,
+        verify_callee_func,
+        begin_time,
+        check_interval=CHECK_INTERVAL,
+        tel_result_wrapper=TelResultWrapper(CallResult('SUCCESS')),
+        wait_time_in_call=WAIT_TIME_IN_CALL)
 
 
 def two_phone_call_leave_voice_mail(
@@ -2461,13 +2399,9 @@
                 ad.log.error("Audio is not in call state at %s", time_message)
                 tel_result_wrapper.result_value = CallResult(
                         'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
-        if not tel_result_wrapper:
-            return tel_result_wrapper
 
-    if ad_hangup:
-        if not hangup_call(log, ad_hangup):
-            ad_hangup.log.info("Failed to hang up the call")
-            tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
+        if not tel_result_wrapper:
+            break
 
     if not tel_result_wrapper:
         for ad in (ad_caller, ad_callee):
@@ -2478,6 +2412,12 @@
                     ad.droid.telecomEndCall()
             except Exception as e:
                 log.error(str(e))
+    else:
+        if ad_hangup:
+            if not hangup_call(log, ad_hangup):
+                ad_hangup.log.info("Failed to hang up the call")
+                tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
+
     if ad_hangup or not tel_result_wrapper:
         for ad in (ad_caller, ad_callee):
             if not wait_for_call_id_clearing(ad, getattr(ad, "caller_ids", [])):
diff --git a/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py b/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py
index a00a431..eb56f20 100644
--- a/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py
+++ b/acts_tests/acts_contrib/test_utils_tests/audio_analysis_integrationtest.py
@@ -21,11 +21,6 @@
 import os
 import unittest
 
-# TODO(markdr): Remove this after soundfile is added to setup.py
-import sys
-import mock
-sys.modules['soundfile'] = mock.Mock()
-
 import acts_contrib.test_utils.audio_analysis_lib.audio_analysis as audio_analysis
 import acts_contrib.test_utils.audio_analysis_lib.audio_data as audio_data
 
diff --git a/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py b/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py
index 396e5b8..c8b4f25 100644
--- a/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py
+++ b/acts_tests/acts_contrib/test_utils_tests/audio_quality_measurement_integrationtest.py
@@ -22,11 +22,6 @@
 import numpy
 import unittest
 
-# TODO(markdr): Remove this after soundfile is added to setup.py
-import sys
-import mock
-sys.modules['soundfile'] = mock.Mock()
-
 import acts_contrib.test_utils.audio_analysis_lib.audio_quality_measurement as audio_quality_measurement
 
 
diff --git a/acts_tests/setup.py b/acts_tests/setup.py
index 2269fcd..9f77e9e 100755
--- a/acts_tests/setup.py
+++ b/acts_tests/setup.py
@@ -30,7 +30,7 @@
 
 acts_tests_dir = os.path.abspath(os.path.dirname(__file__))
 
-install_requires = []
+install_requires = ['soundfile']
 
 
 
diff --git a/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py b/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py
index c044b4d..877b00e 100644
--- a/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py
+++ b/acts_tests/tests/google/ble/api/BleAdvertiseApiTest.py
@@ -20,13 +20,16 @@
 then other test suites utilising Ble Advertisements will also fail.
 """
 
+import pprint
+
 from acts.controllers.sl4a_lib import rpc_client
 from acts.test_decorators import test_tracker_info
 from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
-from acts_contrib.test_utils.bt.bt_test_utils import adv_fail
+from acts_contrib.test_utils.bt.bt_test_utils import adv_fail, adv_succ, scan_result
 from acts_contrib.test_utils.bt.bt_test_utils import generate_ble_advertise_objects
 from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_modes
 from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_tx_powers
+# from acts_contrib.test_utils.bt.bt_constants import ble_advertise_settings_own_address_types
 from acts_contrib.test_utils.bt.bt_constants import java_integer
 
 
@@ -38,6 +41,7 @@
     def setup_class(self):
         super().setup_class()
         self.ad_dut = self.android_devices[0]
+        self.sc_dut = self.android_devices[1]
 
     @BluetoothBaseTest.bt_test_wrap
     @test_tracker_info(uuid='d6d8d0a6-7b3e-4e4b-a5d0-bcfd6e207474')
@@ -498,6 +502,149 @@
                                                        exp_is_connectable)
 
     @BluetoothBaseTest.bt_test_wrap
+    def test_adv_settings_set_adv_own_address_type_public(self):
+        """Tests advertise settings own address type public.
+
+        This advertisement settings from "set" advertisement own address type
+        should match the corresponding "get" function.
+
+        Steps:
+        1. Build a new advertise settings object.
+        2. Set the advertise mode attribute to own address type public.
+        3. Get the attributes of the advertise settings object.
+        4. Compare the attributes found against the attributes exp.
+
+        Expected Result:
+        Found attributes should match expected attributes.
+
+        Returns:
+          True is pass
+          False if fail
+
+        TAGS: LE, Advertising
+        Priority: 1
+        """
+        self.log.debug("Step 1: Setup environment.")
+        droid = self.ad_dut.droid
+        # exp_adv_own_address_type = ble_advertise_settings_own_address_types['public']
+        exp_adv_own_address_type = 0
+        self.log.debug(
+            "Step 2: Set the filtering settings object's value to {}".format(
+                exp_adv_own_address_type))
+        return self.verify_adv_settings_own_address_type(droid, exp_adv_own_address_type)
+
+    @BluetoothBaseTest.bt_test_wrap
+    def test_adv_settings_set_adv_own_address_type_random(self):
+        """Tests advertise settings own address type random.
+
+        This advertisement settings from "set" advertisement own address type
+        should match the corresponding "get" function.
+
+        Steps:
+        1. Build a new advertise settings object.
+        2. Set the advertise mode attribute to own address type random.
+        3. Get the attributes of the advertise settings object.
+        4. Compare the attributes found against the attributes exp.
+
+        Expected Result:
+        Found attributes should match expected attributes.
+
+        Returns:
+          True is pass
+          False if fail
+
+        TAGS: LE, Advertising
+        Priority: 1
+        """
+        self.log.debug("Step 1: Setup environment.")
+        droid = self.ad_dut.droid
+        # exp_adv_own_address_type = ble_advertise_settings_own_address_types['random']
+        exp_adv_own_address_type = 1
+        self.log.debug(
+            "Step 2: Set the filtering settings object's value to {}".format(
+                exp_adv_own_address_type))
+        return self.verify_adv_settings_own_address_type(droid, exp_adv_own_address_type)
+
+    @BluetoothBaseTest.bt_test_wrap
+    def test_adv_with_multiple_own_address_types(self):
+        ad_droid = self.ad_dut.droid
+        sc_droid = self.sc_dut.droid
+        sc_ed = self.sc_dut.ed
+        adv_count = 10
+        exp_adv_own_address_types = [0, 1, 1, 0, 0, 1, 1, 1, 0, 0]
+        uuid = '01234567-89ab-cdef-0123-456789abcdef'
+        service_data = []
+
+        for i in range(3):
+            service_data.append(i)
+
+        for own_add_type in exp_adv_own_address_types:
+            result = self.verify_adv_set_address_type_start_adv(ad_droid,
+                    own_add_type, uuid, service_data)
+            if result is False:
+                return False
+
+        mac_list = []
+
+        filter_list = sc_droid.bleGenFilterList()
+        scan_settings = sc_droid.bleBuildScanSetting()
+        scan_callback = sc_droid.bleGenScanCallback()
+        sc_droid.bleStartBleScan(filter_list, scan_settings,
+                                       scan_callback)
+        event_name = scan_result.format(scan_callback)
+        self.log.info("Scan onSuccess Event")
+
+        for _ in range(1000):
+            if len(mac_list) is adv_count:
+                break
+
+            try:
+                event = sc_ed.pop_event(event_name, 10)
+                result = event['data']['Result']
+                deviceInfo = result['deviceInfo']
+                serviceUuidList = result['serviceUuidList']
+                if uuid in serviceUuidList:
+                    mac_addr = deviceInfo['address']
+                    if mac_addr not in mac_list:
+                        self.log.info("Found device. address: {}".format(mac_addr))
+                        mac_list.append(mac_addr)
+
+            except rpc_client.Sl4aApiError:
+                self.log.info("{} event was not found.".format(event_name))
+                break
+
+        return len(mac_list) is adv_count
+
+    @BluetoothBaseTest.bt_test_wrap
+    def test_adv_settings_set_invalid_adv_own_address_type(self):
+        """Tests advertise settings invalid own address type.
+
+        This advertisement settings from "set" advertisement own address type
+        should match the corresponding "get" function.
+
+        Steps:
+        1. Build a new advertise settings object.
+        2. Set the advertise mode attribute to invalid own address type.
+        3. Get the attributes of the advertise settings object.
+        4. Compare the attributes found against the attributes exp.
+
+        Expected Result:
+        Found attributes should match expected attributes.
+
+        Returns:
+          True is pass
+          False if fail
+
+        TAGS: LE, Advertising
+        Priority: 1
+        """
+        self.log.debug("Step 1: Setup environment.")
+        droid = self.ad_dut.droid
+        exp_adv_own_address_type = -100
+        self.log.debug("Step 2: Set the filtering settings own address type to -1")
+        return self.verify_invalid_adv_settings_own_address_type(droid, exp_adv_own_address_type)
+
+    @BluetoothBaseTest.bt_test_wrap
     @test_tracker_info(uuid='a770ed7e-c6cd-4533-8876-e42e68f8b4fb')
     def test_adv_data_set_service_uuids_empty(self):
         """Tests advertisement data's service uuids to empty.
@@ -1095,6 +1242,55 @@
                        " value test Passed.".format(exp_is_connectable))
         return True
 
+    def verify_adv_settings_own_address_type(self, droid, exp_adv_own_address_type):
+        try:
+            droid.bleSetAdvertiseSettingsOwnAddressType(exp_adv_own_address_type)
+        except BleAdvertiseVerificationError as error:
+            self.log.debug(str(error))
+            return False
+        self.log.debug("Step 3: Get a filtering settings object's index.")
+        settings_index = droid.bleBuildAdvertiseSettings()
+        self.log.debug("Step 4: Get the filtering setting's own address type.")
+        adv_own_address_type = droid.bleGetAdvertiseSettingsOwnAddressType(
+            settings_index)
+        if exp_adv_own_address_type is not adv_own_address_type:
+            self.log.debug("exp value: {}, Actual value: {}".format(
+                exp_adv_own_address_type, adv_own_address_type))
+            return False
+        self.log.debug("Advertise Setting's own address type {}"
+                       "  value test Passed.".format(exp_adv_own_address_type))
+        return True
+
+    def verify_adv_set_address_type_start_adv(self, droid, own_address_type, uuid, service_data):
+        try:
+            droid.bleSetAdvertiseSettingsOwnAddressType(own_address_type)
+        except BleAdvertiseVerificationError as error:
+            self.log.debug(str(error))
+            return False
+
+        droid.bleAddAdvertiseDataServiceData(
+            uuid, service_data)
+        advcallback, adv_data, adv_settings = generate_ble_advertise_objects(
+            droid)
+        droid.bleStartBleAdvertising(advcallback, adv_data, adv_settings)
+
+        adv_own_address_type = droid.bleGetAdvertiseSettingsOwnAddressType(
+            adv_settings)
+        if own_address_type is not adv_own_address_type:
+            self.log.debug("exp value: {}, Actual value: {}".format(
+                own_address_type, adv_own_address_type))
+            return False
+
+        try:
+            event = self.android_devices[0].ed.pop_event(adv_succ.format(advcallback), 10)
+            self.log.info("Ble Advertise Success Event: {}".format(event))
+        except rpc_client.Sl4aApiError:
+            self.log.info("{} event was not found.".format(
+                adv_succ.format(advcallback)))
+            return False
+
+        return True
+
     def verify_adv_data_service_uuids(self, droid, exp_service_uuids):
         try:
             droid.bleSetAdvertiseDataSetServiceUuids(exp_service_uuids)
@@ -1227,6 +1423,20 @@
                 "failed successfullywith input as {}".format(exp_adv_tx_power))
             return True
 
+    def verify_invalid_adv_settings_own_address_type(self, droid,
+                                                   exp_adv_own_address_type):
+        try:
+            droid.bleSetAdvertiseSettingsOwnAddressType(exp_adv_own_address_type)
+            droid.bleBuildAdvertiseSettings()
+            self.log.debug("Set Advertise settings invalid own address type " +
+                           " with input as {}".format(exp_adv_own_address_type))
+            return False
+        except rpc_client.Sl4aApiError:
+            self.log.debug(
+                "Set Advertise settings invalid own address type "
+                "failed successfully with input as {}".format(exp_adv_own_address_type))
+            return True
+
     def verify_invalid_adv_data_service_uuids(self, droid, exp_service_uuids):
         try:
             droid.bleSetAdvertiseDataSetServiceUuids(exp_service_uuids)
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py
index 65f1c9a..962c1bf 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/VapeInteropTest.py
@@ -75,6 +75,7 @@
         self.dut.turn_location_off_and_scan_toggle_off()
         self.dut.disconnect()
         self.dut.reset_wifi()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py
index fa4e13a..04adfab 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11ACTest.py
@@ -159,6 +159,7 @@
         self.dut.turn_location_off_and_scan_toggle_off()
         self.dut.disconnect()
         self.dut.reset_wifi()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py
index 08b2cc6..ad0800f 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyCompliance11NTest.py
@@ -122,6 +122,7 @@
         self.dut.turn_location_off_and_scan_toggle_off()
         self.dut.disconnect()
         self.dut.reset_wifi()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py
index 3dac3f9..2d17f4b 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanPhyComplianceABGTest.py
@@ -123,6 +123,7 @@
         self.dut.turn_location_off_and_scan_toggle_off()
         self.dut.disconnect()
         self.dut.reset_wifi()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py
index 22bcfdc..a32c7c4 100644
--- a/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/compliance/WlanSecurityComplianceABGTest.py
@@ -201,6 +201,7 @@
         self.dut.turn_location_off_and_scan_toggle_off()
         self.dut.disconnect()
         self.dut.reset_wifi()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py
index f99e610..a2a763b 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/BeaconLossTest.py
@@ -70,7 +70,7 @@
         else:
             # Default is an android device, just like the other tests
             self.dut = create_wlan_device(self.android_devices[0])
-        self.ap = self.access_points[0]
+        self.access_point = self.access_points[0]
         self.num_of_iterations = int(
             self.user_params.get("beacon_loss_test_iterations",
                                  self.num_of_iterations))
@@ -80,23 +80,25 @@
         self.dut.disconnect()
         self.dut.reset_wifi()
         # ensure radio is on, in case the test failed while the radio was off
-        self.ap.iwconfig.ap_iwconfig(self.in_use_interface, "txpower on")
-        self.ap.stop_all_aps()
+        self.access_point.iwconfig.ap_iwconfig(self.in_use_interface,
+                                               "txpower on")
+        self.download_ap_logs()
+        self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
         super().on_fail(test_name, begin_time)
-        self.ap.stop_all_aps()
+        self.access_point.stop_all_aps()
 
     def beacon_loss(self, channel):
-        setup_ap(access_point=self.ap,
+        setup_ap(access_point=self.access_point,
                  profile_name='whirlwind',
                  channel=channel,
                  ssid=self.ssid)
         time.sleep(self.wait_ap_startup_s)
         if channel > 14:
-            self.in_use_interface = self.ap.wlan_5g
+            self.in_use_interface = self.access_point.wlan_5g
         else:
-            self.in_use_interface = self.ap.wlan_2g
+            self.in_use_interface = self.access_point.wlan_2g
 
         # TODO(b/144505723): [ACTS] update BeaconLossTest.py to handle client
         # roaming, saved networks, etc.
@@ -110,7 +112,8 @@
         for _ in range(0, self.num_of_iterations):
             # Turn off AP radio
             self.log.info("turning off radio")
-            self.ap.iwconfig.ap_iwconfig(self.in_use_interface, "txpower off")
+            self.access_point.iwconfig.ap_iwconfig(self.in_use_interface,
+                                                   "txpower off")
             time.sleep(self.wait_after_ap_txoff_s)
 
             # Did we disconnect from AP?
@@ -119,7 +122,8 @@
 
             # Turn on AP radio
             self.log.info("turning on radio")
-            self.ap.iwconfig.ap_iwconfig(self.in_use_interface, "txpower on")
+            self.access_point.iwconfig.ap_iwconfig(self.in_use_interface,
+                                                   "txpower on")
             time.sleep(self.wait_to_connect_after_ap_txon_s)
 
             # Tell the client to connect
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/ChannelSwitchTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/ChannelSwitchTest.py
index ccaa37a..be8e3ca 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/ChannelSwitchTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/ChannelSwitchTest.py
@@ -57,14 +57,15 @@
         else:
             # Default is an android device, just like the other tests
             self.dut = create_wlan_device(self.android_devices[0])
-        self.ap = self.access_points[0]
+        self.access_point = self.access_points[0]
         self._stop_all_soft_aps()
         self.in_use_interface = None
 
     def teardown_test(self) -> None:
         self.dut.disconnect()
         self.dut.reset_wifi()
-        self.ap.stop_all_aps()
+        self.download_ap_logs()
+        self.access_point.stop_all_aps()
 
     # TODO(fxbug.dev/85738): Change band type to an enum.
     def channel_switch(self,
@@ -98,15 +99,15 @@
 
         self.current_channel_num = starting_channel
         if band == hostapd_constants.BAND_5G:
-            self.in_use_interface = self.ap.wlan_5g
+            self.in_use_interface = self.access_point.wlan_5g
         elif band == hostapd_constants.BAND_2G:
-            self.in_use_interface = self.ap.wlan_2g
+            self.in_use_interface = self.access_point.wlan_2g
         asserts.assert_true(
             self._channels_valid_for_band([self.current_channel_num], band),
             'starting channel {} not a valid channel for band {}'.format(
                 self.current_channel_num, band))
 
-        setup_ap(access_point=self.ap,
+        setup_ap(access_point=self.access_point,
                  profile_name='whirlwind',
                  channel=self.current_channel_num,
                  ssid=self.ssid)
@@ -128,8 +129,9 @@
                 continue
             self.log.info('channel switch: {} -> {}'.format(
                 self.current_channel_num, channel_num))
-            self.ap.channel_switch(self.in_use_interface, channel_num)
-            channel_num_after_switch = self.ap.get_current_channel(
+            self.access_point.channel_switch(self.in_use_interface,
+                                             channel_num)
+            channel_num_after_switch = self.access_point.get_current_channel(
                 self.in_use_interface)
             asserts.assert_true(channel_num_after_switch == channel_num,
                                 'AP failed to channel switch')
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py
index 640792a..64fc144 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/ConnectionStressTest.py
@@ -46,7 +46,7 @@
         self.ssid = rand_ascii_str(10)
         self.fd = self.fuchsia_devices[0]
         self.dut = create_wlan_device(self.fd)
-        self.ap = self.access_points[0]
+        self.access_point = self.access_points[0]
         self.num_of_iterations = int(
             self.user_params.get("connection_stress_test_iterations",
                                  self.num_of_iterations))
@@ -54,11 +54,12 @@
 
     def teardown_test(self):
         self.dut.reset_wifi()
-        self.ap.stop_all_aps()
+        self.download_ap_logs()
+        self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
         super().on_fail(test_name, begin_time)
-        self.ap.stop_all_aps()
+        self.access_point.stop_all_aps()
 
     def start_ap(self, profile, channel, security=None):
         """Starts an Access Point
@@ -68,7 +69,7 @@
             channel: Channel to operate on
         """
         self.log.info('Profile: %s, Channel: %d' % (profile, channel))
-        setup_ap(access_point=self.ap,
+        setup_ap(access_point=self.access_point,
                  profile_name=profile,
                  channel=channel,
                  ssid=self.ssid,
@@ -131,7 +132,7 @@
             time.sleep(1)
 
         # Stop AP
-        self.ap.stop_all_aps()
+        self.access_point.stop_all_aps()
         if failed:
             raise signals.TestFailure(
                 'One or more association attempt failed.')
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py
index 5027ddf..5ec6290 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/DownloadStressTest.py
@@ -56,12 +56,12 @@
         super().setup_class()
         self.ssid = rand_ascii_str(10)
         self.dut = create_wlan_device(self.fuchsia_devices[0])
-        self.ap = self.access_points[0]
+        self.access_point = self.access_points[0]
         self.num_of_iterations = int(
             self.user_params.get("download_stress_test_iterations",
                                  self.num_of_iterations))
 
-        setup_ap(access_point=self.ap,
+        setup_ap(access_point=self.access_point,
                  profile_name='whirlwind',
                  channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
                  ssid=self.ssid)
@@ -71,7 +71,8 @@
         self.download_threads_result.clear()
         self.dut.disconnect()
         self.dut.reset_wifi()
-        self.ap.stop_all_aps()
+        self.download_ap_logs()
+        self.access_point.stop_all_aps()
 
     def test_download_small(self):
         self.log.info("Downloading small file")
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py
index e7facd0..5f8addc 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/PingStressTest.py
@@ -48,8 +48,8 @@
 
         self.ssid = rand_ascii_str(10)
         self.dut = create_wlan_device(self.fuchsia_devices[0])
-        self.ap = self.access_points[0]
-        setup_ap(access_point=self.ap,
+        self.access_point = self.access_points[0]
+        setup_ap(access_point=self.access_point,
                  profile_name='whirlwind',
                  channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
                  ssid=self.ssid,
@@ -59,7 +59,8 @@
     def teardown_class(self):
         self.dut.disconnect()
         self.dut.reset_wifi()
-        self.ap.stop_all_aps()
+        self.download_ap_logs()
+        self.access_point.stop_all_aps()
 
     def send_ping(self,
                   dest_ip,
@@ -97,7 +98,7 @@
         return self.send_ping('127.0.0.1')
 
     def test_ping_AP(self):
-        return self.send_ping(self.ap.ssh_settings.hostname)
+        return self.send_ping(self.access_point.ssh_settings.hostname)
 
     def test_ping_with_params(self):
         return self.send_ping(self.google_dns_1,
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py
index 2a05579..ec74992 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/SoftApTest.py
@@ -208,6 +208,7 @@
             ad.droid.goToSleepNow()
         self.stop_all_soft_aps()
         if self.access_point:
+            self.download_ap_logs()
             self.access_point.stop_all_aps()
         self.dut.disconnect()
 
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py
index 7ffb5ef..8d365a7 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/WlanRebootTest.py
@@ -168,8 +168,14 @@
         self.ssid = utils.rand_ascii_str(hostapd_constants.AP_SSID_LENGTH_2G)
 
     def teardown_test(self):
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
         if self.router_adv_daemon:
+            output_path = context.get_current_context().get_base_output_path()
+            full_output_path = os.path.join(output_path, "radvd_log.txt")
+            radvd_log_file = open(full_output_path, 'w')
+            radvd_log_file.write(self.router_adv_daemon.pull_logs())
+            radvd_log_file.close()
             self.router_adv_daemon.stop()
             self.router_adv_daemon = None
         self.dut.disconnect()
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py
index 3a2e7f2..6133f0b 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/WlanScanTest.py
@@ -45,6 +45,7 @@
     def setup_class(self):
         super().setup_class()
 
+        self.access_point = self.access_points[0]
         self.start_access_point = False
         for fd in self.fuchsia_devices:
             fd.configure_wlan(association_mechanism='drivers')
@@ -84,14 +85,14 @@
                         security_mode=self.wpa2_network_5g["security"],
                         password=self.wpa2_network_5g["password"])))
             self.ap_2g = hostapd_ap_preset.create_ap_preset(
-                iface_wlan_2g=self.access_points[0].wlan_2g,
-                iface_wlan_5g=self.access_points[0].wlan_5g,
+                iface_wlan_2g=self.access_point.wlan_2g,
+                iface_wlan_5g=self.access_point.wlan_5g,
                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_2G,
                 ssid=self.open_network_2g['SSID'],
                 bss_settings=bss_settings_2g)
             self.ap_5g = hostapd_ap_preset.create_ap_preset(
-                iface_wlan_2g=self.access_points[0].wlan_2g,
-                iface_wlan_5g=self.access_points[0].wlan_5g,
+                iface_wlan_2g=self.access_point.wlan_2g,
+                iface_wlan_5g=self.access_point.wlan_5g,
                 channel=hostapd_constants.AP_DEFAULT_CHANNEL_5G,
                 ssid=self.open_network_5g['SSID'],
                 bss_settings=bss_settings_5g)
@@ -133,10 +134,10 @@
         # previously saved ssid on the device.
         if self.start_access_point_2g:
             self.start_access_point = True
-            self.access_points[0].start_ap(hostapd_config=self.ap_2g)
+            self.access_point.start_ap(hostapd_config=self.ap_2g)
         if self.start_access_point_5g:
             self.start_access_point = True
-            self.access_points[0].start_ap(hostapd_config=self.ap_5g)
+            self.access_point.start_ap(hostapd_config=self.ap_5g)
 
     def setup_test(self):
         for fd in self.fuchsia_devices:
@@ -149,7 +150,8 @@
 
     def teardown_class(self):
         if self.start_access_point:
-            self.access_points[0].stop_all_aps()
+            self.download_ap_logs()
+            self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
         for fd in self.fuchsia_devices:
diff --git a/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py b/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py
index 0512b87..2debf65 100644
--- a/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/functional/WlanTargetSecurityTest.py
@@ -49,8 +49,9 @@
         self.dut.disconnect()
         self.access_point.stop_all_aps()
 
-    def setup_test(self):
+    def teardown_test(self):
         self.dut.disconnect()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py b/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py
index 842fa48..950015d 100644
--- a/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/misc/WlanMiscScenarioTest.py
@@ -50,8 +50,9 @@
         self.dut.disconnect()
         self.access_point.stop_all_aps()
 
-    def setup_test(self):
+    def teardown_test(self):
         self.dut.disconnect()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def on_fail(self, test_name, begin_time):
diff --git a/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py b/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py
index b687022..8ea7891 100644
--- a/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/performance/ChannelSweepTest.py
@@ -175,6 +175,7 @@
             ad.droid.goToSleepNow()
         self.dut.turn_location_off_and_scan_toggle_off()
         self.dut.disconnect()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def set_dut_country_code(self, country_code):
diff --git a/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py b/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py
index e640238..545bbc5 100644
--- a/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/performance/WlanRvrTest.py
@@ -13,6 +13,7 @@
 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
+import os
 import time
 
 from acts import asserts
@@ -226,6 +227,11 @@
         """
 
         if self.router_adv_daemon:
+            output_path = context.get_current_context().get_base_output_path()
+            full_output_path = os.path.join(output_path, "radvd_log.txt")
+            radvd_log_file = open(full_output_path, 'w')
+            radvd_log_file.write(self.router_adv_daemon.pull_logs())
+            radvd_log_file.close()
             self.router_adv_daemon.stop()
         if hasattr(self, "android_devices"):
             for ad in self.android_devices:
@@ -236,6 +242,7 @@
         self.dut.turn_location_off_and_scan_toggle_off()
         self.dut.disconnect()
         self.dut.reset_wifi()
+        self.download_ap_logs()
         self.access_point.stop_all_aps()
 
     def _wait_for_ipv4_addrs(self):
diff --git a/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py b/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py
index 3a3cd13..adbb5f6 100644
--- a/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py
+++ b/acts_tests/tests/google/fuchsia/wlan/performance/WlanWmmTest.py
@@ -190,6 +190,7 @@
                 tc.wlan_device.disconnect()
                 tc.wlan_device.reset_wifi()
             if tc.access_point:
+                self.download_ap_logs()
                 tc.access_point.stop_all_aps()
 
     def teardown_class(self):
diff --git a/acts_tests/tests/google/net/ApfCountersTest.py b/acts_tests/tests/google/net/ApfCountersTest.py
index 4a23203..4d602b2 100755
--- a/acts_tests/tests/google/net/ApfCountersTest.py
+++ b/acts_tests/tests/google/net/ApfCountersTest.py
@@ -35,8 +35,6 @@
 WifiEnums = wutils.WifiEnums
 
 RA_SCRIPT = 'sendra.py'
-SCAPY = 'scapy-2.2.0.tar.gz'
-SCAPY_INSTALL_COMMAND = 'sudo python setup.py install'
 PROC_NET_SNMP6 = '/proc/net/snmp6'
 LIFETIME_FRACTION = 6
 LIFETIME = 180
@@ -52,10 +50,11 @@
                       "test_IPv6_RA_with_RTT", )
 
     def setup_class(self):
+        super().setup_class()
         self.dut = self.android_devices[0]
         wutils.wifi_test_device_init(self.dut)
-        req_params = []
-        opt_param = ["reference_networks", ]
+        req_params = ["scapy"]
+        opt_param = ["reference_networks"]
 
         self.unpack_userparams(
             req_param_names=req_params, opt_param_names=opt_param)
@@ -74,8 +73,7 @@
         # install scapy
         current_dir = os.path.dirname(os.path.realpath(__file__))
         send_ra = os.path.join(current_dir, RA_SCRIPT)
-        send_scapy = os.path.join(current_dir, SCAPY)
-        self.access_points[0].install_scapy(send_scapy, send_ra)
+        self.access_points[0].install_scapy(self.scapy[0], send_ra)
         self.tcpdump_pid = None
 
     def setup_test(self):
@@ -95,6 +93,7 @@
             del self.user_params["reference_networks"]
         self.access_points[0].cleanup_scapy()
         wutils.reset_wifi(self.dut)
+        self.dut.adb.shell("settings put global stay_on_while_plugged_in 7")
 
     """ Helper methods """
 
@@ -164,6 +163,8 @@
         ra_count_latest = self._get_icmp6intype134()
         asserts.assert_true(ra_count_latest == ra_count + 1,
                             "Device dropped the first RA in sequence")
+        self.dut.adb.shell("settings put global stay_on_while_plugged_in 0")
+        self.dut.droid.goToSleepNow()
 
         # Generate and send 'x' number of duplicate RAs, for 1/6th of the the
         # lifetime of the original RA. Test assumes that the original RA has a
diff --git a/acts_tests/tests/google/net/DataCostTest.py b/acts_tests/tests/google/net/DataCostTest.py
index 6174009..c8089d9 100644
--- a/acts_tests/tests/google/net/DataCostTest.py
+++ b/acts_tests/tests/google/net/DataCostTest.py
@@ -1,5 +1,5 @@
 #
-#   Copyright 2018 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
 from acts.controllers import adb
 from acts.test_decorators import test_tracker_info
 from acts_contrib.test_utils.net import net_test_utils as nutils
-from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existance
+from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existence
 from acts_contrib.test_utils.tel.tel_test_utils import _generate_file_directory_and_file_name
 from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
 from acts_contrib.test_utils.net.connectivity_const import MULTIPATH_PREFERENCE_NONE as NONE
@@ -252,7 +252,7 @@
             self.download_file, DOWNLOAD_PATH)
         file_path = os.path.join(file_folder, file_name)
         self.log.info("File path: %s" % file_path)
-        if _check_file_existance(ad, file_path):
+        if _check_file_existence(ad, file_path):
             self.log.info("File exists. Removing file %s" % file_name)
             ad.adb.shell("rm -rf %s%s" % (DOWNLOAD_PATH, file_name))
 
diff --git a/acts_tests/tests/google/net/DataUsageTest.py b/acts_tests/tests/google/net/DataUsageTest.py
index 1582886..e6b3fca 100644
--- a/acts_tests/tests/google/net/DataUsageTest.py
+++ b/acts_tests/tests/google/net/DataUsageTest.py
@@ -1,5 +1,5 @@
 #
-#   Copyright 2018 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
 from acts_contrib.test_utils.net.net_test_utils import stop_tcpdump
 from acts_contrib.test_utils.tel import tel_test_utils as ttutils
 from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import http_file_download_by_chrome
+from acts_contrib.test_utils.tel.tel_data_utils import http_file_download_by_chrome
 from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
 import queue
 from queue import Empty
@@ -143,7 +143,7 @@
         download_status = False
         end_time = time.time() + TIMEOUT
         while time.time() < end_time:
-            download_status = ttutils._check_file_existance(
+            download_status = ttutils._check_file_existence(
                 ad, self.file_path, self.file_size * BYTE_TO_MB)
             if download_status:
                 self.log.info("Delete file: %s", self.file_path)
diff --git a/acts_tests/tests/google/net/DhcpTest.py b/acts_tests/tests/google/net/DhcpTest.py
index a06b8fe..08aa983 100644
--- a/acts_tests/tests/google/net/DhcpTest.py
+++ b/acts_tests/tests/google/net/DhcpTest.py
@@ -50,11 +50,12 @@
                             "OpenWrt Wifi interface is not ready.")
 
     def teardown_class(self):
-        """Reset wifi to make sure VPN tears down cleanly."""
+        """Reset wifi and stop tcpdump cleanly."""
         wutils.reset_wifi(self.dut)
+        self.openwrt.network_setting.clear_tcpdump()
 
     def teardown_test(self):
-        """Reset wifi to make sure VPN tears down cleanly."""
+        """Reset wifi to make sure DUT tears down cleanly."""
         wutils.reset_wifi(self.dut)
 
     def _verify_ping(self, option="", dest=PING_ADDR):
diff --git a/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py b/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py
index 6196f61..22fa780 100644
--- a/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py
+++ b/acts_tests/tests/google/net/IKEv2VpnOverWifiTest.py
@@ -13,39 +13,69 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
+import time
 
-from acts import base_test
+from acts.controllers.openwrt_ap import MOBLY_CONTROLLER_CONFIG_NAME as OPENWRT
 from acts.test_decorators import test_tracker_info
 from acts_contrib.test_utils.net import connectivity_const
 from acts_contrib.test_utils.net import net_test_utils as nutils
 from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
+
 
 VPN_CONST = connectivity_const.VpnProfile
 VPN_TYPE = connectivity_const.VpnProfileType
 VPN_PARAMS = connectivity_const.VpnReqParams
 
 
-class IKEv2VpnOverWifiTest(base_test.BaseTestClass):
+class IKEv2VpnOverWifiTest(WifiBaseTest):
   """IKEv2 VPN tests."""
 
   def setup_class(self):
+    """Setup wi-fi connection and unpack params."""
     self.dut = self.android_devices[0]
-
-    required_params = dir(VPN_PARAMS)
-    required_params = [x for x in required_params if not x.startswith("__")]
-    self.unpack_userparams(req_param_names=required_params)
-    self.vpn_params = {
-        "vpn_username": self.vpn_username,
-        "vpn_password": self.vpn_password,
-        "psk_secret": self.psk_secret,
-        "client_pkcs_file_name": self.client_pkcs_file_name,
-        "cert_path_vpnserver": self.cert_path_vpnserver,
-        "cert_password": self.cert_password,
-        "vpn_identity": self.vpn_identity,
-    }
+    req_params = dir(VPN_PARAMS)
+    req_params = [
+      x for x in req_params if not x.startswith("__")
+    ]
+    opt_params = ["wifi_network", "vpn_cert_country",
+            "vpn_cert_org", "configure_OpenWrt"]
+    self.unpack_userparams(req_param_names=req_params,
+                 opt_param_names=opt_params)
 
     wutils.wifi_test_device_init(self.dut)
-    wutils.connect_to_wifi_network(self.dut, self.wifi_network)
+    wutils.wifi_toggle_state(self.dut, True)
+    if OPENWRT in self.user_params:
+      self.openwrt = self.access_points[0]
+      if hasattr(self, "configure_OpenWrt") and self.configure_OpenWrt == "skip":
+        self.dut.log.info("Skip configure Wifi interface due to config setup.")
+      else:
+        self.configure_openwrt_ap_and_start(wpa_network=True)
+        self.wifi_network = self.openwrt.get_wifi_network()
+      # Wait for OpenWrt statement update
+      time.sleep(10)
+      self.openwrt.network_setting.setup_vpn_l2tp_server(
+        self.vpn_server_hostname,
+        self.vpn_verify_addresses["IKEV2_IPSEC_RSA"][0],
+        self.vpn_username,
+        self.vpn_password,
+        self.vpn_identity,
+        "ikev2-server",
+        self.vpn_cert_country,
+        self.vpn_cert_org
+      )
+    wutils.start_wifi_connection_scan_and_ensure_network_found(
+      self.dut, self.wifi_network["SSID"])
+    wutils.wifi_connect(self.dut, self.wifi_network)
+    time.sleep(3)
+
+    self.vpn_params = {"vpn_username": self.vpn_username,
+               "vpn_password": self.vpn_password,
+               "psk_secret": self.psk_secret,
+               "client_pkcs_file_name": self.client_pkcs_file_name,
+               "cert_path_vpnserver": self.cert_path_vpnserver,
+               "cert_password": self.cert_password,
+               "vpn_identity": self.vpn_identity}
 
   def teardown_class(self):
     wutils.reset_wifi(self.dut)
@@ -54,6 +84,7 @@
     self.dut.take_bug_report(test_name, begin_time)
 
   ### Helper methods ###
+
   def _test_ikev2_vpn(self, vpn, hostname=None):
     """Verify IKEv2 VPN connection.
 
@@ -86,7 +117,8 @@
 
   @test_tracker_info(uuid="bdd8a967-8dac-4e48-87b7-2ce9f7d32158")
   def test_ikev2_psk_vpn_wifi_with_hostname(self):
-    self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_PSK, self.vpn_server_hostname)
+    self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_PSK,
+                         self.vpn_server_hostname)
 
   @test_tracker_info(uuid="19692520-c123-4b42-8549-08dda9c4873e")
   def test_ikev2_mschapv2_vpn_wifi_with_hostname(self):
@@ -95,4 +127,5 @@
 
   @test_tracker_info(uuid="bdaaf6e3-6671-4533-baba-2951009c7d69")
   def test_ikev2_rsa_vpn_wifi_with_hostname(self):
-    self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_RSA, self.vpn_server_hostname)
+    self._test_ikev2_vpn(VPN_TYPE.IKEV2_IPSEC_RSA,
+                         self.vpn_server_hostname)
diff --git a/acts_tests/tests/google/net/UsbTetheringTest.py b/acts_tests/tests/google/net/UsbTetheringTest.py
index 26a7f5c..1f1d4cf 100644
--- a/acts_tests/tests/google/net/UsbTetheringTest.py
+++ b/acts_tests/tests/google/net/UsbTetheringTest.py
@@ -38,9 +38,12 @@
     self.unpack_userparams(req_params)
     # Enable USB tethering and get the USB network interface
     iflist_before = nutils.get_if_list()
+    serial = self.dut.device_info['serial']
     nutils.start_usb_tethering(self.dut)
+    self.dut.recreate_services(serial)
     self.iface = nutils.wait_for_new_iface(iflist_before)
-    self.check_upstream_ready()
+    if not self.check_upstream_ready():
+      raise asserts.fail("Upstream interface is not active.")
 
   def teardown_class(self):
     nutils.stop_usb_tethering(self.dut)
@@ -185,8 +188,9 @@
     for i in range(0, retry):
       output = self.dut.adb.shell(DUMSYS_CMD)
       for line in output.split("\n"):
-        if UPSTREAM_WANTED_STRING in line and "true" in line:
+        if UPSTREAM_WANTED_STRING in line:
           if "true" in line:
             self.log.info("Upstream interface is active")
           elif i == retry:
-            raise asserts.fail("Upstream interface is not active.")
+            return False
+    return True
diff --git a/acts_tests/tests/google/net/scapy-2.2.0.tar.gz b/acts_tests/tests/google/net/scapy-2.2.0.tar.gz
deleted file mode 100644
index 47ac039..0000000
--- a/acts_tests/tests/google/net/scapy-2.2.0.tar.gz
+++ /dev/null
Binary files differ
diff --git a/acts_tests/tests/google/nr/cbr/CellBroadcastInitializationTest.py b/acts_tests/tests/google/nr/cbr/CellBroadcastInitializationTest.py
new file mode 100644
index 0000000..ed3ea6a
--- /dev/null
+++ b/acts_tests/tests/google/nr/cbr/CellBroadcastInitializationTest.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2022 - Google
+#
+#   Licensed under the Apache License, Version 2.0 (the "License");
+#   you may not use this file except in compliance with the License.
+#   You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+"""
+    Test Script for CellBroadcast initialization Test
+"""
+
+import time
+import os
+
+
+from acts.logger import epoch_to_log_line_timestamp
+from acts.keys import Config
+from acts.base_test import BaseTestClass
+from acts.test_decorators import test_tracker_info
+from acts.utils import load_config
+from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
+
+
+class CellBroadcastInitializationTest(BaseTestClass):
+    def setup_test(self):
+        super().setup_class()
+        self.number_of_devices = 1
+        self.cbr_init_iteration = self.user_params.get("cbr_init_iteration", 50)
+
+    def teardown_class(self):
+        super().teardown_class(self)
+
+    def _get_current_time_in_secs(self, ad):
+        try:
+            c_time = get_device_epoch_time(ad)
+            c_time = epoch_to_log_line_timestamp(c_time).split()[1].split('.')[0]
+            return self._convert_formatted_time_to_secs(c_time)
+        except Exception as e:
+            ad.log.error(e)
+
+    def _convert_formatted_time_to_secs(self, formatted_time):
+        try:
+            time_list = formatted_time.split(":")
+            return int(time_list[0]) * 3600 + int(time_list[1]) * 60 + int(time_list[2])
+        except Exception as e:
+            self.log.error(e)
+
+    def _verify_channel_config_4400(self, ad):
+        #TODO add all channel checks as constants in tel_defines
+        channel_4400__log = 'SmsBroadcastConfigInfo: Id \\[4400'
+        return ad.search_logcat(channel_4400__log)
+
+    @test_tracker_info(uuid="30f30fa4-f57a-40bd-a37a-141a8efb5a04")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_reboot_stress(self):
+        """ Verifies channel 4400 is set correctly after device boot up
+        only applicable to US carriers
+        after every boot up, search logcat to verify channel 4400 is set
+        default iterations is 50
+        config param : cbr_init_iteration
+
+        """
+        ad = self.android_devices[0]
+
+        current_cbr_version = ad.get_apk_version('com.google.android.cellbroadcast')
+        ad.log.info("Current cbr apk version is %s.", current_cbr_version)
+
+        failure_count = 0
+        begin_time = self._get_current_time_in_secs(ad)
+        for iteration in range(1, self.cbr_init_iteration + 1):
+            msg = "Stress CBR reboot initialization test Iteration: <%s>/<%s>" % (iteration, self.cbr_init_iteration)
+            self.log.info(msg)
+            ad.reboot()
+            ad.wait_for_boot_completion()
+            self.log.info("Rebooted")
+            #TODO make sleep time a constant in tel_defines WAIT_TIME_CBR_INIT_AFTER_REBOOT
+            time.sleep(40)
+            if not self._verify_channel_config_4400(ad):
+                failure_count += 1
+                self.log.error('Iteration failed at %d ' % iteration)
+        end_time = self._get_current_time_in_secs(ad)
+        self.log.debug('Test completed from %s to %s' % (begin_time, end_time))
+        result = True
+        if failure_count > 0:
+            result = False
+            self.log.error('CBR reboot init stress test: <%s> failures in %s iterations',
+                           failure_count, self.cbr_init_iteration)
+        return result
+
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSVoiceTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSVoiceTest.py
index 2e42a12..3544b8d 100644
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSVoiceTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDSDSVoiceTest.py
@@ -19,6 +19,7 @@
 from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
+from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_long_call_streaming_test
 from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_voice_call_test
 from acts_contrib.test_utils.tel.tel_dsds_utils import enable_slot_after_voice_call_test
 from acts_contrib.test_utils.tel.tel_dsds_utils import enable_slot_after_data_call_test
@@ -2149,4 +2150,708 @@
             wifi_network_ssid=self.wifi_network_ssid,
             wifi_network_pass=self.wifi_network_pass,
             turn_off_wifi_in_the_end=True,
-            turn_off_airplane_mode_in_the_end=True)
\ No newline at end of file
+            turn_off_airplane_mode_in_the_end=True)
+
+    @test_tracker_info(uuid="f07a4924-0752-41fd-8e52-e75c3c78c538")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mo_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="cac09fa6-5db1-4523-910a-7fe9918a04ac")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mt_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MT VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="a0039ac0-9d3d-4acf-801b-4b0d01971153")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mo_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="9cf03491-df27-4eda-9e3d-7782a44c0674")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mt_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MT VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="6c8c7e67-3bec-49b4-8164-963e488df14f")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mo_5g_nsa_volte_psim_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="9a2bc9a2-18a2-471f-9b21-fd0aea1b126b")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mt_5g_nsa_volte_psim_volte_dds_0(self):
+        """ A MT VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="c88a0ed6-f8b6-4033-93db-b160c29d4b9e")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mo_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="b4aa294d-679d-4a0e-8cc9-9261bfe8b392")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mt_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="2e20f05f-9434-410f-a40a-a01c0303d1a0")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mo_5g_nsa_volte_esim_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="3f89b354-0cdc-4522-8a67-76773219e5af")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mt_5g_nsa_volte_esim_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="f18c61c5-3c3b-4645-90eb-e7bdef9b7c74")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mo_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="8324ffe2-1332-47fc-af92-a3ed7be9b629")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mt_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="e6760078-2a5e-4182-8ba1-57788fc607f1")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mo_volte_psim_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="c736e4f0-8dbc-480a-8da6-68453cc13d07")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_esim_mt_volte_psim_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="19dc55b5-b989-481d-a980-fcd0ff56abc2")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mo_volte_esim_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="494e9c90-6c56-4fa1-9fac-ac8f2b1c0dba")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_psim_mt_volte_esim_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=False)
+
+    @test_tracker_info(uuid="d253553d-7dc9-4e38-8e20-0839326c20aa")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mo_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="80a201c5-0bfe-4d7f-b08b-52b7c53b6468")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mt_5g_nsa_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MT VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="8938575b-2544-4075-9cf9-3d938ad4d9cb")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mo_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="200c7cce-aba2-40f8-a274-9b05177d00e0")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mt_volte_psim_5g_nsa_volte_dds_0(self):
+        """ A MT VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="26bb9415-44f4-43df-b2e6-abbdfacf33c2")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mo_5g_nsa_volte_psim_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="8a8dc1ca-6a85-4dc8-9e34-e17abe61f7b8")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mt_5g_nsa_volte_psim_volte_dds_0(self):
+        """ A MT VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 0)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="903a2813-6b27-4020-aaf2-b5ab8b29fa13")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mo_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="33d8ba2c-fa45-4ec0-aef5-b191b6ddd9a6")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mt_5g_nsa_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="6db23c84-13d9-47fa-b8f1-45c56e2d6428")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mo_5g_nsa_volte_esim_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="3a77b38f-c327-4c43-addf-48832bca7148")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mt_5g_nsa_volte_esim_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM during streaming, where
+            - pSIM 5G NSA VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["5g_volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="2898eb67-3dfe-4322-8c69-817e0a95dfda")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mo_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="780e8187-2068-4eca-a9de-e5f2f3491403")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mt_volte_esim_5g_nsa_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 5G NSA VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "5g_volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="9b84bd00-fae3-45c0-9e44-dd57d1719bb9")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mo_volte_psim_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="813c6059-bcef-42d3-b70b-9b0ba67ffc20")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_esim_mt_volte_psim_volte_dds_0(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=1,
+            dds_slot=0,
+            direction="mt",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="970b1d31-195b-4599-80bc-bc46ede43a90")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mo_volte_esim_volte_dds_1(self):
+        """ A MO VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mo",
+            duration=360,
+            streaming=True)
+
+    @test_tracker_info(uuid="62843f60-5d1c-44ed-9936-e10d2691e787")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_msim_long_voice_streaming_psim_mt_volte_esim_volte_dds_1(self):
+        """ A MT VoLTE long call at eSIM during streaming, where
+            - pSIM 4G VoLTE
+            - eSIM 4G VoLTE
+            - DDS at pSIM (slot 1)
+
+            After call end will check the eSIM if is attach to the network
+            with assigned RAT successfully and data works fine.
+        """
+        return dsds_long_call_streaming_test(
+            self.log,
+            self.tel_logger,
+            self.android_devices,
+            test_rat=["volte", "volte"],
+            test_slot=0,
+            dds_slot=1,
+            direction="mt",
+            duration=360,
+            streaming=True)
\ No newline at end of file
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py
index e75af47..1a6be2a 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gDataTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2020 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -27,6 +27,9 @@
 from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackCapabilitiesChanged
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
 from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
 from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
 from acts_contrib.test_utils.tel.tel_data_utils import test_data_connectivity_multi_bearer
 from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
@@ -38,9 +41,6 @@
 from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
 from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
 from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
 from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
 from acts_contrib.test_utils.tel.tel_test_utils import iperf_test_by_adb
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py
index a2a5b3a..e7bcb5a 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gMmsTest.py
@@ -25,8 +25,13 @@
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
 from acts_contrib.test_utils.tel.tel_message_utils import message_test
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_task
 from acts_contrib.test_utils.tel.tel_test_utils import install_message_apk
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts.libs.utils.multithread import run_multithread_func
 
 
 class Nsa5gMmsTest(TelephonyBaseTest):
@@ -761,4 +766,105 @@
             wifi_ssid=self.wifi_network_ssid,
             wifi_pwd=self.wifi_network_pass)
 
+    @test_tracker_info(uuid="536c8e25-2d72-46a6-89e1-03f70c5a28a3")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_5g_nsa_mms_multiple_pdns_mo(self):
+        """Test 5G NSA for multiple pdns
+
+        Steps:
+            (1) UE supports EN-DC option 3.
+            (2) SIM with 5G service.
+            (3) UE is provisioned for 5G service and powered off.
+            (4) NR cell (Cell 2) that is within the coverage of LTE cell (Cell 1).
+            (5) UE is in near cell coverage for LTE (Cell 1) and NR (Cell 2).
+            (6) Power on the UE.
+            (7) Initiate data transfer while UE is in idle mode.
+            (8) During data transferring, send a MO MMS.
+            (9) End the data transfer
+
+        Returns:
+            True if pass; False if fail.
+        """
+        cell_1 = self.android_devices[0]
+        cell_2 = self.android_devices[1]
+        if not phone_setup_volte(self.log, cell_1):
+            cell_1.log.error("Failed to setup on VoLTE")
+            return False
+
+        if not verify_internet_connection(self.log, cell_1):
+            return False
+        if not provision_device_for_5g(self.log, cell_2, nr_type='nsa'):
+            cell_2.log.error("Failed to setup on 5G NSA")
+            return False
+        if not verify_internet_connection(self.log, cell_2):
+            return False
+        if not active_file_download_task(self.log, cell_2):
+            return False
+        download_task = active_file_download_task(self.log, cell_2, "10MB")
+        message_task = (message_test, (self.log, cell_2, cell_1,
+                                        '5g', 'volte', 'mms'))
+        results = run_multithread_func(self.log, [download_task, message_task])
+
+        if ((results[0]) & (results[1])):
+            self.log.info("PASS - MO MMS test validated over active data transfer")
+        elif ((results[0] == False) & (results[1] == True)):
+            self.log.error("FAIL - Data Transfer failed")
+        elif ((results[0] == True) & (results[1] == False)):
+            self.log.error("FAIL - Sending MMS failed")
+        else:
+            self.log.error("FAILED - MO MMS test over active data transfer")
+
+        return results
+
+    @test_tracker_info(uuid="10212ab7-a03f-4e11-889e-236b8d1d8afc")
+    @TelephonyBaseTest.tel_test_wrap
+    def test_5g_nsa_mms_multiple_pdns_mt(self):
+        """Test 5G NSA for multiple pdns
+
+        Steps:
+            (1) UE supports EN-DC option 3.
+            (2) SIM with 5G service.
+            (3) UE is provisioned for 5G service and powered off.
+            (4) NR cell (Cell 2) that is within the coverage of LTE cell (Cell 1).
+            (5) UE is in near cell coverage for LTE (Cell 1) and NR (Cell 2).
+            (6) Power on the UE.
+            (7) Initiate data transfer while UE is in idle mode.
+            (8) During data transferring, send a MT MMS.
+            (9) End the data transfer.
+
+        Returns:
+            True if pass; False if fail.
+        """
+        cell_1 = self.android_devices[0]
+        cell_2 = self.android_devices[1]
+
+        if not phone_setup_volte(self.log, cell_1):
+            cell_1.log.error("Failed to setup on VoLTE")
+            return False
+        if not verify_internet_connection(self.log, cell_1):
+            return False
+        if not provision_device_for_5g(self.log, cell_2, nr_type='nsa'):
+            cell_2.log.error("Failed to setup on 5G NSA")
+            return False
+        if not verify_internet_connection(self.log, cell_2):
+            return False
+        if not active_file_download_task(self.log, cell_2):
+            return False
+
+        download_task = active_file_download_task(self.log, cell_2, "10MB")
+        message_task = (message_test, (self.log, cell_1, cell_2,
+                                        'volte', '5g', 'mms'))
+        results = run_multithread_func(self.log, [download_task, message_task])
+
+        if ((results[0]) & (results[1])):
+            self.log.info("PASS - MT MMS test validated over active data transfer")
+        elif ((results[0] == False) & (results[1] == True)):
+            self.log.error("FAIL - Data Transfer failed")
+        elif ((results[0] == True) & (results[1] == False)):
+            self.log.error("FAIL - Sending MMS failed")
+        else:
+            self.log.error("FAILED - MT MMS test over active data transfer")
+
+        return results
+
     """ Tests End """
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py
index 3381d9f..f1df4f4 100755
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gSmsTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -24,10 +24,10 @@
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
 from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_task
 from acts_contrib.test_utils.tel.tel_message_utils import message_test
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_task
 from acts_contrib.test_utils.tel.tel_test_utils import install_message_apk
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
diff --git a/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py b/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py
index 5140dec..ebeca77 100644
--- a/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py
+++ b/acts_tests/tests/google/nr/nsa5g/Nsa5gVoiceTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2020 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -35,6 +35,9 @@
 from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
 from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
 from acts_contrib.test_utils.tel.tel_data_utils import call_epdg_to_epdg_wfc
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
 from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_data_transfer
 from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_youtube_video
 from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
@@ -50,10 +53,7 @@
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
 from acts_contrib.test_utils.tel.tel_test_utils import install_dialer_apk
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
 from acts_contrib.test_utils.tel.tel_voice_utils import _test_call_long_duration
 from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_2g
 from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_3g
diff --git a/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwDataTest.py b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwDataTest.py
index adfe5c3..19618f7 100755
--- a/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwDataTest.py
+++ b/acts_tests/tests/google/nr/nsa5gmmw/Nsa5gMmwDataTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -26,10 +26,19 @@
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA
 from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackCapabilitiesChanged
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import set_preferred_mode_for_5g
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
+from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
+from acts_contrib.test_utils.tel.tel_data_utils import verify_for_network_callback
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
 from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
 from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
 from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
 from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
@@ -37,15 +46,6 @@
 from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
-from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
-from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
-from acts_contrib.test_utils.tel.tel_data_utils import verify_for_network_callback
-from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
-from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import set_preferred_mode_for_5g
 from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
 from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
 from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
diff --git a/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py b/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py
index 339969a..05d6535 100755
--- a/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py
+++ b/acts_tests/tests/google/nr/sa5g/Sa5gDataTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -28,10 +28,14 @@
 from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
 from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
 from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
 from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
+from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
+from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
 from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
 from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
 from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
@@ -39,10 +43,6 @@
 from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
-from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
-from acts_contrib.test_utils.tel.tel_data_utils import test_wifi_connect_disconnect
-from acts_contrib.test_utils.tel.tel_data_utils import wifi_cell_switching
 from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
 from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
 
diff --git a/acts_tests/tests/google/tel/lab/TelLabDataTest.py b/acts_tests/tests/google/tel/lab/TelLabDataTest.py
index 33c393d..7481799 100644
--- a/acts_tests/tests/google/tel/lab/TelLabDataTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabDataTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2016 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -43,15 +43,15 @@
 from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_UMTS
 from acts_contrib.test_utils.tel.tel_defines import POWER_LEVEL_OUT_OF_SERVICE
 from acts_contrib.test_utils.tel.tel_defines import POWER_LEVEL_FULL_SERVICE
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
 from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_rat
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
 from acts_contrib.test_utils.tel.tel_test_utils import get_host_ip_address
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import iperf_test_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
 from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
 from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
 from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTAirplaneModeTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTAirplaneModeTest.py
index bbe9b14..b385d80 100644
--- a/acts_tests/tests/google/tel/lab/TelLabGFTAirplaneModeTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTAirplaneModeTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -35,11 +35,11 @@
 from acts_contrib.test_utils.tel.tel_defines import GEN_4G
 from acts_contrib.test_utils.tel.tel_defines import GEN_5G
 from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
 from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
 
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTDSDSInOutServiceTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSInOutServiceTest.py
index 9a56a42..8f254fb 100644
--- a/acts_tests/tests/google/tel/lab/TelLabGFTDSDSInOutServiceTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSInOutServiceTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
 from acts_contrib.test_utils.tel.GFTInOutBaseTest import GFTInOutBaseTest
 from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
 from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ims_registered
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
 from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
 
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTDSDS.py b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSTest.py
similarity index 98%
rename from acts_tests/tests/google/tel/lab/TelLabGFTDSDS.py
rename to acts_tests/tests/google/tel/lab/TelLabGFTDSDSTest.py
index 67833b2..4453d15 100644
--- a/acts_tests/tests/google/tel/lab/TelLabGFTDSDS.py
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTDSDSTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -25,10 +25,10 @@
 from acts_contrib.test_utils.tel.gft_inout_defines import NO_SERVICE_POWER_LEVEL
 from acts_contrib.test_utils.tel.gft_inout_defines import IN_SERVICE_POWER_LEVEL
 from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
 from acts_contrib.test_utils.tel.tel_dsds_utils import dsds_voice_call_test
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
diff --git a/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py b/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py
index ba314d0..9694749 100644
--- a/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py
+++ b/acts_tests/tests/google/tel/lab/TelLabGFTInOutServiceTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
 from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
 from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
 from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
 from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
 
diff --git a/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py b/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py
index 24a784c..78bd320 100644
--- a/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveDSDSVoiceTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2019 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
 from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_TERMINATED
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
 from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
 from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
@@ -55,7 +56,6 @@
 from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
 from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
 from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
 from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
 from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
diff --git a/acts_tests/tests/google/tel/live/TelLiveDataTest.py b/acts_tests/tests/google/tel/live/TelLiveDataTest.py
index 1f3e3c0..aae9fc0 100755
--- a/acts_tests/tests/google/tel/live/TelLiveDataTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveDataTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2016 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -49,11 +49,18 @@
 from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_SSID_LIST
 from acts_contrib.test_utils.tel.tel_defines import TETHERING_SPECIAL_PASSWORD_LIST
 from acts_contrib.test_utils.tel.tel_bt_utils import verify_bluetooth_tethering_connection
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_data_utils import airplane_mode_test
 from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
 from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
 from acts_contrib.test_utils.tel.tel_data_utils import change_data_sim_and_verify_data
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_detection
+from acts_contrib.test_utils.tel.tel_data_utils import check_data_stall_recovery
+from acts_contrib.test_utils.tel.tel_data_utils import check_network_validation_fail
 from acts_contrib.test_utils.tel.tel_data_utils import data_connectivity_single_bearer
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
 from acts_contrib.test_utils.tel.tel_data_utils import tethering_check_internet_connection
 from acts_contrib.test_utils.tel.tel_data_utils import test_data_connectivity_multi_bearer
 from acts_contrib.test_utils.tel.tel_data_utils import test_setup_tethering
@@ -85,19 +92,12 @@
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
 from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_detection
-from acts_contrib.test_utils.tel.tel_test_utils import check_network_validation_fail
 from acts_contrib.test_utils.tel.tel_test_utils import break_internet_except_sl4a_port
 from acts_contrib.test_utils.tel.tel_test_utils import resume_internet_with_sl4a_port
 from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
-from acts_contrib.test_utils.tel.tel_test_utils import check_data_stall_recovery
 from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_success_using_sl4a
 from acts_contrib.test_utils.tel.tel_test_utils import test_data_browsing_failure_using_sl4a
 from acts_contrib.test_utils.tel.tel_test_utils import set_time_sync_from_network
diff --git a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py
index 92d01ec..b762af0 100644
--- a/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveGFTDSDSDDSSwitchTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2020 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -27,6 +27,8 @@
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
 from acts_contrib.test_utils.tel.tel_data_utils import reboot_test
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection_for_subscription
 from acts_contrib.test_utils.tel.tel_ims_utils import is_volte_enabled
 from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
 from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte_for_subscription
@@ -48,8 +50,6 @@
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
-from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection_for_subscription
 from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
diff --git a/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py b/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py
index 824f0c8..b608584 100644
--- a/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveMobilityStressTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2017 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@
 from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
 from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
 from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
 from acts_contrib.test_utils.tel.tel_voice_utils import get_current_voice_rat
 from acts.utils import get_current_epoch_time
diff --git a/acts_tests/tests/google/tel/live/TelLiveRilDataKpiTest.py b/acts_tests/tests/google/tel/live/TelLiveRilDataKpiTest.py
index 44b3125..ce6e6fa 100644
--- a/acts_tests/tests/google/tel/live/TelLiveRilDataKpiTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveRilDataKpiTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
 from acts_contrib.test_utils.tel.tel_data_utils import activate_and_verify_cellular_data
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_data_utils import deactivate_and_verify_cellular_data
 from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
 from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
@@ -38,7 +39,6 @@
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_0
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot_1
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_data_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
 from acts.utils import get_current_epoch_time
 from acts.libs.utils.multithread import multithread_func
 
diff --git a/acts_tests/tests/google/tel/live/TelLiveSmsTest.py b/acts_tests/tests/google/tel/live/TelLiveSmsTest.py
index dc3af48..d03d42a 100644
--- a/acts_tests/tests/google/tel/live/TelLiveSmsTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveSmsTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2021 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -26,16 +26,16 @@
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
 from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
 from acts_contrib.test_utils.tel.tel_message_utils import sms_in_collision_send_receive_verify
 from acts_contrib.test_utils.tel.tel_message_utils import sms_rx_power_off_multiple_send_receive_verify
 from acts_contrib.test_utils.tel.tel_message_utils import message_test
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
 from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
 from acts_contrib.test_utils.tel.tel_test_utils import install_message_apk
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
 from acts.utils import rand_ascii_str
 from acts.libs.utils.multithread import multithread_func
 
diff --git a/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py b/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py
index da8d9b1..91e1332 100644
--- a/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveStressFdrTest.py
@@ -57,6 +57,7 @@
     def setup_class(self):
         TelephonyBaseTest.setup_class(self)
 
+        self.user_params["telephony_auto_rerun"] = 0
         self.stress_test_number = int(
             self.user_params.get("stress_test_number", 100))
         self.skip_reset_between_cases = False
diff --git a/acts_tests/tests/google/tel/live/TelLiveStressTest.py b/acts_tests/tests/google/tel/live/TelLiveStressTest.py
index 6f3e0f7..e04ba6a 100644
--- a/acts_tests/tests/google/tel/live/TelLiveStressTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveStressTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2017 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -47,6 +47,8 @@
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_MESSAGE_SUB_ID
 from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_VOICE_SUB_ID
 from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
 from acts_contrib.test_utils.tel.tel_logging_utils import extract_test_log
 from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
@@ -72,7 +74,6 @@
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
 from acts_contrib.test_utils.tel.tel_subscription_utils import set_always_allow_mms_data
 from acts_contrib.test_utils.tel.tel_test_utils import STORY_LINE
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_test_utils import force_connectivity_metrics_upload
 from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
 from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
@@ -477,9 +478,7 @@
                 incall_ui_display=INCALL_UI_DISPLAY_BACKGROUND,
                 call_stats_check=self.call_stats_check,
                 voice_type_init=voice_type_init,
-                result_info = self.result_info,
-                nw_gen_5g=self.nsa_5g_for_stress,
-                nr_type= self.nr_type
+                result_info = self.result_info
             ) and wait_for_in_call_active(self.dut, 60, 3)
         else:
             call_setup_result = call_setup_teardown(
@@ -494,9 +493,7 @@
                 slot_id_callee=slot_id_callee,
                 call_stats_check=self.call_stats_check,
                 voice_type_init=voice_type_init,
-                result_info = self.result_info,
-                nsa_5g_for_stress=self.nsa_5g_for_stress,
-                nr_type= self.nr_type)
+                result_info = self.result_info)
             self.result_collection[RESULTS_LIST[call_setup_result.result_value]] += 1
 
         if not call_setup_result:
@@ -563,6 +560,11 @@
         if not hangup_call(self.log, ads[0]):
             failure_reasons.add("Teardown")
             result = False
+        else:
+            if self.nsa_5g_for_stress:
+                for ad in (ads[0], ads[1]):
+                    if not is_current_network_5g(ad, self.nr_type):
+                        ad.log.error("Phone not attached on 5G")
         for ad in ads:
             if not wait_for_call_id_clearing(ad,
                                              []) or ad.droid.telecomIsInCall():
diff --git a/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py b/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py
index 344e1e9..b105660 100644
--- a/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py
+++ b/acts_tests/tests/google/tel/live/TelLiveVoiceTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2016 - Google
+#   Copyright 2022 - Google
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -24,6 +24,9 @@
 from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
 from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
 from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_data_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_data_utils import remove_mobile_data_usage_limit
+from acts_contrib.test_utils.tel.tel_data_utils import set_mobile_data_usage_limit
 from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_data_transfer
 from acts_contrib.test_utils.tel.tel_data_utils import test_call_setup_in_active_youtube_video
 from acts_contrib.test_utils.tel.tel_data_utils import call_epdg_to_epdg_wfc
@@ -57,11 +60,8 @@
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
 from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
 from acts_contrib.test_utils.tel.tel_test_utils import install_dialer_apk
 from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import remove_mobile_data_usage_limit
-from acts_contrib.test_utils.tel.tel_test_utils import set_mobile_data_usage_limit
 from acts_contrib.test_utils.tel.tel_test_utils import STORY_LINE
 from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
 from acts_contrib.test_utils.tel.tel_voice_utils import hold_unhold_test
diff --git a/acts_tests/tests/google/tel/live/TelWifiDataTest.py b/acts_tests/tests/google/tel/live/TelWifiDataTest.py
index 2938c08..9582405 100644
--- a/acts_tests/tests/google/tel/live/TelWifiDataTest.py
+++ b/acts_tests/tests/google/tel/live/TelWifiDataTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-# Copyright 2016 - The Android Open Source Project
+# Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -24,12 +24,12 @@
 from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
 from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
 from acts_contrib.test_utils.tel.tel_defines import GEN_4G
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
 from acts_contrib.test_utils.tel.tel_data_utils import wait_for_wifi_data_connection
 from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
 from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
 from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
 from acts_contrib.test_utils.tel.tel_test_utils import reboot_device
 from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
diff --git a/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py b/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py
index e11eaa5..84fc6aa 100644
--- a/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py
+++ b/acts_tests/tests/google/wifi/WifiTetheringPowerTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2017 - The Android Open Source Project
+#   Copyright 2022 - The Android Open Source Project
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
 from acts_contrib.test_utils.tel import tel_data_utils as tel_utils
 from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
 from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
-from acts_contrib.test_utils.tel.tel_test_utils import http_file_download_by_chrome
+from acts_contrib.test_utils.tel.tel_data_utils import http_file_download_by_chrome
 from acts.utils import force_airplane_mode
 from acts.utils import set_adaptive_brightness
 from acts.utils import set_ambient_display